From patchwork Tue Apr 26 17:44:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konstantin Ananyev X-Patchwork-Id: 110285 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 9D09EA050D; Tue, 26 Apr 2022 19:45:35 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 62BAE42819; Tue, 26 Apr 2022 19:45:31 +0200 (CEST) Received: from forward501p.mail.yandex.net (forward501p.mail.yandex.net [77.88.28.111]) by mails.dpdk.org (Postfix) with ESMTP id D42B142819; Tue, 26 Apr 2022 19:45:29 +0200 (CEST) Received: from iva3-d53c26eb10e1.qloud-c.yandex.net (iva3-d53c26eb10e1.qloud-c.yandex.net [IPv6:2a02:6b8:c0c:4987:0:640:d53c:26eb]) by forward501p.mail.yandex.net (Yandex) with ESMTP id C0B7C6213598; Tue, 26 Apr 2022 20:45:16 +0300 (MSK) Received: from iva3-dd2bb2ff2b5f.qloud-c.yandex.net (iva3-dd2bb2ff2b5f.qloud-c.yandex.net [2a02:6b8:c0c:7611:0:640:dd2b:b2ff]) by iva3-d53c26eb10e1.qloud-c.yandex.net (mxback/Yandex) with ESMTP id gDNEbRzfDQ-jGgWwkWe; Tue, 26 Apr 2022 20:45:16 +0300 X-Yandex-Fwd: 2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1650995116; bh=zpb5D4jUHR2BLFwaAlaQNnwjr216hWnj8MfePcPYeek=; h=In-Reply-To:References:Date:Subject:Cc:To:From:Message-Id; b=AHguiPEBw9iVPrYb152ONzeJ2J9VN8gAo0Mwz5OAWsfN8MqxMx4t3EE2Lv318+SWm BEnYVmKZdtIvYN/hgTVx6tBpADl1/r6aOflA3TajcELgvrdhu+gx9uz8L6a0lNsYQD hyxmiTUt0Yo2tocdhKGX/v6AnK7KoU04Xq54UB3s= Authentication-Results: iva3-d53c26eb10e1.qloud-c.yandex.net; dkim=pass header.i=@yandex.ru Received: by iva3-dd2bb2ff2b5f.qloud-c.yandex.net (smtp/Yandex) with ESMTPSA id 4Jw1POtKVO-jFMGDhQ5; Tue, 26 Apr 2022 20:45:16 +0300 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client certificate not present) From: Konstantin Ananyev To: dev@dpdk.org Cc: stable@dpdk.org, Ido Goshen Subject: [PATCH 1/2] acl: fix rules with 8 bytes field size are broken Date: Tue, 26 Apr 2022 18:44:53 +0100 Message-Id: <20220426174454.311999-2-konstantin.v.ananyev@yandex.ru> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220426174454.311999-1-konstantin.v.ananyev@yandex.ru> References: <20220426174454.311999-1-konstantin.v.ananyev@yandex.ru> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org In theory ACL library allows fields with 8B long. Though in practice they usually not used, not tested, and as was revealed by Ido, this functionality is not working properly. There are few places inside ACL build code-path that need to be addressed. Bugzilla ID: 673 Fixes: dc276b5780c2 ("acl: new library") Cc: stable@dpdk.org Reported-by: Ido Goshen Signed-off-by: Konstantin Ananyev --- lib/acl/acl_bld.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/acl/acl_bld.c b/lib/acl/acl_bld.c index 7ea30f4186..2816632803 100644 --- a/lib/acl/acl_bld.c +++ b/lib/acl/acl_bld.c @@ -12,6 +12,9 @@ /* number of pointers per alloc */ #define ACL_PTR_ALLOC 32 +/* account for situation when all fields are 8B long */ +#define ACL_MAX_INDEXES (2 * RTE_ACL_MAX_FIELDS) + /* macros for dividing rule sets heuristics */ #define NODE_MAX 0x4000 #define NODE_MIN 0x800 @@ -80,7 +83,7 @@ struct acl_build_context { struct tb_mem_pool pool; struct rte_acl_trie tries[RTE_ACL_MAX_TRIES]; struct rte_acl_bld_trie bld_tries[RTE_ACL_MAX_TRIES]; - uint32_t data_indexes[RTE_ACL_MAX_TRIES][RTE_ACL_MAX_FIELDS]; + uint32_t data_indexes[RTE_ACL_MAX_TRIES][ACL_MAX_INDEXES]; /* memory free lists for nodes and blocks used for node ptrs */ struct acl_mem_block blocks[MEM_BLOCK_NUM]; @@ -988,7 +991,7 @@ build_trie(struct acl_build_context *context, struct rte_acl_build_rule *head, */ uint64_t mask; mask = RTE_ACL_MASKLEN_TO_BITMASK( - fld->mask_range.u32, + fld->mask_range.u64, rule->config->defs[n].size); /* gen a mini-trie for this field */ @@ -1301,6 +1304,9 @@ acl_build_index(const struct rte_acl_config *config, uint32_t *data_index) if (last_header != config->defs[n].input_index) { last_header = config->defs[n].input_index; data_index[m++] = config->defs[n].offset; + if (config->defs[n].size > sizeof(uint32_t)) + data_index[m++] = config->defs[n].offset + + sizeof(uint32_t); } } @@ -1487,7 +1493,7 @@ acl_set_data_indexes(struct rte_acl_ctx *ctx) memcpy(ctx->data_indexes + ofs, ctx->trie[i].data_index, n * sizeof(ctx->data_indexes[0])); ctx->trie[i].data_index = ctx->data_indexes + ofs; - ofs += RTE_ACL_MAX_FIELDS; + ofs += ACL_MAX_INDEXES; } } @@ -1643,7 +1649,7 @@ rte_acl_build(struct rte_acl_ctx *ctx, const struct rte_acl_config *cfg) /* allocate and fill run-time structures. */ rc = rte_acl_gen(ctx, bcx.tries, bcx.bld_tries, bcx.num_tries, bcx.cfg.num_categories, - RTE_ACL_MAX_FIELDS * RTE_DIM(bcx.tries) * + ACL_MAX_INDEXES * RTE_DIM(bcx.tries) * sizeof(ctx->data_indexes[0]), max_size); if (rc == 0) { /* set data indexes. */ From patchwork Tue Apr 26 17:44:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Konstantin Ananyev X-Patchwork-Id: 110284 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 3FA9BA050D; Tue, 26 Apr 2022 19:45:28 +0200 (CEST) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 22F634280C; Tue, 26 Apr 2022 19:45:28 +0200 (CEST) Received: from forward501j.mail.yandex.net (forward501j.mail.yandex.net [5.45.198.251]) by mails.dpdk.org (Postfix) with ESMTP id 73C9E4280A for ; Tue, 26 Apr 2022 19:45:26 +0200 (CEST) Received: from iva8-def7434e1e2c.qloud-c.yandex.net (iva8-def7434e1e2c.qloud-c.yandex.net [IPv6:2a02:6b8:c0c:3b96:0:640:def7:434e]) by forward501j.mail.yandex.net (Yandex) with ESMTP id F244062325A for ; Tue, 26 Apr 2022 20:45:25 +0300 (MSK) Received: from iva3-dd2bb2ff2b5f.qloud-c.yandex.net (iva3-dd2bb2ff2b5f.qloud-c.yandex.net [2a02:6b8:c0c:7611:0:640:dd2b:b2ff]) by iva8-def7434e1e2c.qloud-c.yandex.net (mxback/Yandex) with ESMTP id kndjtafoMm-jPgek7DL; Tue, 26 Apr 2022 20:45:25 +0300 X-Yandex-Fwd: 2 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yandex.ru; s=mail; t=1650995125; bh=gyfCUCaBsedfiCNCNPHNlv6gyu9VL1/X2eRoM6kOlFs=; h=In-Reply-To:Message-Id:References:Date:Subject:To:From; b=B/IMwsJ4cX/BAE45aignwNcN0VMqjfq/KBLz9Cu6Skg1KJBMwKp2Cjyvw2XbmQkQj SEnLVG/jBaO8JaI20NnujoOM8z7iil/OGurLUVyeZNDVr0dYKpdcQyM0PUSz9rqG6O /z8d6XdCWikDzo3J8EWFey0BPdKIosG8YK/LLeL4= Authentication-Results: iva8-def7434e1e2c.qloud-c.yandex.net; dkim=pass header.i=@yandex.ru Received: by iva3-dd2bb2ff2b5f.qloud-c.yandex.net (smtp/Yandex) with ESMTPSA id 4Jw1POtKVO-jPMGF80R; Tue, 26 Apr 2022 20:45:25 +0300 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client certificate not present) From: Konstantin Ananyev To: dev@dpdk.org Subject: [PATCH 2/2] app/acl: support different formats for IPv6 address Date: Tue, 26 Apr 2022 18:44:54 +0100 Message-Id: <20220426174454.311999-3-konstantin.v.ananyev@yandex.ru> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220426174454.311999-1-konstantin.v.ananyev@yandex.ru> References: <20220426174454.311999-1-konstantin.v.ananyev@yandex.ru> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Within ACL rule IPv6 address can be represented in different ways: either as 4x4B fields, or as 2x8B fields. Till now, only first format was supported. Extend test-acl to support both formats, mainly for testing and demonstrating purposes. To control desired behavior '--ipv6' command-line option is extend to accept an optional argument: To be more precise: '--ipv6' - use 4x4B fields format (default behavior) '--ipv6=4B' - use 4x4B fields format (default behavior) '--ipv6=8B' - use 2x8B fields format app/acl: use posix functions for network address parsing Also replaced home brewed IPv4/IPv6 address parsing with inet_pton() calls. Signed-off-by: Konstantin Ananyev --- app/test-acl/main.c | 355 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 276 insertions(+), 79 deletions(-) diff --git a/app/test-acl/main.c b/app/test-acl/main.c index 06e3847ab9..41ce83db08 100644 --- a/app/test-acl/main.c +++ b/app/test-acl/main.c @@ -57,6 +57,12 @@ enum { DUMP_MAX }; +enum { + IPV6_FRMT_NONE, + IPV6_FRMT_U32, + IPV6_FRMT_U64, +}; + struct acl_alg { const char *name; enum rte_acl_classify_alg alg; @@ -123,7 +129,7 @@ static struct { .name = "default", .alg = RTE_ACL_CLASSIFY_DEFAULT, }, - .ipv6 = 0 + .ipv6 = IPV6_FRMT_NONE, }; static struct rte_acl_param prm = { @@ -210,6 +216,7 @@ struct rte_acl_field_def ipv4_defs[NUM_FIELDS_IPV4] = { #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; @@ -219,6 +226,7 @@ struct ipv6_5tuple { uint16_t port_dst; }; +/* treat IPV6 address as uint32_t[4] (default mode) */ enum { PROTO_FIELD_IPV6, SRC1_FIELD_IPV6, @@ -234,6 +242,27 @@ enum { 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, @@ -314,6 +343,57 @@ struct rte_acl_field_def ipv6_defs[NUM_FIELDS_IPV6] = { }, }; +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, @@ -385,49 +465,11 @@ parse_cb_ipv4_trace(char *str, struct ipv4_5tuple *v) return 0; } -/* - * Parse IPv6 address, expects the following format: - * XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX (where X is a hexadecimal 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; } @@ -548,20 +590,33 @@ tracef_init(void) } 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++) { @@ -569,7 +624,7 @@ parse_ipv6_net(const char *in, struct rte_acl_field field[4]) 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]; } @@ -577,14 +632,88 @@ parse_ipv6_net(const char *in, struct rte_acl_field field[4]) 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 '@' */ @@ -600,28 +729,30 @@ parse_cb_ipv6_rule(char *str, struct acl_rule *v) 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, @@ -629,37 +760,61 @@ parse_cb_ipv6_rule(char *str, struct acl_rule *v) 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; - addr[0] = RTE_IPV4(a, b, c, d); + 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); + + GET_CB_FIELD(sm, m, 0, sizeof(uint32_t) * CHAR_BIT, 0); mask_len[0] = m; return 0; @@ -757,8 +912,14 @@ add_cb_rules(FILE *f, struct rte_acl_ctx *ctx) 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++) { @@ -804,9 +965,12 @@ acx_init(void) 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)); @@ -958,6 +1122,37 @@ get_alg_opt(const char *opt, const char *name) 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) { @@ -999,7 +1194,7 @@ print_usage(const char *prgname) "[--" OPT_ITER_NUM "=]\n" "[--" OPT_VERBOSE "=]\n" "[--" OPT_SEARCH_ALG "=%s]\n" - "[--" OPT_IPV6 "=]\n", + "[--" OPT_IPV6 "(=4B | 8B) ]\n", prgname, RTE_ACL_RESULTS_MULTIPLIER, (uint32_t)RTE_ACL_MAX_CATEGORIES, buf); @@ -1050,7 +1245,7 @@ get_input_opts(int argc, char **argv) {OPT_ITER_NUM, 1, 0, 0}, {OPT_VERBOSE, 1, 0, 0}, {OPT_SEARCH_ALG, 1, 0, 0}, - {OPT_IPV6, 0, 0, 0}, + {OPT_IPV6, 2, 0, 0}, {NULL, 0, 0, 0} }; @@ -1099,7 +1294,9 @@ get_input_opts(int argc, char **argv) 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) :