From patchwork Wed Jan 13 17:07:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kozyrev X-Patchwork-Id: 86487 X-Patchwork-Delegate: ferruh.yigit@amd.com 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 5F7D1A0A02; Wed, 13 Jan 2021 18:07:55 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3ABBA140E23; Wed, 13 Jan 2021 18:07:55 +0100 (CET) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by mails.dpdk.org (Postfix) with ESMTP id 27C3E140E23 for ; Wed, 13 Jan 2021 18:07:54 +0100 (CET) Received: from Internal Mail-Server by MTLPINE1 (envelope-from akozyrev@nvidia.com) with SMTP; 13 Jan 2021 19:07:52 +0200 Received: from nvidia.com (pegasus02.mtr.labs.mlnx [10.210.16.122]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 10DH7qaH032089; Wed, 13 Jan 2021 19:07:52 +0200 From: Alexander Kozyrev To: dev@dpdk.org Cc: viacheslavo@nvidia.com, orika@nvidia.com, thomas@monjalon.net, ferruh.yigit@intel.com, andrew.rybchenko@oktetlabs.ru Date: Wed, 13 Jan 2021 17:07:50 +0000 Message-Id: <20210113170751.13044-2-akozyrev@nvidia.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20210113170751.13044-1-akozyrev@nvidia.com> References: <20210113033854.11827-1-akozyrev@nvidia.com> <20210113170751.13044-1-akozyrev@nvidia.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v4 1/2] ethdev: introduce generic copy rte flow action 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 Sender: "dev" Implement a generic copy flow API to allow copying of an arbitrary header field (as well as mark, metadata or tag) to another field. This generic copy mechanism removes the necessity to implement a separate RTE Flow action every time we need to modify a new packet field in the future. A user-provided value can be used from a specified tag/metadata/mark or directly copied from another packet field. The field ID is used to specify the desired source/destination packet field in order to simplify the API for various encapsulation models. Specifying the packet field ID with the needed encapsulation level is able to quickly get a packet field for any inner packet header. Alternatively, the special ID (ITEM_START) can be used to point to the very beginning of a packet. This ID in conjunction with the offset parameter provides great flexibility to copy/modify any part of a packet as needed. The number of bits to copy as well as the offset to start from can be specified to allow a partial copy or dividing a big packet field into multiple small fields (let's say copying 128 bits of IPv6 to 4 tags). RFC: http://patches.dpdk.org/patch/85384/ Signed-off-by: Alexander Kozyrev Acked-by: Ori Kam --- doc/guides/prog_guide/rte_flow.rst | 57 +++++++++++++++++++++++++ doc/guides/rel_notes/release_21_02.rst | 5 +++ lib/librte_ethdev/rte_flow.c | 1 + lib/librte_ethdev/rte_flow.h | 59 ++++++++++++++++++++++++++ 4 files changed, 122 insertions(+) diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst index 86b3444803..9617b9c1ba 100644 --- a/doc/guides/prog_guide/rte_flow.rst +++ b/doc/guides/prog_guide/rte_flow.rst @@ -2766,6 +2766,63 @@ The behaviour of the shared action defined by ``action`` argument of type | no properties | +---------------+ +Action: ``COPY_FIELD`` +^^^^^^^^^^^^^^^^^^^^^^ + +Copy ``width`` bits from ``src`` field to ``dst`` field. + +Any arbitrary header field (as well as mark, metadata or tag values) +can be used as both source and destination fields as set by ``field``. +``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet. +The copy is ignored in case the field specified is not present in a packet. + + ``width`` defines a number of bits to copy. A user is responsible for + supplying the appropriate length to copy. The width that exceeds the + hardware capabilities is rejected. + + ``level`` is used to access any packet field on any encapsulation level + as well as any tag element in the tag array. + +- ``0`` means the default behaviour. Depending on the packet type, it can + mean outermost, innermost or anything in between. + +- ``1`` requests access to the outermost packet encapsulation level. + +- ``2`` and subsequent values requests access to the specified packet + encapsulation level, from outermost to innermost (lower to higher values). + For the tag array ``level`` translates directly into the array index. + +``offset`` specifies the number of bits to skip from an field's start. +That allows performing a partial copy of the needed part or to divide a big +packet field into multiple smaller fields. Alternatively, ``offset`` allows +going past the specified packet field boundary to copy an field to an +arbitrary place in a packet essentially providing a way to copy any part of +a packet to any other part of it if supported by a underlying PMD driver. + +.. _table_rte_flow_action_copy_field: + +.. table:: COPY_FIELD + + +-----------------------------------------+ + | Field | Value | + +===============+=========================+ + | ``dst`` | destination field | + | ``src`` | source field | + | ``width`` | number of bits to copy | + +---------------+-------------------------+ + +.. _table_rte_flow_action_copy_data: + +.. table:: destination/source field definition + + +--------------------------------------------------------------------------+ + | Field | Value | + +===============+==========================================================+ + | ``field`` | field ID of a packet field or mark/metadata/tag | + | ``level`` | encapsulation level of a packet field or tag array index | + | ``offset`` | number of bits to skip at the beginning during the copy | + +---------------+----------------------------------------------------------+ + Negative types ~~~~~~~~~~~~~~ diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst index 706cbf8f0c..109b082931 100644 --- a/doc/guides/rel_notes/release_21_02.rst +++ b/doc/guides/rel_notes/release_21_02.rst @@ -55,6 +55,11 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Added support of copy action in the flow API.** + + Added copy action support to copy any arbitrary header field + (as well as mark, metadata or tag values) to another one: + ``RTE_FLOW_ACTION_TYPE_COPY_FIELD``. Removed Items ------------- diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c index a06f64c271..c3154a29e2 100644 --- a/lib/librte_ethdev/rte_flow.c +++ b/lib/librte_ethdev/rte_flow.c @@ -176,6 +176,7 @@ static const struct rte_flow_desc_data rte_flow_desc_action[] = { MK_FLOW_ACTION(SET_IPV6_DSCP, sizeof(struct rte_flow_action_set_dscp)), MK_FLOW_ACTION(AGE, sizeof(struct rte_flow_action_age)), MK_FLOW_ACTION(SAMPLE, sizeof(struct rte_flow_action_sample)), + MK_FLOW_ACTION(COPY_FIELD, sizeof(struct rte_flow_action_copy_field)), /** * Shared action represented as handle of type * (struct rte_flow_shared action *) stored in conf field (see diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h index 0977a78270..e2a2807f65 100644 --- a/lib/librte_ethdev/rte_flow.h +++ b/lib/librte_ethdev/rte_flow.h @@ -2198,6 +2198,16 @@ enum rte_flow_action_type { * struct rte_flow_shared_action). */ RTE_FLOW_ACTION_TYPE_SHARED, + + /** + * Copy a packet header field, tag, mark or metadata. + * + * Allow saving an arbitrary header field by copying its value + * to a tag/mark/metadata or copy it into another header field. + * + * See struct rte_flow_action_copy_field. + */ + RTE_FLOW_ACTION_TYPE_COPY_FIELD, }; /** @@ -2791,6 +2801,55 @@ struct rte_flow_action_set_dscp { */ struct rte_flow_shared_action; +enum rte_flow_field_id { + RTE_FLOW_FIELD_START = 0, + RTE_FLOW_FIELD_MAC_DST, + RTE_FLOW_FIELD_MAC_SRC, + RTE_FLOW_FIELD_VLAN_TYPE, + RTE_FLOW_FIELD_VLAN_ID, + RTE_FLOW_FIELD_MAC_TYPE, + RTE_FLOW_FIELD_IPV4_DSCP, + RTE_FLOW_FIELD_IPV4_TTL, + RTE_FLOW_FIELD_IPV4_SRC, + RTE_FLOW_FIELD_IPV4_DST, + RTE_FLOW_FIELD_IPV6_HOPLIMIT, + RTE_FLOW_FIELD_IPV6_SRC, + RTE_FLOW_FIELD_IPV6_DST, + RTE_FLOW_FIELD_TCP_PORT_SRC, + RTE_FLOW_FIELD_TCP_PORT_DST, + RTE_FLOW_FIELD_TCP_SEQ_NUM, + RTE_FLOW_FIELD_TCP_ACK_NUM, + RTE_FLOW_FIELD_TCP_FLAGS, + RTE_FLOW_FIELD_UDP_PORT_SRC, + RTE_FLOW_FIELD_UDP_PORT_DST, + RTE_FLOW_FIELD_VXLAN_VNI, + RTE_FLOW_FIELD_GENEVE_VNI, + RTE_FLOW_FIELD_GTP_TEID, + RTE_FLOW_FIELD_TAG, + RTE_FLOW_FIELD_MARK, + RTE_FLOW_FIELD_META, +}; + +struct rte_flow_action_copy_data { + enum rte_flow_field_id field; + uint32_t level; + uint32_t offset; +}; + +/** + * RTE_FLOW_ACTION_TYPE_COPY_FIELD + * + * Copies a specified number of bits from a source header field + * to a destination header field. Tag, mark or metadata can also + * be used as a source/destination to allow saving/overwriting + * an arbitrary header field with a user-specified value. + */ +struct rte_flow_action_copy_field { + struct rte_flow_action_copy_data dst; + struct rte_flow_action_copy_data src; + uint32_t width; +}; + /* Mbuf dynamic field offset for metadata. */ extern int32_t rte_flow_dynf_metadata_offs; From patchwork Wed Jan 13 17:07:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kozyrev X-Patchwork-Id: 86489 X-Patchwork-Delegate: ferruh.yigit@amd.com 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 CD994A0A02; Wed, 13 Jan 2021 18:08:08 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id BEB43140E59; Wed, 13 Jan 2021 18:07:57 +0100 (CET) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by mails.dpdk.org (Postfix) with ESMTP id 3EE53140E41 for ; Wed, 13 Jan 2021 18:07:54 +0100 (CET) Received: from Internal Mail-Server by MTLPINE1 (envelope-from akozyrev@nvidia.com) with SMTP; 13 Jan 2021 19:07:52 +0200 Received: from nvidia.com (pegasus02.mtr.labs.mlnx [10.210.16.122]) by labmailer.mlnx (8.13.8/8.13.8) with ESMTP id 10DH7qaI032089; Wed, 13 Jan 2021 19:07:52 +0200 From: Alexander Kozyrev To: dev@dpdk.org Cc: viacheslavo@nvidia.com, orika@nvidia.com, thomas@monjalon.net, ferruh.yigit@intel.com, andrew.rybchenko@oktetlabs.ru Date: Wed, 13 Jan 2021 17:07:51 +0000 Message-Id: <20210113170751.13044-3-akozyrev@nvidia.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20210113170751.13044-1-akozyrev@nvidia.com> References: <20210113033854.11827-1-akozyrev@nvidia.com> <20210113170751.13044-1-akozyrev@nvidia.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v4 2/2] app/testpmd: add support for generic copy rte flow action 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 Sender: "dev" Add support for the RTE_FLOW_ACTION_COPY_FIELD to the testpmd. Implement CLI to create the copy_field action and supply all the needed parameters to copy an arbitrary packet field (as well as mark, tag or metadata) into another field. Example of the flow is the following: flow create 0 egress group 1 pattern eth / ipv4 / udp / end actions copy_field dst_type tag dst_level 0 dst_offset 8 src_type gtp_teid src_level 0 src_offset 0 width 32 / end This flow copies 32 bits from the first Tag in the Tags array into the outermost GTP TEID packet header field. 8 bits of the Tag are skipped as indicated by the dst_offset action parameter. dst_type and src_type are the only mandatory parameters to specify. Levels and offset are 0 by default if they are not overridden by a user. The width parameter gets the smallest width from the source and destination sizes if it is not specified. Signed-off-by: Alexander Kozyrev Acked-by: Ori Kam --- app/test-pmd/cmdline_flow.c | 166 ++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 585cab98b4..115d4772f9 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -408,6 +408,16 @@ enum index { ACTION_SAMPLE_INDEX_VALUE, ACTION_SHARED, SHARED_ACTION_ID2PTR, + ACTION_COPY_FIELD, + ACTION_COPY_FIELD_DST_TYPE, + ACTION_COPY_FIELD_DST_TYPE_VALUE, + ACTION_COPY_FIELD_DST_LEVEL, + ACTION_COPY_FIELD_DST_OFFSET, + ACTION_COPY_FIELD_SRC_TYPE, + ACTION_COPY_FIELD_SRC_TYPE_VALUE, + ACTION_COPY_FIELD_SRC_LEVEL, + ACTION_COPY_FIELD_SRC_OFFSET, + ACTION_COPY_FIELD_WIDTH, }; /** Maximum size for pattern in struct rte_flow_item_raw. */ @@ -561,6 +571,18 @@ struct rte_flow_action_count sample_count[RAW_SAMPLE_CONFS_MAX_NUM]; struct rte_flow_action_port_id sample_port_id[RAW_SAMPLE_CONFS_MAX_NUM]; struct rte_flow_action_raw_encap sample_encap[RAW_SAMPLE_CONFS_MAX_NUM]; +static const char *const copy_field_table[] = { + "start", "mac_dst", "mac_src", + "vlan_type", "vlan_id", "mac_type", + "ipv4_dscp", "ipv4_ttl", "ipv4_src", "ipv4_dst", + "ipv6_hoplimit", "ipv6_src", "ipv6_dst", + "tcp_port_src", "tcp_port_dst", + "tcp_seq_num", "tcp_ack_num", "tcp_flags", + "udp_port_src", "udp_port_dst", + "vxlan_vni", "geneve_vni", "gtp_teid", + "tag", "mark", "meta", NULL +}; + /** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16 @@ -1306,6 +1328,7 @@ static const enum index next_action[] = { ACTION_AGE, ACTION_SAMPLE, ACTION_SHARED, + ACTION_COPY_FIELD, ZERO, }; @@ -1556,6 +1579,20 @@ static const enum index next_action_sample[] = { ZERO, }; +static const enum index action_copy_field_dst[] = { + ACTION_COPY_FIELD_DST_LEVEL, + ACTION_COPY_FIELD_DST_OFFSET, + ACTION_COPY_FIELD_SRC_TYPE, + ZERO, +}; + +static const enum index action_copy_field_src[] = { + ACTION_COPY_FIELD_SRC_LEVEL, + ACTION_COPY_FIELD_SRC_OFFSET, + ACTION_COPY_FIELD_WIDTH, + ZERO, +}; + static int parse_set_raw_encap_decap(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1638,6 +1675,10 @@ static int parse_vc_action_sample_index(struct context *ctx, const struct token *token, const char *str, unsigned int len, void *buf, unsigned int size); +static int +parse_vc_copy_field(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size); static int parse_destroy(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1722,6 +1763,8 @@ static int comp_set_raw_index(struct context *, const struct token *, unsigned int, char *, unsigned int); static int comp_set_sample_index(struct context *, const struct token *, unsigned int, char *, unsigned int); +static int comp_set_copy_field(struct context *, const struct token *, + unsigned int, char *, unsigned int); /** Token definitions. */ static const struct token token_list[] = { @@ -4037,6 +4080,81 @@ static const struct token token_list[] = { .call = parse_vc_action_raw_decap_index, .comp = comp_set_raw_index, }, + [ACTION_COPY_FIELD] = { + .name = "copy_field", + .help = "copy data from destination field to source field", + .priv = PRIV_ACTION(COPY_FIELD, + sizeof(struct rte_flow_action_copy_field)), + .next = NEXT(NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE)), + .call = parse_vc, + }, + [ACTION_COPY_FIELD_DST_TYPE] = { + .name = "dst_type", + .help = "destination field type", + .next = NEXT(action_copy_field_dst, + NEXT_ENTRY(ACTION_COPY_FIELD_DST_TYPE_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_COPY_FIELD_DST_TYPE_VALUE] = { + .name = "{type}", + .help = "destination field type value", + .call = parse_vc_copy_field, + .comp = comp_set_copy_field, + }, + [ACTION_COPY_FIELD_DST_LEVEL] = { + .name = "dst_level", + .help = "destination field level", + .next = NEXT(action_copy_field_dst, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field, + dst.level)), + .call = parse_vc_conf, + }, + [ACTION_COPY_FIELD_DST_OFFSET] = { + .name = "dst_offset", + .help = "destination field bit offset", + .next = NEXT(action_copy_field_dst, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field, + dst.offset)), + .call = parse_vc_conf, + }, + [ACTION_COPY_FIELD_SRC_TYPE] = { + .name = "src_type", + .help = "source field type", + .next = NEXT(action_copy_field_src, + NEXT_ENTRY(ACTION_COPY_FIELD_SRC_TYPE_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_COPY_FIELD_SRC_TYPE_VALUE] = { + .name = "{type}", + .help = "source field type value", + .call = parse_vc_copy_field, + .comp = comp_set_copy_field, + }, + [ACTION_COPY_FIELD_SRC_LEVEL] = { + .name = "src_level", + .help = "source field level", + .next = NEXT(action_copy_field_src, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field, + src.level)), + .call = parse_vc_conf, + }, + [ACTION_COPY_FIELD_SRC_OFFSET] = { + .name = "src_offset", + .help = "source field bit offset", + .next = NEXT(action_copy_field_src, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field, + src.offset)), + .call = parse_vc_conf, + }, + [ACTION_COPY_FIELD_WIDTH] = { + .name = "width", + .help = "number of bits to copy", + .next = NEXT(NEXT_ENTRY(ACTION_NEXT), + NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_copy_field, + width)), + .call = parse_vc_conf, + }, /* Top level command. */ [SET] = { .name = "set", @@ -5960,6 +6078,36 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token, return len; } +/** Parse tokens for copy_field command. */ +static int +parse_vc_copy_field(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size) +{ + struct rte_flow_action_copy_field *action_copy_field; + unsigned int i; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_COPY_FIELD_DST_TYPE_VALUE && + ctx->curr != ACTION_COPY_FIELD_SRC_TYPE_VALUE) + return -1; + for (i = 0; copy_field_table[i]; ++i) + if (!strcmp_partial(copy_field_table[i], str, len)) + break; + if (!copy_field_table[i]) + return -1; + if (!ctx->object) + return len; + action_copy_field = ctx->object; + if (ctx->curr == ACTION_COPY_FIELD_DST_TYPE_VALUE) + action_copy_field->dst.field = (enum rte_flow_field_id)i; + else + action_copy_field->src.field = (enum rte_flow_field_id)i; + return len; +} + /** Parse tokens for destroy command. */ static int parse_destroy(struct context *ctx, const struct token *token, @@ -7029,6 +7177,24 @@ comp_set_sample_index(struct context *ctx, const struct token *token, return nb; } +/** Complete field type for copy_field command. */ +static int +comp_set_copy_field(struct context *ctx, const struct token *token, + unsigned int ent, char *buf, unsigned int size) +{ + uint16_t idx = 0; + + RTE_SET_USED(ctx); + RTE_SET_USED(token); + for (idx = 0; copy_field_table[idx]; ++idx) + ; + if (!buf) + return idx + 1; + if (ent < idx) + return strlcpy(buf, copy_field_table[ent], size); + return -1; +} + /** Internal context. */ static struct context cmd_flow_context;