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 <jiaw...@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viachesl...@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.c    | 175 ++++++++++++++++++++++++++++------------
 drivers/net/mlx5/mlx5_flow_dv.c |  10 ---
 2 files changed, 123 insertions(+), 62 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 055474b..df79318 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4490,6 +4490,8 @@ struct mlx5_hlist_entry *
  *   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.
@@ -4499,13 +4501,15 @@ struct mlx5_hlist_entry *
 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;
@@ -4514,25 +4518,53 @@ struct mlx5_hlist_entry *
                        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;
@@ -4567,6 +4599,8 @@ struct mlx5_hlist_entry *
  *   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.
  *
@@ -4584,14 +4618,17 @@ struct mlx5_hlist_entry *
                       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)
@@ -4599,13 +4636,37 @@ struct mlx5_hlist_entry *
                                          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;
@@ -4630,31 +4691,7 @@ struct mlx5_hlist_entry *
                        .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)
@@ -4665,6 +4702,22 @@ struct mlx5_hlist_entry *
        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,
@@ -5068,12 +5121,16 @@ struct mlx5_hlist_entry *
        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)
@@ -5097,16 +5154,23 @@ struct mlx5_hlist_entry *
                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,
@@ -5117,21 +5181,28 @@ struct mlx5_hlist_entry *
                }
                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 63569ad..4b191fd 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -3600,8 +3600,6 @@ struct mlx5_cache_entry *
                                            (dev, &res, dev_flow, error);
 }
 
-static int fdb_mirror_limit;
-
 /**
  * Validate the modify-header actions.
  *
@@ -3629,12 +3627,6 @@ struct mlx5_cache_entry *
                                          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;
 }
 
@@ -4365,7 +4357,6 @@ struct mlx5_hlist_entry *
        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,
@@ -4482,7 +4473,6 @@ struct mlx5_hlist_entry *
                                                  "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,
-- 
1.8.3.1

Reply via email to