-/*-
- * 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.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2010-2014 Intel Corporation
*/
+#include <rte_string_fns.h>
#include <rte_acl.h>
#include <getopt.h>
#include <string.h>
-#ifndef RTE_LIBRTE_ACL_STANDALONE
-
#include <rte_cycles.h>
#include <rte_per_lcore.h>
#include <rte_lcore.h>
#include <rte_ip.h>
-#define PRINT_USAGE_START "%s [EAL options]\n"
-
-#else
-
-#define IPv4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | \
- (((b) & 0xff) << 16) | \
- (((c) & 0xff) << 8) | \
- ((d) & 0xff))
-
-#define RTE_LCORE_FOREACH_SLAVE(x) while (((x) = 0))
-
-#define rte_eal_remote_launch(a, b, c) DUMMY_MACRO
-#define rte_eal_mp_wait_lcore() DUMMY_MACRO
-
-#define rte_eal_init(c, v) (0)
-
-#define PRINT_USAGE_START "%s\n"
+#define PRINT_USAGE_START "%s [EAL options] --\n"
-#endif /*RTE_LIBRTE_ACL_STANDALONE */
+#define RTE_LOGTYPE_TESTACL RTE_LOGTYPE_USER1
-#include "main.h"
+#define APP_NAME "TESTACL"
#define GET_CB_FIELD(in, fd, base, lim, dlm) do { \
unsigned long val; \
#define OPT_RULE_NUM "rulenum"
#define OPT_TRACE_NUM "tracenum"
#define OPT_TRACE_STEP "tracestep"
-#define OPT_SEARCH_SCALAR "scalar"
+#define OPT_SEARCH_ALG "alg"
#define OPT_BLD_CATEGORIES "bldcat"
#define OPT_RUN_CATEGORIES "runcat"
+#define OPT_MAX_SIZE "maxsize"
#define OPT_ITER_NUM "iter"
#define OPT_VERBOSE "verbose"
#define OPT_IPV6 "ipv6"
#define RULE_NUM 0x10000
+#define COMMENT_LEAD_CHAR '#'
+
enum {
DUMP_NONE,
DUMP_SEARCH,
DUMP_MAX
};
+enum {
+ IPV6_FRMT_NONE,
+ IPV6_FRMT_U32,
+ IPV6_FRMT_U64,
+};
+
+struct acl_alg {
+ const char *name;
+ enum rte_acl_classify_alg alg;
+};
+
+static const struct acl_alg acl_alg[] = {
+ {
+ .name = "scalar",
+ .alg = RTE_ACL_CLASSIFY_SCALAR,
+ },
+ {
+ .name = "sse",
+ .alg = RTE_ACL_CLASSIFY_SSE,
+ },
+ {
+ .name = "avx2",
+ .alg = RTE_ACL_CLASSIFY_AVX2,
+ },
+ {
+ .name = "neon",
+ .alg = RTE_ACL_CLASSIFY_NEON,
+ },
+ {
+ .name = "altivec",
+ .alg = RTE_ACL_CLASSIFY_ALTIVEC,
+ },
+ {
+ .name = "avx512x16",
+ .alg = RTE_ACL_CLASSIFY_AVX512X16,
+ },
+ {
+ .name = "avx512x32",
+ .alg = RTE_ACL_CLASSIFY_AVX512X32,
+ },
+};
+
static struct {
const char *prgname;
const char *rule_file;
const char *trace_file;
+ size_t max_size;
uint32_t bld_categories;
uint32_t run_categories;
uint32_t nb_rules;
uint32_t trace_sz;
uint32_t iter_num;
uint32_t verbose;
- uint32_t scalar;
+ uint32_t ipv6;
+ struct acl_alg alg;
uint32_t used_traces;
void *traces;
struct rte_acl_ctx *acx;
- uint32_t ipv6;
} config = {
.bld_categories = 3,
.run_categories = 1,
.trace_step = TRACE_STEP_DEF,
.iter_num = 1,
.verbose = DUMP_MAX,
- .ipv6 = 0
+ .alg = {
+ .name = "default",
+ .alg = RTE_ACL_CLASSIFY_DEFAULT,
+ },
+ .ipv6 = IPV6_FRMT_NONE,
};
static struct rte_acl_param prm = {
NUM_FIELDS_IPV4
};
+/*
+ * That effectively defines order of IPV4VLAN classifications:
+ * - PROTO
+ * - VLAN (TAG and DOMAIN)
+ * - SRC IP ADDRESS
+ * - DST IP ADDRESS
+ * - PORTS (SRC and DST)
+ */
+enum {
+ RTE_ACL_IPV4VLAN_PROTO,
+ RTE_ACL_IPV4VLAN_VLAN,
+ RTE_ACL_IPV4VLAN_SRC,
+ RTE_ACL_IPV4VLAN_DST,
+ RTE_ACL_IPV4VLAN_PORTS,
+ RTE_ACL_IPV4VLAN_NUM
+};
+
struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = {
{
.type = RTE_ACL_FIELD_TYPE_BITMASK,
#define IPV6_ADDR_LEN 16
#define IPV6_ADDR_U16 (IPV6_ADDR_LEN / sizeof(uint16_t))
#define IPV6_ADDR_U32 (IPV6_ADDR_LEN / sizeof(uint32_t))
+#define IPV6_ADDR_U64 (IPV6_ADDR_LEN / sizeof(uint64_t))
struct ipv6_5tuple {
uint8_t proto;
uint16_t port_dst;
};
+/* treat IPV6 address as uint32_t[4] (default mode) */
enum {
PROTO_FIELD_IPV6,
SRC1_FIELD_IPV6,
NUM_FIELDS_IPV6
};
+/* treat IPV6 address as uint64_t[2] (default mode) */
+enum {
+ PROTO_FIELD_IPV6_U64,
+ SRC1_FIELD_IPV6_U64,
+ SRC2_FIELD_IPV6_U64,
+ DST1_FIELD_IPV6_U64,
+ DST2_FIELD_IPV6_U64,
+ SRCP_FIELD_IPV6_U64,
+ DSTP_FIELD_IPV6_U64,
+ NUM_FIELDS_IPV6_U64
+};
+
+enum {
+ PROTO_INDEX_IPV6_U64 = PROTO_FIELD_IPV6_U64,
+ SRC1_INDEX_IPV6_U64 = SRC1_FIELD_IPV6_U64,
+ SRC2_INDEX_IPV6_U64 = SRC2_FIELD_IPV6_U64 + 1,
+ DST1_INDEX_IPV6_U64 = DST1_FIELD_IPV6_U64 + 2,
+ DST2_INDEX_IPV6_U64 = DST2_FIELD_IPV6_U64 + 3,
+ PRT_INDEX_IPV6_U64 = SRCP_FIELD_IPV6 + 4,
+};
+
struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = {
{
.type = RTE_ACL_FIELD_TYPE_BITMASK,
},
};
+struct rte_acl_field_def ipv6_u64_defs[NUM_FIELDS_IPV6_U64] = {
+ {
+ .type = RTE_ACL_FIELD_TYPE_BITMASK,
+ .size = sizeof(uint8_t),
+ .field_index = PROTO_FIELD_IPV6_U64,
+ .input_index = PROTO_FIELD_IPV6_U64,
+ .offset = offsetof(struct ipv6_5tuple, proto),
+ },
+ {
+ .type = RTE_ACL_FIELD_TYPE_MASK,
+ .size = sizeof(uint64_t),
+ .field_index = SRC1_FIELD_IPV6_U64,
+ .input_index = SRC1_INDEX_IPV6_U64,
+ .offset = offsetof(struct ipv6_5tuple, ip_src[0]),
+ },
+ {
+ .type = RTE_ACL_FIELD_TYPE_MASK,
+ .size = sizeof(uint64_t),
+ .field_index = SRC2_FIELD_IPV6_U64,
+ .input_index = SRC2_INDEX_IPV6_U64,
+ .offset = offsetof(struct ipv6_5tuple, ip_src[2]),
+ },
+ {
+ .type = RTE_ACL_FIELD_TYPE_MASK,
+ .size = sizeof(uint64_t),
+ .field_index = DST1_FIELD_IPV6_U64,
+ .input_index = DST1_INDEX_IPV6_U64,
+ .offset = offsetof(struct ipv6_5tuple, ip_dst[0]),
+ },
+ {
+ .type = RTE_ACL_FIELD_TYPE_MASK,
+ .size = sizeof(uint64_t),
+ .field_index = DST2_FIELD_IPV6_U64,
+ .input_index = DST2_INDEX_IPV6_U64,
+ .offset = offsetof(struct ipv6_5tuple, ip_dst[2]),
+ },
+ {
+ .type = RTE_ACL_FIELD_TYPE_RANGE,
+ .size = sizeof(uint16_t),
+ .field_index = SRCP_FIELD_IPV6_U64,
+ .input_index = PRT_INDEX_IPV6_U64,
+ .offset = offsetof(struct ipv6_5tuple, port_src),
+ },
+ {
+ .type = RTE_ACL_FIELD_TYPE_RANGE,
+ .size = sizeof(uint16_t),
+ .field_index = DSTP_FIELD_IPV6_U64,
+ .input_index = PRT_INDEX_IPV6_U64,
+ .offset = offsetof(struct ipv6_5tuple, port_dst),
+ },
+};
enum {
CB_FLD_SRC_ADDR,
return 0;
}
-/*
- * Parses IPV6 address, exepcts the following format:
- * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX (where X - is a hexedecimal digit).
- */
-static int
-parse_ipv6_addr(const char *in, const char **end, uint32_t v[IPV6_ADDR_U32],
- char dlm)
-{
- uint32_t addr[IPV6_ADDR_U16];
-
- GET_CB_FIELD(in, addr[0], 16, UINT16_MAX, ':');
- GET_CB_FIELD(in, addr[1], 16, UINT16_MAX, ':');
- GET_CB_FIELD(in, addr[2], 16, UINT16_MAX, ':');
- GET_CB_FIELD(in, addr[3], 16, UINT16_MAX, ':');
- GET_CB_FIELD(in, addr[4], 16, UINT16_MAX, ':');
- GET_CB_FIELD(in, addr[5], 16, UINT16_MAX, ':');
- GET_CB_FIELD(in, addr[6], 16, UINT16_MAX, ':');
- GET_CB_FIELD(in, addr[7], 16, UINT16_MAX, dlm);
-
- *end = in;
-
- v[0] = (addr[0] << 16) + addr[1];
- v[1] = (addr[2] << 16) + addr[3];
- v[2] = (addr[4] << 16) + addr[5];
- v[3] = (addr[6] << 16) + addr[7];
-
- return 0;
-}
-
static int
parse_cb_ipv6_addr_trace(const char *in, uint32_t v[IPV6_ADDR_U32])
{
- int32_t rc;
- const char *end;
-
- rc = parse_ipv6_addr(in, &end, v, 0);
- if (rc != 0)
- return rc;
-
- v[0] = rte_cpu_to_be_32(v[0]);
- v[1] = rte_cpu_to_be_32(v[1]);
- v[2] = rte_cpu_to_be_32(v[2]);
- v[3] = rte_cpu_to_be_32(v[3]);
+ if (inet_pton(AF_INET6, in, v) != 1)
+ return -EINVAL;
return 0;
}
return 0;
}
+/* Bypass comment and empty lines */
+static int
+skip_line(const char *buf)
+{
+ uint32_t i;
+
+ for (i = 0; isspace(buf[i]) != 0; i++)
+ ;
+
+ if (buf[i] == 0 || buf[i] == COMMENT_LEAD_CHAR)
+ return 1;
+
+ return 0;
+}
+
static void
tracef_init(void)
{
static const char name[] = APP_NAME;
FILE *f;
size_t sz;
- uint32_t n;
+ uint32_t i, k, n;
struct ipv4_5tuple *v;
struct ipv6_5tuple *w;
sz = config.nb_traces * (config.ipv6 ? sizeof(*w) : sizeof(*v));
- config.traces = rte_zmalloc_socket(name, sz, CACHE_LINE_SIZE,
+ config.traces = rte_zmalloc_socket(name, sz, RTE_CACHE_LINE_SIZE,
SOCKET_ID_ANY);
if (config.traces == NULL)
rte_exit(EXIT_FAILURE, "Cannot allocate %zu bytes for "
v = config.traces;
w = config.traces;
- for (n = 0; n != config.nb_traces; n++) {
+ k = 0;
+ n = 0;
+ for (i = 0; n != config.nb_traces; i++) {
if (fgets(line, sizeof(line), f) == NULL)
break;
+ if (skip_line(line) != 0) {
+ k++;
+ continue;
+ }
+
+ n = i - k;
+
if (config.ipv6) {
if (parse_cb_ipv6_trace(line, w + n) != 0)
rte_exit(EXIT_FAILURE,
"%s: failed to parse ipv6 trace "
"record at line %u\n",
- config.trace_file, n + 1);
+ config.trace_file, i + 1);
} else {
if (parse_cb_ipv4_trace(line, v + n) != 0)
rte_exit(EXIT_FAILURE,
"%s: failed to parse ipv4 trace "
"record at line %u\n",
- config.trace_file, n + 1);
+ config.trace_file, i + 1);
}
}
- config.used_traces = n;
+ config.used_traces = i - k;
fclose(f);
}
static int
-parse_ipv6_net(const char *in, struct rte_acl_field field[4])
+parse_ipv6_u32_net(char *in, struct rte_acl_field field[IPV6_ADDR_U32])
{
- int32_t rc;
- const char *mp;
- uint32_t i, m, v[4];
+ char *sa, *sm, *sv;
+ uint32_t i, m, v[IPV6_ADDR_U32];
+
+ const char *dlm = "/";
const uint32_t nbu32 = sizeof(uint32_t) * CHAR_BIT;
/* get address. */
- rc = parse_ipv6_addr(in, &mp, v, '/');
- if (rc != 0)
- return rc;
+ sv = NULL;
+ sa = strtok_r(in, dlm, &sv);
+ if (sa == NULL)
+ return -EINVAL;
+ sm = strtok_r(NULL, dlm, &sv);
+ if (sm == NULL)
+ return -EINVAL;
+
+ if (inet_pton(AF_INET6, sa, v) != 1)
+ return -EINVAL;
+
+ v[0] = rte_be_to_cpu_32(v[0]);
+ v[1] = rte_be_to_cpu_32(v[1]);
+ v[2] = rte_be_to_cpu_32(v[2]);
+ v[3] = rte_be_to_cpu_32(v[3]);
/* get mask. */
- GET_CB_FIELD(mp, m, 0, CHAR_BIT * sizeof(v), 0);
+ GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
/* put all together. */
for (i = 0; i != RTE_DIM(v); i++) {
field[i].mask_range.u32 = nbu32;
else
field[i].mask_range.u32 = m > (i * nbu32) ?
- m - (i * 32) : 0;
+ m - (i * nbu32) : 0;
field[i].value.u32 = v[i];
}
return 0;
}
+static int
+parse_ipv6_u64_net(char *in, struct rte_acl_field field[IPV6_ADDR_U64])
+{
+ char *sa, *sm, *sv;
+ uint32_t i, m;
+ uint64_t v[IPV6_ADDR_U64];
+
+ const char *dlm = "/";
+ const uint32_t nbu64 = sizeof(uint64_t) * CHAR_BIT;
+
+ /* get address. */
+ sv = NULL;
+ sa = strtok_r(in, dlm, &sv);
+ if (sa == NULL)
+ return -EINVAL;
+ sm = strtok_r(NULL, dlm, &sv);
+ if (sm == NULL)
+ return -EINVAL;
+
+ if (inet_pton(AF_INET6, sa, v) != 1)
+ return -EINVAL;
+
+ v[0] = rte_be_to_cpu_64(v[0]);
+ v[1] = rte_be_to_cpu_64(v[1]);
+
+ /* get mask. */
+ GET_CB_FIELD(sm, m, 0, CHAR_BIT * sizeof(v), 0);
+
+ /* put all together. */
+ for (i = 0; i != RTE_DIM(v); i++) {
+ if (m >= (i + 1) * nbu64)
+ field[i].mask_range.u32 = nbu64;
+ else
+ field[i].mask_range.u32 = m > (i * nbu64) ?
+ m - (i * nbu64) : 0;
+
+ field[i].value.u64 = v[i];
+ }
+
+ return 0;
+}
static int
-parse_cb_ipv6_rule(char *str, struct acl_rule *v)
+parse_cb_ipv6_rule(char *str, struct acl_rule *v, int frmt)
{
int i, rc;
+ uint32_t fidx;
+ const uint32_t *field_map;
char *s, *sp, *in[CB_FLD_NUM];
+ int (*parse_ipv6_net)(char *s, struct rte_acl_field f[]);
+
static const char *dlm = " \t\n";
+ static const uint32_t field_map_u32[CB_FLD_NUM] = {
+ [CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6,
+ [CB_FLD_DST_ADDR] = DST1_FIELD_IPV6,
+ [CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6,
+ [CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6,
+ [CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6,
+ [CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6,
+ [CB_FLD_PROTO] = PROTO_FIELD_IPV6,
+ };
+
+ static const uint32_t field_map_u64[CB_FLD_NUM] = {
+ [CB_FLD_SRC_ADDR] = SRC1_FIELD_IPV6_U64,
+ [CB_FLD_DST_ADDR] = DST1_FIELD_IPV6_U64,
+ [CB_FLD_SRC_PORT_LOW] = SRCP_FIELD_IPV6_U64,
+ [CB_FLD_SRC_PORT_HIGH] = SRCP_FIELD_IPV6_U64,
+ [CB_FLD_DST_PORT_LOW] = DSTP_FIELD_IPV6_U64,
+ [CB_FLD_DST_PORT_HIGH] = DSTP_FIELD_IPV6_U64,
+ [CB_FLD_PROTO] = PROTO_FIELD_IPV6_U64,
+ };
+
+ if (frmt == IPV6_FRMT_U32) {
+ field_map = field_map_u32;
+ parse_ipv6_net = parse_ipv6_u32_net;
+ } else if (frmt == IPV6_FRMT_U64) {
+ field_map = field_map_u64;
+ parse_ipv6_net = parse_ipv6_u64_net;
+ } else
+ return -ENOTSUP;
+
/*
* Skip leading '@'
*/
s = NULL;
}
- rc = parse_ipv6_net(in[CB_FLD_SRC_ADDR], v->field + SRC1_FIELD_IPV6);
+ fidx = CB_FLD_SRC_ADDR;
+ rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
if (rc != 0) {
RTE_LOG(ERR, TESTACL,
- "failed to read source address/mask: %s\n",
- in[CB_FLD_SRC_ADDR]);
+ "failed to read source address/mask: %s\n", in[fidx]);
return rc;
}
- rc = parse_ipv6_net(in[CB_FLD_DST_ADDR], v->field + DST1_FIELD_IPV6);
+ fidx = CB_FLD_DST_ADDR;
+ rc = parse_ipv6_net(in[fidx], v->field + field_map[fidx]);
if (rc != 0) {
RTE_LOG(ERR, TESTACL,
"failed to read destination address/mask: %s\n",
- in[CB_FLD_DST_ADDR]);
+ in[fidx]);
return rc;
}
/* source port. */
- GET_CB_FIELD(in[CB_FLD_SRC_PORT_LOW],
- v->field[SRCP_FIELD_IPV6].value.u16,
+ fidx = CB_FLD_SRC_PORT_LOW;
+ GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
0, UINT16_MAX, 0);
- GET_CB_FIELD(in[CB_FLD_SRC_PORT_HIGH],
- v->field[SRCP_FIELD_IPV6].mask_range.u16,
+
+ fidx = CB_FLD_SRC_PORT_HIGH;
+ GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
0, UINT16_MAX, 0);
if (strncmp(in[CB_FLD_SRC_PORT_DLM], cb_port_delim,
return -EINVAL;
/* destination port. */
- GET_CB_FIELD(in[CB_FLD_DST_PORT_LOW],
- v->field[DSTP_FIELD_IPV6].value.u16,
+ fidx = CB_FLD_DST_PORT_LOW;
+ GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u16,
0, UINT16_MAX, 0);
- GET_CB_FIELD(in[CB_FLD_DST_PORT_HIGH],
- v->field[DSTP_FIELD_IPV6].mask_range.u16,
+
+ fidx = CB_FLD_DST_PORT_HIGH;
+ GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u16,
0, UINT16_MAX, 0);
if (strncmp(in[CB_FLD_DST_PORT_DLM], cb_port_delim,
sizeof(cb_port_delim)) != 0)
return -EINVAL;
- GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].value.u8,
+ fidx = CB_FLD_PROTO;
+ GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].value.u8,
0, UINT8_MAX, '/');
- GET_CB_FIELD(in[CB_FLD_PROTO], v->field[PROTO_FIELD_IPV6].mask_range.u8,
+ GET_CB_FIELD(in[fidx], v->field[field_map[fidx]].mask_range.u8,
0, UINT8_MAX, 0);
return 0;
}
static int
-parse_ipv4_net(const char *in, uint32_t *addr, uint32_t *mask_len)
+parse_cb_ipv6_u32_rule(char *str, struct acl_rule *v)
{
- uint8_t a, b, c, d, m;
+ return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U32);
+}
- GET_CB_FIELD(in, a, 0, UINT8_MAX, '.');
- GET_CB_FIELD(in, b, 0, UINT8_MAX, '.');
- GET_CB_FIELD(in, c, 0, UINT8_MAX, '.');
- GET_CB_FIELD(in, d, 0, UINT8_MAX, '/');
- GET_CB_FIELD(in, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
+static int
+parse_cb_ipv6_u64_rule(char *str, struct acl_rule *v)
+{
+ return parse_cb_ipv6_rule(str, v, IPV6_FRMT_U64);
+}
+
+static int
+parse_ipv4_net(char *in, uint32_t *addr, uint32_t *mask_len)
+{
+ char *sa, *sm, *sv;
+ uint32_t m, v;
+
+ const char *dlm = "/";
+
+ sv = NULL;
+ sa = strtok_r(in, dlm, &sv);
+ if (sa == NULL)
+ return -EINVAL;
+ sm = strtok_r(NULL, dlm, &sv);
+ if (sm == NULL)
+ return -EINVAL;
+
+ if (inet_pton(AF_INET, sa, &v) != 1)
+ return -EINVAL;
+
+ addr[0] = rte_be_to_cpu_32(v);
- addr[0] = IPv4(a, b, c, d);
+ GET_CB_FIELD(sm, m, 0, sizeof(uint32_t) * CHAR_BIT, 0);
mask_len[0] = m;
return 0;
add_cb_rules(FILE *f, struct rte_acl_ctx *ctx)
{
int rc;
- uint32_t n;
+ uint32_t i, k, n;
struct acl_rule v;
parse_5tuple parser;
+ static const parse_5tuple parser_func[] = {
+ [IPV6_FRMT_NONE] = parse_cb_ipv4_rule,
+ [IPV6_FRMT_U32] = parse_cb_ipv6_u32_rule,
+ [IPV6_FRMT_U64] = parse_cb_ipv6_u64_rule,
+ };
+
memset(&v, 0, sizeof(v));
- parser = (config.ipv6 != 0) ? parse_cb_ipv6_rule : parse_cb_ipv4_rule;
+ parser = parser_func[config.ipv6];
+
+ k = 0;
+ for (i = 1; fgets(line, sizeof(line), f) != NULL; i++) {
- for (n = 1; fgets(line, sizeof(line), f) != NULL; n++) {
+ if (skip_line(line) != 0) {
+ k++;
+ continue;
+ }
+ n = i - k;
rc = parser(line, &v);
if (rc != 0) {
RTE_LOG(ERR, TESTACL, "line %u: parse_cb_ipv4vlan_rule"
" failed, error code: %d (%s)\n",
- n, rc, strerror(-rc));
+ i, rc, strerror(-rc));
return rc;
}
- v.data.category_mask = LEN2MASK(RTE_ACL_MAX_CATEGORIES);
+ v.data.category_mask = RTE_LEN2MASK(RTE_ACL_MAX_CATEGORIES,
+ typeof(v.data.category_mask));
v.data.priority = RTE_ACL_MAX_PRIORITY - n;
v.data.userdata = n;
if (rc != 0) {
RTE_LOG(ERR, TESTACL, "line %u: failed to add rules "
"into ACL context, error code: %d (%s)\n",
- n, rc, strerror(-rc));
+ i, rc, strerror(-rc));
return rc;
}
}
FILE *f;
struct rte_acl_config cfg;
+ memset(&cfg, 0, sizeof(cfg));
+
/* setup ACL build config. */
- if (config.ipv6) {
+ if (config.ipv6 == IPV6_FRMT_U32) {
cfg.num_fields = RTE_DIM(ipv6_defs);
memcpy(&cfg.defs, ipv6_defs, sizeof(ipv6_defs));
+ } else if (config.ipv6 == IPV6_FRMT_U64) {
+ cfg.num_fields = RTE_DIM(ipv6_u64_defs);
+ memcpy(&cfg.defs, ipv6_u64_defs, sizeof(ipv6_u64_defs));
} else {
cfg.num_fields = RTE_DIM(ipv4_defs);
memcpy(&cfg.defs, ipv4_defs, sizeof(ipv4_defs));
}
cfg.num_categories = config.bld_categories;
+ cfg.max_size = config.max_size;
/* setup ACL creation parameters. */
prm.rule_size = RTE_ACL_RULE_SZ(cfg.num_fields);
if (config.acx == NULL)
rte_exit(rte_errno, "failed to create ACL context\n");
+ /* set default classify method for this context. */
+ if (config.alg.alg != RTE_ACL_CLASSIFY_DEFAULT) {
+ ret = rte_acl_set_ctx_classify(config.acx, config.alg.alg);
+ if (ret != 0)
+ rte_exit(ret, "failed to setup %s method "
+ "for ACL context\n", config.alg.name);
+ }
+
/* add ACL rules. */
f = fopen(config.rule_file, "r");
if (f == NULL)
ret = add_cb_rules(f, config.acx);
if (ret != 0)
- rte_exit(rte_errno, "failed to add rules into ACL context\n");
+ rte_exit(ret, "failed to add rules into ACL context\n");
fclose(f);
}
static uint32_t
-search_ip5tuples_once(uint32_t categories, uint32_t step, int scalar)
+search_ip5tuples_once(uint32_t categories, uint32_t step, const char *alg)
{
int ret;
uint32_t i, j, k, n, r;
v += config.trace_sz;
}
- if (scalar != 0)
- ret = rte_acl_classify_scalar(config.acx, data,
- results, n, categories);
-
- else
- ret = rte_acl_classify(config.acx, data,
- results, n, categories);
+ ret = rte_acl_classify(config.acx, data, results,
+ n, categories);
if (ret != 0)
rte_exit(ret, "classify for ipv%c_5tuples returns %d\n",
dump_verbose(DUMP_SEARCH, stdout,
"%s(%u, %u, %s) returns %u\n", __func__,
- categories, step, scalar != 0 ? "scalar" : "sse", i);
+ categories, step, alg, i);
return i;
}
static int
-search_ip5tuples(__attribute__((unused)) void *arg)
+search_ip5tuples(__rte_unused void *arg)
{
uint64_t pkt, start, tm;
uint32_t i, lcore;
+ long double st;
lcore = rte_lcore_id();
- start = rte_rdtsc();
+ start = rte_rdtsc_precise();
pkt = 0;
for (i = 0; i != config.iter_num; i++) {
pkt += search_ip5tuples_once(config.run_categories,
- config.trace_step, config.scalar);
+ config.trace_step, config.alg.name);
}
- tm = rte_rdtsc() - start;
+ tm = rte_rdtsc_precise() - start;
+
+ st = (long double)tm / rte_get_timer_hz();
dump_verbose(DUMP_NONE, stdout,
"%s @lcore %u: %" PRIu32 " iterations, %" PRIu64 " pkts, %"
- PRIu32 " categories, %" PRIu64 " cycles, %#Lf cycles/pkt\n",
- __func__, lcore, i, pkt, config.run_categories,
- tm, (long double)tm / pkt);
+ PRIu32 " categories, %" PRIu64 " cycles (%.2Lf sec), "
+ "%.2Lf cycles/pkt, %.2Lf pkt/sec\n",
+ __func__, lcore, i, pkt,
+ config.run_categories, tm, st,
+ (pkt == 0) ? 0 : (long double)tm / pkt, pkt / st);
return 0;
}
-static uint32_t
-get_uint32_opt(const char *opt, const char *name, uint32_t min, uint32_t max)
+static unsigned long
+get_ulong_opt(const char *opt, const char *name, size_t min, size_t max)
{
unsigned long val;
char *end;
return val;
}
+static void
+get_alg_opt(const char *opt, const char *name)
+{
+ uint32_t i;
+
+ for (i = 0; i != RTE_DIM(acl_alg); i++) {
+ if (strcmp(opt, acl_alg[i].name) == 0) {
+ config.alg = acl_alg[i];
+ return;
+ }
+ }
+
+ rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
+ opt, name);
+}
+
+static void
+get_ipv6_opt(const char *opt, const char *name)
+{
+ uint32_t i;
+
+ static const struct {
+ const char *name;
+ uint32_t val;
+ } ipv6_opt[] = {
+ {
+ .name = "4B",
+ .val = IPV6_FRMT_U32,
+ },
+ {
+ .name = "8B",
+ .val = IPV6_FRMT_U64,
+ },
+ };
+
+ for (i = 0; i != RTE_DIM(ipv6_opt); i++) {
+ if (strcmp(opt, ipv6_opt[i].name) == 0) {
+ config.ipv6 = ipv6_opt[i].val;
+ return;
+ }
+ }
+
+ rte_exit(-EINVAL, "invalid value: \"%s\" for option: %s\n",
+ opt, name);
+}
+
+
static void
print_usage(const char *prgname)
{
+ uint32_t i, n, rc;
+ char buf[PATH_MAX];
+
+ n = 0;
+ buf[0] = 0;
+
+ for (i = 0; i < RTE_DIM(acl_alg) - 1; i++) {
+ rc = snprintf(buf + n, sizeof(buf) - n, "%s|",
+ acl_alg[i].name);
+ if (rc > sizeof(buf) - n)
+ break;
+ n += rc;
+ }
+
+ strlcpy(buf + n, acl_alg[i].name, sizeof(buf) - n);
+
fprintf(stdout,
PRINT_USAGE_START
"--" OPT_RULE_FILE "=<rules set file>\n"
"=<number of categories to run with> "
"should be either 1 or multiple of %zu, "
"but not greater then %u]\n"
+ "[--" OPT_MAX_SIZE
+ "=<size limit (in bytes) for runtime ACL structures> "
+ "leave 0 for default behaviour]\n"
"[--" OPT_ITER_NUM "=<number of iterations to perform>]\n"
"[--" OPT_VERBOSE "=<verbose level>]\n"
- "[--" OPT_SEARCH_SCALAR "=<use scalar version>]\n"
- "[--" OPT_IPV6 "=<IPv6 rules and trace files>]\n",
+ "[--" OPT_SEARCH_ALG "=%s]\n"
+ "[--" OPT_IPV6 "(=4B | 8B) <IPv6 rules and trace files>]\n",
prgname, RTE_ACL_RESULTS_MULTIPLIER,
- (uint32_t)RTE_ACL_MAX_CATEGORIES);
+ (uint32_t)RTE_ACL_MAX_CATEGORIES,
+ buf);
}
static void
fprintf(f, "%s:%u\n", OPT_TRACE_STEP, config.trace_step);
fprintf(f, "%s:%u\n", OPT_BLD_CATEGORIES, config.bld_categories);
fprintf(f, "%s:%u\n", OPT_RUN_CATEGORIES, config.run_categories);
+ fprintf(f, "%s:%zu\n", OPT_MAX_SIZE, config.max_size);
fprintf(f, "%s:%u\n", OPT_ITER_NUM, config.iter_num);
fprintf(f, "%s:%u\n", OPT_VERBOSE, config.verbose);
- fprintf(f, "%s:%u\n", OPT_SEARCH_SCALAR, config.scalar);
+ fprintf(f, "%s:%u(%s)\n", OPT_SEARCH_ALG, config.alg.alg,
+ config.alg.name);
fprintf(f, "%s:%u\n", OPT_IPV6, config.ipv6);
}
{OPT_TRACE_FILE, 1, 0, 0},
{OPT_TRACE_NUM, 1, 0, 0},
{OPT_RULE_NUM, 1, 0, 0},
+ {OPT_MAX_SIZE, 1, 0, 0},
{OPT_TRACE_STEP, 1, 0, 0},
{OPT_BLD_CATEGORIES, 1, 0, 0},
{OPT_RUN_CATEGORIES, 1, 0, 0},
{OPT_ITER_NUM, 1, 0, 0},
{OPT_VERBOSE, 1, 0, 0},
- {OPT_SEARCH_SCALAR, 0, 0, 0},
- {OPT_IPV6, 0, 0, 0},
+ {OPT_SEARCH_ALG, 1, 0, 0},
+ {OPT_IPV6, 2, 0, 0},
{NULL, 0, 0, 0}
};
} else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_FILE) == 0) {
config.trace_file = optarg;
} else if (strcmp(lgopts[opt_idx].name, OPT_RULE_NUM) == 0) {
- config.nb_rules = get_uint32_opt(optarg,
+ config.nb_rules = get_ulong_opt(optarg,
lgopts[opt_idx].name, 1, RTE_ACL_MAX_INDEX + 1);
+ } else if (strcmp(lgopts[opt_idx].name, OPT_MAX_SIZE) == 0) {
+ config.max_size = get_ulong_opt(optarg,
+ lgopts[opt_idx].name, 0, SIZE_MAX);
} else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_NUM) == 0) {
- config.nb_traces = get_uint32_opt(optarg,
+ config.nb_traces = get_ulong_opt(optarg,
lgopts[opt_idx].name, 1, UINT32_MAX);
} else if (strcmp(lgopts[opt_idx].name, OPT_TRACE_STEP) == 0) {
- config.trace_step = get_uint32_opt(optarg,
+ config.trace_step = get_ulong_opt(optarg,
lgopts[opt_idx].name, 1, TRACE_STEP_MAX);
} else if (strcmp(lgopts[opt_idx].name,
OPT_BLD_CATEGORIES) == 0) {
- config.bld_categories = get_uint32_opt(optarg,
+ config.bld_categories = get_ulong_opt(optarg,
lgopts[opt_idx].name, 1,
RTE_ACL_MAX_CATEGORIES);
} else if (strcmp(lgopts[opt_idx].name,
OPT_RUN_CATEGORIES) == 0) {
- config.run_categories = get_uint32_opt(optarg,
+ config.run_categories = get_ulong_opt(optarg,
lgopts[opt_idx].name, 1,
RTE_ACL_MAX_CATEGORIES);
} else if (strcmp(lgopts[opt_idx].name, OPT_ITER_NUM) == 0) {
- config.iter_num = get_uint32_opt(optarg,
- lgopts[opt_idx].name, 1, UINT16_MAX);
+ config.iter_num = get_ulong_opt(optarg,
+ lgopts[opt_idx].name, 1, INT32_MAX);
} else if (strcmp(lgopts[opt_idx].name, OPT_VERBOSE) == 0) {
- config.verbose = get_uint32_opt(optarg,
+ config.verbose = get_ulong_opt(optarg,
lgopts[opt_idx].name, DUMP_NONE, DUMP_MAX);
} else if (strcmp(lgopts[opt_idx].name,
- OPT_SEARCH_SCALAR) == 0) {
- config.scalar = 1;
+ OPT_SEARCH_ALG) == 0) {
+ get_alg_opt(optarg, lgopts[opt_idx].name);
} else if (strcmp(lgopts[opt_idx].name, OPT_IPV6) == 0) {
- config.ipv6 = 1;
+ config.ipv6 = IPV6_FRMT_U32;
+ if (optarg != NULL)
+ get_ipv6_opt(optarg, lgopts[opt_idx].name);
}
}
config.trace_sz = config.ipv6 ? sizeof(struct ipv6_5tuple) :
}
int
-MAIN(int argc, char **argv)
+main(int argc, char **argv)
{
int ret;
uint32_t lcore;
if (config.trace_file != NULL)
tracef_init();
- RTE_LCORE_FOREACH_SLAVE(lcore)
+ RTE_LCORE_FOREACH_WORKER(lcore)
rte_eal_remote_launch(search_ip5tuples, NULL, lcore);
search_ip5tuples(NULL);