From patchwork Fri Jan 15 15:42:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kozyrev X-Patchwork-Id: 86706 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 4F99EA0A04; Fri, 15 Jan 2021 16:42:56 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 3E00A14117F; Fri, 15 Jan 2021 16:42: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 26B0214117E for ; Fri, 15 Jan 2021 16:42:54 +0100 (CET) Received: from Internal Mail-Server by MTLPINE1 (envelope-from akozyrev@nvidia.com) with SMTP; 15 Jan 2021 17:42:48 +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 10FFgmA3003066; Fri, 15 Jan 2021 17:42:48 +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, jerinjacobk@gmail.com Date: Fri, 15 Jan 2021 15:42:45 +0000 Message-Id: <20210115154246.8770-2-akozyrev@nvidia.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20210115154246.8770-1-akozyrev@nvidia.com> References: <20210113170751.13044-1-akozyrev@nvidia.com> <20210115154246.8770-1-akozyrev@nvidia.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v5 1/2] ethdev: introduce generic modify 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 the generic modify flow API to allow manipulations on an arbitrary header field (as well as mark, metadata or tag) using data from another field or a user-specified value. This generic modify 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 packet field/tag/metadata/mark/memory location or directly provided by a user. Supported operation are: - mov: copy data from source to destination. - add: integer addition, stores the result in destination. - sub: integer subtraction, stores the result in destination. 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 use from a source as well as the offset can be be specified to allow a partial copy or dividing a big packet field into multiple small fields (e.g. copying 128 bits of IPv6 to 4 tags). An immediate value (or pointer to it) can be specified instead of the level and the offset for the special FIELD_VALUE ID (or FIELD_POINTER). Can be used as a source only, in case of user-provided values. RFC: http://patches.dpdk.org/patch/85384/ Signed-off-by: Alexander Kozyrev Acked-by: Ori Kam --- v1: Initialy RTE_FLOW_ACTION_TYPE_COPY_ITEM v2: Renamed to RTE_FLOW_ACTION_TYPE_COPY_FIELD v3: Redesigned as RTE_FLOW_ACTION_TYPE_MODIFY_FIELD --- doc/guides/prog_guide/rte_flow.rst | 65 +++++++++++++++++++++ doc/guides/rel_notes/release_21_02.rst | 8 +++ lib/librte_ethdev/rte_flow.c | 2 + lib/librte_ethdev/rte_flow.h | 79 +++++++++++++++++++++++++- 4 files changed, 153 insertions(+), 1 deletion(-) diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst index 86b3444803..3b1babd587 100644 --- a/doc/guides/prog_guide/rte_flow.rst +++ b/doc/guides/prog_guide/rte_flow.rst @@ -2766,6 +2766,71 @@ The behaviour of the shared action defined by ``action`` argument of type | no properties | +---------------+ +Action: ``MODIFY_FIELD`` +^^^^^^^^^^^^^^^^^^^^^^^^ + +Modify ``dst`` field according to ``op`` selected (move, addition, +substraction) with ``width`` bits of data from ``src`` 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``. +The immediate value ``RTE_FLOW_FIELD_VALUE`` (or a pointer to it +``RTE_FLOW_FIELD_POINTER``) is allowed as a source only. +``RTE_FLOW_FIELD_START`` is used to point to the beginning of a packet. + +``op`` selects the operation to perform on a destination field. +- ``mov`` copies the data from ``src`` field to ``dst`` field. +- ``add`` adds together ``dst`` and ``src`` and stores the result into ``dst``. +- ``sub`` substracts ``src`` from ``dst`` and stores the result into ``dst`` + + ``width`` defines a number of bits to use from ``src`` field. + + ``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 a 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 a 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 an underlying PMD driver. + +``value`` sets an immediate value to be used as a source or points to a +location of the value in memory. It is used instead of ``level`` and ``offset`` +for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively. + +.. _table_rte_flow_action_modify_field: + +.. table:: MODIFY_FIELD + + +-----------------------------------------+ + | Field | Value | + +===============+=========================+ + | ``op`` | operation to perform | + | ``dst`` | destination field | + | ``src`` | source field | + | ``width`` | number of bits to use | + +---------------+-------------------------+ + +.. _table_rte_flow_action_modify_data: + +.. table:: destination/source field definition + + +--------------------------------------------------------------------------+ + | Field | Value | + +===============+==========================================================+ + | ``field`` | ID: packet field, mark, meta, tag, immediate, pointer | + | ``level`` | encapsulation level of a packet field or tag array index | + | ``offset`` | number of bits to skip at the beginning | + | ``value`` | immediate value or a poiner to it | + +---------------+----------------------------------------------------------+ + Negative types ~~~~~~~~~~~~~~ diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst index c64294e7a6..fc828cb21d 100644 --- a/doc/guides/rel_notes/release_21_02.rst +++ b/doc/guides/rel_notes/release_21_02.rst @@ -55,6 +55,14 @@ New Features Also, make sure to start the actual text at the margin. ======================================================= +* **Added support of modify field action in the flow API.** + + Added modify action support to perform various operations on + any arbitrary header field (as well as mark, metadata or tag values): + ``RTE_FLOW_ACTION_TYPE_MODIFY_FIELD``. + supported operations are: overwriting the field with the content from + another field, addition and subtraction of an immediate value. + * **Updated Broadcom bnxt driver.** Updated the Broadcom bnxt driver with fixes and improvements, including: diff --git a/lib/librte_ethdev/rte_flow.c b/lib/librte_ethdev/rte_flow.c index a06f64c271..9dd051f3c2 100644 --- a/lib/librte_ethdev/rte_flow.c +++ b/lib/librte_ethdev/rte_flow.c @@ -176,6 +176,8 @@ 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(MODIFY_FIELD, + sizeof(struct rte_flow_action_modify_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..6610e638d7 100644 --- a/lib/librte_ethdev/rte_flow.h +++ b/lib/librte_ethdev/rte_flow.h @@ -2198,6 +2198,17 @@ enum rte_flow_action_type { * struct rte_flow_shared_action). */ RTE_FLOW_ACTION_TYPE_SHARED, + + /** + * Modify a packet header field, tag, mark or metadata. + * + * Allow the modification of an arbitrary header field via + * set, add and sub operations or copying its content into + * tag, meta or mark for future processing. + * + * See struct rte_flow_action_modify_field. + */ + RTE_FLOW_ACTION_TYPE_MODIFY_FIELD, }; /** @@ -2777,7 +2788,6 @@ struct rte_flow_action_set_dscp { uint8_t dscp; }; - /** * RTE_FLOW_ACTION_TYPE_SHARED * @@ -2791,6 +2801,73 @@ 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, + RTE_FLOW_FIELD_POINTER, + RTE_FLOW_FIELD_VALUE, +}; + +struct rte_flow_action_modify_data { + enum rte_flow_field_id field; + RTE_STD_C11 + union { + struct { + uint32_t level; + uint32_t offset; + }; + uint64_t value; + }; +}; + +enum rte_flow_modify_op { + RTE_FLOW_MODIFY_MOV = 0, + RTE_FLOW_MODIFY_ADD, + RTE_FLOW_MODIFY_SUB, +}; + +/** + * @warning + * @b EXPERIMENTAL: this structure may change without prior notice + * + * RTE_FLOW_ACTION_TYPE_MODIFY_FIELD + * + * Modifies a destination header field according to the specified + * operation. Another packet field can be used as a source as well + * as tag, mark, metadata or an immediate value or a pointer to it. + * Width is the number of bits used from the source item. + */ +struct rte_flow_action_modify_field { + enum rte_flow_modify_op operation; + struct rte_flow_action_modify_data dst; + struct rte_flow_action_modify_data src; + uint32_t width; +}; + /* Mbuf dynamic field offset for metadata. */ extern int32_t rte_flow_dynf_metadata_offs; From patchwork Fri Jan 15 15:42:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Kozyrev X-Patchwork-Id: 86707 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 23CC9A0A04; Fri, 15 Jan 2021 16:43:04 +0100 (CET) Received: from [217.70.189.124] (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 71D7C141187; Fri, 15 Jan 2021 16:42:56 +0100 (CET) Received: from mellanox.co.il (mail-il-dmz.mellanox.com [193.47.165.129]) by mails.dpdk.org (Postfix) with ESMTP id 26CC014117F for ; Fri, 15 Jan 2021 16:42:54 +0100 (CET) Received: from Internal Mail-Server by MTLPINE1 (envelope-from akozyrev@nvidia.com) with SMTP; 15 Jan 2021 17:42:48 +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 10FFgmA4003066; Fri, 15 Jan 2021 17:42:48 +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, jerinjacobk@gmail.com Date: Fri, 15 Jan 2021 15:42:46 +0000 Message-Id: <20210115154246.8770-3-akozyrev@nvidia.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20210115154246.8770-1-akozyrev@nvidia.com> References: <20210113170751.13044-1-akozyrev@nvidia.com> <20210115154246.8770-1-akozyrev@nvidia.com> MIME-Version: 1.0 Subject: [dpdk-dev] [PATCH v5 2/2] app/testpmd: add support for modify field 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_MODIFY_FIELD to the testpmd. Implement CLI to create the modify_field action and supply all the needed parameters to modify an arbitrary packet field (as well as mark, tag or metadata) with data from another field or immediate value. Example of the flow is the following: flow create 0 egress group 1 pattern eth / ipv4 / udp / end actions modify_field op mov dst_type tag dst_level 2 dst_offset 8 src_type gtp_teid src_level 0 src_offset 0 width 16 / end This flow copies 16 bits from the second 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. op, dst_type, src_type and width are the mandatory parameters to specify. Levels and offset are 0 by default if they are not overridden by a user. The operation can be mov, add or sub. Signed-off-by: Alexander Kozyrev Acked-by: Ori Kam --- v1: Initial implementation. v2: Made dst_type, src_type and width only mandatory parameters. v3: Reworked to accomodate API change from copy_field to modify_field. --- app/test-pmd/cmdline_flow.c | 246 ++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) diff --git a/app/test-pmd/cmdline_flow.c b/app/test-pmd/cmdline_flow.c index 585cab98b4..62305b7fb7 100644 --- a/app/test-pmd/cmdline_flow.c +++ b/app/test-pmd/cmdline_flow.c @@ -408,6 +408,19 @@ enum index { ACTION_SAMPLE_INDEX_VALUE, ACTION_SHARED, SHARED_ACTION_ID2PTR, + ACTION_MODIFY_FIELD, + ACTION_MODIFY_FIELD_OP, + ACTION_MODIFY_FIELD_OP_VALUE, + ACTION_MODIFY_FIELD_DST_TYPE, + ACTION_MODIFY_FIELD_DST_TYPE_VALUE, + ACTION_MODIFY_FIELD_DST_LEVEL, + ACTION_MODIFY_FIELD_DST_OFFSET, + ACTION_MODIFY_FIELD_SRC_TYPE, + ACTION_MODIFY_FIELD_SRC_TYPE_VALUE, + ACTION_MODIFY_FIELD_SRC_LEVEL, + ACTION_MODIFY_FIELD_SRC_OFFSET, + ACTION_MODIFY_FIELD_SRC_VALUE, + ACTION_MODIFY_FIELD_WIDTH, }; /** Maximum size for pattern in struct rte_flow_item_raw. */ @@ -561,6 +574,22 @@ 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 modify_field_ops[] = { + "mov", "add", "sub", NULL +}; + +static const char *const modify_field_ids[] = { + "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", "value", "pointer", NULL +}; + /** Maximum number of subsequent tokens and arguments on the stack. */ #define CTX_STACK_SIZE 16 @@ -1306,6 +1335,7 @@ static const enum index next_action[] = { ACTION_AGE, ACTION_SAMPLE, ACTION_SHARED, + ACTION_MODIFY_FIELD, ZERO, }; @@ -1556,6 +1586,21 @@ static const enum index next_action_sample[] = { ZERO, }; +static const enum index action_modify_field_dst[] = { + ACTION_MODIFY_FIELD_DST_LEVEL, + ACTION_MODIFY_FIELD_DST_OFFSET, + ACTION_MODIFY_FIELD_SRC_TYPE, + ZERO, +}; + +static const enum index action_modify_field_src[] = { + ACTION_MODIFY_FIELD_SRC_LEVEL, + ACTION_MODIFY_FIELD_SRC_OFFSET, + ACTION_MODIFY_FIELD_SRC_VALUE, + ACTION_MODIFY_FIELD_WIDTH, + ZERO, +}; + static int parse_set_raw_encap_decap(struct context *, const struct token *, const char *, unsigned int, void *, unsigned int); @@ -1638,6 +1683,14 @@ 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_modify_field_op(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size); +static int +parse_vc_modify_field_id(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 +1775,10 @@ 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_modify_field_op(struct context *, const struct token *, + unsigned int, char *, unsigned int); +static int comp_set_modify_field_id(struct context *, const struct token *, + unsigned int, char *, unsigned int); /** Token definitions. */ static const struct token token_list[] = { @@ -4037,6 +4094,103 @@ static const struct token token_list[] = { .call = parse_vc_action_raw_decap_index, .comp = comp_set_raw_index, }, + [ACTION_MODIFY_FIELD] = { + .name = "modify_field", + .help = "modify destination field with data from source field", + .priv = PRIV_ACTION(MODIFY_FIELD, + sizeof(struct rte_flow_action_modify_field)), + .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_OP)), + .call = parse_vc, + }, + [ACTION_MODIFY_FIELD_OP] = { + .name = "op", + .help = "operation type", + .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE), + NEXT_ENTRY(ACTION_MODIFY_FIELD_OP_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_OP_VALUE] = { + .name = "{operation}", + .help = "operation type value", + .call = parse_vc_modify_field_op, + .comp = comp_set_modify_field_op, + }, + [ACTION_MODIFY_FIELD_DST_TYPE] = { + .name = "dst_type", + .help = "destination field type", + .next = NEXT(action_modify_field_dst, + NEXT_ENTRY(ACTION_MODIFY_FIELD_DST_TYPE_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_DST_TYPE_VALUE] = { + .name = "{dst_type}", + .help = "destination field type value", + .call = parse_vc_modify_field_id, + .comp = comp_set_modify_field_id, + }, + [ACTION_MODIFY_FIELD_DST_LEVEL] = { + .name = "dst_level", + .help = "destination field level", + .next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + dst.level)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_DST_OFFSET] = { + .name = "dst_offset", + .help = "destination field bit offset", + .next = NEXT(action_modify_field_dst, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + dst.offset)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_TYPE] = { + .name = "src_type", + .help = "source field type", + .next = NEXT(action_modify_field_src, + NEXT_ENTRY(ACTION_MODIFY_FIELD_SRC_TYPE_VALUE)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_TYPE_VALUE] = { + .name = "{src_type}", + .help = "source field type value", + .call = parse_vc_modify_field_id, + .comp = comp_set_modify_field_id, + }, + [ACTION_MODIFY_FIELD_SRC_LEVEL] = { + .name = "src_level", + .help = "source field level", + .next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + src.level)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_OFFSET] = { + .name = "src_offset", + .help = "source field bit offset", + .next = NEXT(action_modify_field_src, NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + src.offset)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_FIELD_SRC_VALUE] = { + .name = "src_value", + .help = "source immediate value", + .next = NEXT(NEXT_ENTRY(ACTION_MODIFY_FIELD_WIDTH), + NEXT_ENTRY(UNSIGNED)), + .args = ARGS(ARGS_ENTRY(struct rte_flow_action_modify_field, + src.value)), + .call = parse_vc_conf, + }, + [ACTION_MODIFY_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_modify_field, + width)), + .call = parse_vc_conf, + }, /* Top level command. */ [SET] = { .name = "set", @@ -5960,6 +6114,62 @@ parse_vc_action_sample_index(struct context *ctx, const struct token *token, return len; } +/** Parse operation for modify_field command. */ +static int +parse_vc_modify_field_op(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size) +{ + struct rte_flow_action_modify_field *action_modify_field; + unsigned int i; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_MODIFY_FIELD_OP_VALUE) + return -1; + for (i = 0; modify_field_ops[i]; ++i) + if (!strcmp_partial(modify_field_ops[i], str, len)) + break; + if (!modify_field_ops[i]) + return -1; + if (!ctx->object) + return len; + action_modify_field = ctx->object; + action_modify_field->operation = (enum rte_flow_modify_op)i; + return len; +} + +/** Parse id for modify_field command. */ +static int +parse_vc_modify_field_id(struct context *ctx, const struct token *token, + const char *str, unsigned int len, void *buf, + unsigned int size) +{ + struct rte_flow_action_modify_field *action_modify_field; + unsigned int i; + + (void)token; + (void)buf; + (void)size; + if (ctx->curr != ACTION_MODIFY_FIELD_DST_TYPE_VALUE && + ctx->curr != ACTION_MODIFY_FIELD_SRC_TYPE_VALUE) + return -1; + for (i = 0; modify_field_ids[i]; ++i) + if (!strcmp_partial(modify_field_ids[i], str, len)) + break; + if (!modify_field_ids[i]) + return -1; + if (!ctx->object) + return len; + action_modify_field = ctx->object; + if (ctx->curr == ACTION_MODIFY_FIELD_DST_TYPE_VALUE) + action_modify_field->dst.field = (enum rte_flow_field_id)i; + else + action_modify_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 +7239,42 @@ comp_set_sample_index(struct context *ctx, const struct token *token, return nb; } +/** Complete operation for modify_field command. */ +static int +comp_set_modify_field_op(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; modify_field_ops[idx]; ++idx) + ; + if (!buf) + return idx + 1; + if (ent < idx) + return strlcpy(buf, modify_field_ops[ent], size); + return -1; +} + +/** Complete field id for modify_field command. */ +static int +comp_set_modify_field_id(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; modify_field_ids[idx]; ++idx) + ; + if (!buf) + return idx + 1; + if (ent < idx) + return strlcpy(buf, modify_field_ids[ent], size); + return -1; +} + /** Internal context. */ static struct context cmd_flow_context;