From 07627fbf15063172a9cad325082066b60d3ed96c Mon Sep 17 00:00:00 2001 From: Jiawei Wang Date: Tue, 12 Jan 2021 12:29:18 +0200 Subject: [PATCH] net/mlx5: support E-Switch mirroring with modify action While there's the modify action and sample action with ratio=1 in the E-Switch flow, and modify action is after the sample action, means that the modify should only impact on after sample. MLX5 PMD will monitor the above case and split the E-Switch flow into two sub flows, similar as sample flow did before: - the prefix sub flow with all actions preceding the sample and the sample action itself, also append the new jump action after sample in the prefix sub flow; - the suffix sub flow with the modify action and other actions following the sample action. The flow split as below: Original flow: items / actions pre / sample / modify / actions sfx prefix sub flow - items / actions pre / set_tag action / sample / jump suffix sub flow - tag_item / modify / actions sfx Signed-off-by: Jiawei Wang Acked-by: Viacheslav Ovsiienko --- doc/guides/nics/mlx5.rst | 1 + doc/guides/rel_notes/release_21_02.rst | 2 + drivers/net/mlx5/mlx5_flow.c | 175 +++++++++++++++++-------- drivers/net/mlx5/mlx5_flow_dv.c | 10 -- 4 files changed, 126 insertions(+), 62 deletions(-) diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst index 54622b5329..fc935457d2 100644 --- a/doc/guides/nics/mlx5.rst +++ b/doc/guides/nics/mlx5.rst @@ -102,6 +102,7 @@ Features - Matching on Geneve TLV option header with raw encap/decap action. - RSS support in sample action. - E-Switch mirroring and jump. +- E-Switch mirroring and modify. Limitations ----------- diff --git a/doc/guides/rel_notes/release_21_02.rst b/doc/guides/rel_notes/release_21_02.rst index 79fe82f488..2a1f43b7b5 100644 --- a/doc/guides/rel_notes/release_21_02.rst +++ b/doc/guides/rel_notes/release_21_02.rst @@ -114,6 +114,8 @@ New Features * Added GTP PDU session container matching and raw encap/decap. * Added support for RSS action in the sample sub-actions list. * Added support for E-Switch mirroring and jump action in the same flow. + * Added support to handle modify action in correct order regarding the + mirroring action on E-Switch. * **Updated Wangxun txgbe driver.** diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 7e52246cbb..5d180fcf12 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -4640,6 +4640,8 @@ flow_mreg_tx_copy_prep(struct rte_eth_dev *dev, * Pointer to the position of the matched action if exists, otherwise is -1. * @param[out] qrss_action_pos * Pointer to the position of the Queue/RSS action if exists, otherwise is -1. + * @param[out] modify_after_mirror + * Pointer to the flag of modify action after FDB mirroring. * * @return * > 0 the total number of actions. @@ -4649,13 +4651,15 @@ static int flow_check_match_action(const struct rte_flow_action actions[], const struct rte_flow_attr *attr, enum rte_flow_action_type action, - int *match_action_pos, int *qrss_action_pos) + int *match_action_pos, int *qrss_action_pos, + int *modify_after_mirror) { const struct rte_flow_action_sample *sample; int actions_n = 0; uint32_t ratio = 0; int sub_type = 0; int flag = 0; + int fdb_mirror = 0; *match_action_pos = -1; *qrss_action_pos = -1; @@ -4664,25 +4668,53 @@ flow_check_match_action(const struct rte_flow_action actions[], flag = 1; *match_action_pos = actions_n; } - if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE || - actions->type == RTE_FLOW_ACTION_TYPE_RSS) + switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_QUEUE: + case RTE_FLOW_ACTION_TYPE_RSS: *qrss_action_pos = actions_n; - if (actions->type == RTE_FLOW_ACTION_TYPE_SAMPLE) { + break; + case RTE_FLOW_ACTION_TYPE_SAMPLE: sample = actions->conf; ratio = sample->ratio; sub_type = ((const struct rte_flow_action *) (sample->actions))->type; + if (ratio == 1 && attr->transfer) + fdb_mirror = 1; + break; + case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC: + case RTE_FLOW_ACTION_TYPE_SET_MAC_DST: + case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC: + case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST: + case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC: + case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST: + case RTE_FLOW_ACTION_TYPE_SET_TP_SRC: + case RTE_FLOW_ACTION_TYPE_SET_TP_DST: + case RTE_FLOW_ACTION_TYPE_DEC_TTL: + case RTE_FLOW_ACTION_TYPE_SET_TTL: + case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ: + case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ: + case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK: + case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK: + case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP: + case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP: + case RTE_FLOW_ACTION_TYPE_FLAG: + case RTE_FLOW_ACTION_TYPE_MARK: + case RTE_FLOW_ACTION_TYPE_SET_META: + case RTE_FLOW_ACTION_TYPE_SET_TAG: + if (fdb_mirror) + *modify_after_mirror = 1; + break; + default: + break; } actions_n++; } - if (flag && action == RTE_FLOW_ACTION_TYPE_SAMPLE && attr->transfer) { - if (ratio == 1) { - /* FDB mirroring uses the destination array to implement - * instead of FLOW_SAMPLER object. - */ - if (sub_type != RTE_FLOW_ACTION_TYPE_END) - flag = 0; - } + if (flag && fdb_mirror && !*modify_after_mirror) { + /* FDB mirroring uses the destination array to implement + * instead of FLOW_SAMPLER object. + */ + if (sub_type != RTE_FLOW_ACTION_TYPE_END) + flag = 0; } /* Count RTE_FLOW_ACTION_TYPE_END. */ return flag ? actions_n + 1 : 0; @@ -4717,6 +4749,8 @@ flow_check_match_action(const struct rte_flow_action actions[], * The sample action position. * @param[in] qrss_action_pos * The Queue/RSS action position. + * @param[in] jump_table + * Add extra jump action flag. * @param[out] error * Perform verbose error reporting if not NULL. * @@ -4734,14 +4768,17 @@ flow_sample_split_prep(struct rte_eth_dev *dev, int actions_n, int sample_action_pos, int qrss_action_pos, + int jump_table, struct rte_flow_error *error) { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_rte_flow_action_set_tag *set_tag; struct mlx5_rte_flow_item_tag *tag_spec; struct mlx5_rte_flow_item_tag *tag_mask; + struct rte_flow_action_jump *jump_action; uint32_t tag_id = 0; int index; + int append_index = 0; int ret; if (sample_action_pos < 0) @@ -4749,13 +4786,37 @@ flow_sample_split_prep(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "invalid position of sample " "action in list"); + /* Prepare the actions for prefix and suffix flow. */ + if (qrss_action_pos >= 0 && qrss_action_pos < sample_action_pos) { + index = qrss_action_pos; + /* Put the preceding the Queue/RSS action into prefix flow. */ + if (index != 0) + memcpy(actions_pre, actions, + sizeof(struct rte_flow_action) * index); + /* Put others preceding the sample action into prefix flow. */ + if (sample_action_pos > index + 1) + memcpy(actions_pre + index, actions + index + 1, + sizeof(struct rte_flow_action) * + (sample_action_pos - index - 1)); + index = sample_action_pos - 1; + /* Put Queue/RSS action into Suffix flow. */ + memcpy(actions_sfx, actions + qrss_action_pos, + sizeof(struct rte_flow_action)); + actions_sfx++; + } else { + index = sample_action_pos; + if (index != 0) + memcpy(actions_pre, actions, + sizeof(struct rte_flow_action) * index); + } /* For CX5, add an extra tag action for NIC-RX and E-Switch ingress. * For CX6DX and above, metadata registers Cx preserve their value, - * add an extra tag action for NIC-RX and E-Switch ingress and egress. + * add an extra tag action for NIC-RX and E-Switch Domain. */ if (add_tag) { /* Prepare the prefix tag action. */ - set_tag = (void *)(actions_pre + actions_n + 1); + append_index++; + set_tag = (void *)(actions_pre + actions_n + append_index); ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 0, error); if (ret < 0) return ret; @@ -4780,31 +4841,7 @@ flow_sample_split_prep(struct rte_eth_dev *dev, .type = (enum rte_flow_item_type) RTE_FLOW_ITEM_TYPE_END, }; - } - /* Prepare the actions for prefix and suffix flow. */ - if (qrss_action_pos >= 0 && qrss_action_pos < sample_action_pos) { - index = qrss_action_pos; - /* Put the preceding the Queue/RSS action into prefix flow. */ - if (index != 0) - memcpy(actions_pre, actions, - sizeof(struct rte_flow_action) * index); - /* Put others preceding the sample action into prefix flow. */ - if (sample_action_pos > index + 1) - memcpy(actions_pre + index, actions + index + 1, - sizeof(struct rte_flow_action) * - (sample_action_pos - index - 1)); - index = sample_action_pos - 1; - /* Put Queue/RSS action into Suffix flow. */ - memcpy(actions_sfx, actions + qrss_action_pos, - sizeof(struct rte_flow_action)); - actions_sfx++; - } else { - index = sample_action_pos; - if (index != 0) - memcpy(actions_pre, actions, - sizeof(struct rte_flow_action) * index); - } - if (add_tag) { + /* Prepare the tag action in prefix subflow. */ actions_pre[index++] = (struct rte_flow_action){ .type = (enum rte_flow_action_type) @@ -4815,6 +4852,22 @@ flow_sample_split_prep(struct rte_eth_dev *dev, memcpy(actions_pre + index, actions + sample_action_pos, sizeof(struct rte_flow_action)); index += 1; + /* For the modify action after the sample action in E-Switch mirroring, + * Add the extra jump action in prefix subflow and jump into the next + * table, then do the modify action in the new table. + */ + if (jump_table) { + /* Prepare the prefix jump action. */ + append_index++; + jump_action = (void *)(actions_pre + actions_n + append_index); + jump_action->group = jump_table; + actions_pre[index++] = + (struct rte_flow_action){ + .type = (enum rte_flow_action_type) + RTE_FLOW_ACTION_TYPE_JUMP, + .conf = jump_action, + }; + } actions_pre[index] = (struct rte_flow_action){ .type = (enum rte_flow_action_type) RTE_FLOW_ACTION_TYPE_END, @@ -5218,12 +5271,16 @@ flow_create_split_sample(struct rte_eth_dev *dev, int sample_action_pos; int qrss_action_pos; int add_tag = 0; + int modify_after_mirror = 0; + uint16_t jump_table = 0; + const uint32_t next_ft_step = 1; int ret = 0; if (priv->sampler_en) actions_n = flow_check_match_action(actions, attr, RTE_FLOW_ACTION_TYPE_SAMPLE, - &sample_action_pos, &qrss_action_pos); + &sample_action_pos, &qrss_action_pos, + &modify_after_mirror); if (actions_n) { /* The prefix actions must includes sample, tag, end. */ act_size = sizeof(struct rte_flow_action) * (actions_n * 2 + 1) @@ -5247,16 +5304,23 @@ flow_create_split_sample(struct rte_eth_dev *dev, if (add_tag) sfx_items = (struct rte_flow_item *)((char *)sfx_actions + act_size); + if (modify_after_mirror) + jump_table = attr->group * MLX5_FLOW_TABLE_FACTOR + + next_ft_step; pre_actions = sfx_actions + actions_n; tag_id = flow_sample_split_prep(dev, add_tag, sfx_items, actions, sfx_actions, pre_actions, actions_n, sample_action_pos, - qrss_action_pos, error); + qrss_action_pos, jump_table, + error); if (tag_id < 0 || (add_tag && !tag_id)) { ret = -rte_errno; goto exit; } + if (modify_after_mirror) + flow_split_info->skip_scale = + 1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT; /* Add the prefix subflow. */ ret = flow_create_split_inner(dev, flow, &dev_flow, attr, items, pre_actions, @@ -5267,21 +5331,28 @@ flow_create_split_sample(struct rte_eth_dev *dev, } dev_flow->handle->split_flow_id = tag_id; #ifdef HAVE_IBV_FLOW_DV_SUPPORT - /* Set the sfx group attr. */ - sample_res = (struct mlx5_flow_dv_sample_resource *) - dev_flow->dv.sample_res; - sfx_tbl = (struct mlx5_flow_tbl_resource *) - sample_res->normal_path_tbl; - sfx_tbl_data = container_of(sfx_tbl, - struct mlx5_flow_tbl_data_entry, tbl); - sfx_attr.group = sfx_attr.transfer ? - (sfx_tbl_data->table_id - 1) : - sfx_tbl_data->table_id; + if (!modify_after_mirror) { + /* Set the sfx group attr. */ + sample_res = (struct mlx5_flow_dv_sample_resource *) + dev_flow->dv.sample_res; + sfx_tbl = (struct mlx5_flow_tbl_resource *) + sample_res->normal_path_tbl; + sfx_tbl_data = container_of(sfx_tbl, + struct mlx5_flow_tbl_data_entry, + tbl); + sfx_attr.group = sfx_attr.transfer ? + (sfx_tbl_data->table_id - 1) : + sfx_tbl_data->table_id; + } else { + MLX5_ASSERT(attr->transfer); + sfx_attr.group = jump_table; + } flow_split_info->prefix_layers = flow_get_prefix_layer_flags(dev_flow); flow_split_info->prefix_mark = dev_flow->handle->mark; /* Suffix group level already be scaled with factor, set - * skip_scale to 1 to avoid scale again in translation. + * MLX5_SCALE_FLOW_GROUP_BIT of skip_scale to 1 to avoid scale + * again in translation. */ flow_split_info->skip_scale = 1 << MLX5_SCALE_FLOW_GROUP_BIT; #endif diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c index 74bc1f107f..b44e9d386e 100644 --- a/drivers/net/mlx5/mlx5_flow_dv.c +++ b/drivers/net/mlx5/mlx5_flow_dv.c @@ -3666,8 +3666,6 @@ flow_dv_create_action_push_vlan(struct rte_eth_dev *dev, (dev, &res, dev_flow, error); } -static int fdb_mirror_limit; - /** * Validate the modify-header actions. * @@ -3695,12 +3693,6 @@ flow_dv_validate_action_modify_hdr(const uint64_t action_flags, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "can't have encap action before" " modify action"); - if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror_limit) - return rte_flow_error_set(error, EINVAL, - RTE_FLOW_ERROR_TYPE_ACTION, NULL, - "can't support sample action before" - " modify action for E-Switch" - " mirroring"); return 0; } @@ -4437,7 +4429,6 @@ flow_dv_validate_action_sample(uint64_t action_flags, int actions_n = 0; int ret; - fdb_mirror_limit = 0; if (!sample) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, action, @@ -4577,7 +4568,6 @@ flow_dv_validate_action_sample(uint64_t action_flags, "E-Switch doesn't support " "any optional action " "for sampling"); - fdb_mirror_limit = 1; if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE) return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, -- 2.20.1