net/mlx5: support E-Switch mirroring and jump in one flow
authorJiawei Wang <jiaweiw@nvidia.com>
Tue, 12 Jan 2021 10:29:16 +0000 (12:29 +0200)
committerFerruh Yigit <ferruh.yigit@intel.com>
Fri, 29 Jan 2021 17:16:07 +0000 (18:16 +0100)
mlx5 E-Switch mirroring is implemented as multiple destination array in
one steering table. The array currently supports only port ID as
destination actions.

This patch adds the jump action support to the array as one of
destination.
The packets can be mirrored to the port and jump to the next table in
the same destination array allowing to continue handling in the new
table.

For example:
    set sample_actions 0 port_id id 1 / end
    flow create 0 ingress transfer pattern eth / end actions
    sample ratio 1 index 0 / jump group 1 / end
    flow create 1 ingress transfer group 1 pattern eth / end actions
    set_mac_dst mac_addr 00:aa:bb:cc:dd:ee / port_id id 2 / end

The flow results all the matched ingress packets are mirrored
to port id 1 and go to group 1. In the group 1, packets are modified
with the destination mac and sent to port id 2.

Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
Acked-by: Viacheslav Ovsiienko <viacheslavo@nvidia.com>
doc/guides/nics/mlx5.rst
doc/guides/rel_notes/release_21_02.rst
drivers/net/mlx5/mlx5_flow.c
drivers/net/mlx5/mlx5_flow.h
drivers/net/mlx5/mlx5_flow_dv.c

index f5034dc..54622b5 100644 (file)
@@ -101,6 +101,7 @@ Features
 - Matching on GTP extension header with raw encap/decap action.
 - Matching on Geneve TLV option header with raw encap/decap action.
 - RSS support in sample action.
+- E-Switch mirroring and jump.
 
 Limitations
 -----------
index 31051ed..79fe82f 100644 (file)
@@ -113,6 +113,7 @@ New Features
   * Introduced basic support on Windows.
   * 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.
 
 * **Updated Wangxun txgbe driver.**
 
index 6716a20..d880a9c 100644 (file)
@@ -4653,7 +4653,6 @@ flow_check_match_action(const struct rte_flow_action actions[],
 {
        const struct rte_flow_action_sample *sample;
        int actions_n = 0;
-       int jump_flag = 0;
        uint32_t ratio = 0;
        int sub_type = 0;
        int flag = 0;
@@ -4668,8 +4667,6 @@ flow_check_match_action(const struct rte_flow_action actions[],
                if (actions->type == RTE_FLOW_ACTION_TYPE_QUEUE ||
                    actions->type == RTE_FLOW_ACTION_TYPE_RSS)
                        *qrss_action_pos = actions_n;
-               if (actions->type == RTE_FLOW_ACTION_TYPE_JUMP)
-                       jump_flag = 1;
                if (actions->type == RTE_FLOW_ACTION_TYPE_SAMPLE) {
                        sample = actions->conf;
                        ratio = sample->ratio;
@@ -4680,10 +4677,10 @@ flow_check_match_action(const struct rte_flow_action actions[],
        }
        if (flag && action == RTE_FLOW_ACTION_TYPE_SAMPLE && attr->transfer) {
                if (ratio == 1) {
-                       /* JUMP Action not support for Mirroring;
-                        * Mirroring support multi-destination;
+                       /* FDB mirroring uses the destination array to implement
+                        * instead of FLOW_SAMPLER object.
                         */
-                       if (!jump_flag && sub_type != RTE_FLOW_ACTION_TYPE_END)
+                       if (sub_type != RTE_FLOW_ACTION_TYPE_END)
                                flag = 0;
                }
        }
@@ -4704,8 +4701,8 @@ flow_check_match_action(const struct rte_flow_action actions[],
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param[in] fdb_tx
- *   FDB egress flow flag.
+ * @param[in] add_tag
+ *   Add extra tag action flag.
  * @param[out] sfx_items
  *   Suffix flow match items (list terminated by the END pattern item).
  * @param[in] actions
@@ -4729,7 +4726,7 @@ flow_check_match_action(const struct rte_flow_action actions[],
  */
 static int
 flow_sample_split_prep(struct rte_eth_dev *dev,
-                      uint32_t fdb_tx,
+                      int add_tag,
                       struct rte_flow_item sfx_items[],
                       const struct rte_flow_action actions[],
                       struct rte_flow_action actions_sfx[],
@@ -4752,7 +4749,11 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
                                          RTE_FLOW_ERROR_TYPE_ACTION,
                                          NULL, "invalid position of sample "
                                          "action in list");
-       if (!fdb_tx) {
+       /* 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.
+        */
+       if (add_tag) {
                /* Prepare the prefix tag action. */
                set_tag = (void *)(actions_pre + actions_n + 1);
                ret = mlx5_flow_get_reg_id(dev, MLX5_APP_TAG, 0, error);
@@ -4803,8 +4804,7 @@ flow_sample_split_prep(struct rte_eth_dev *dev,
                        memcpy(actions_pre, actions,
                               sizeof(struct rte_flow_action) * index);
        }
-       /* Add the extra tag action for NIC-RX and E-Switch ingress. */
-       if (!fdb_tx) {
+       if (add_tag) {
                actions_pre[index++] =
                        (struct rte_flow_action){
                        .type = (enum rte_flow_action_type)
@@ -5217,6 +5217,7 @@ flow_create_split_sample(struct rte_eth_dev *dev,
        int actions_n = 0;
        int sample_action_pos;
        int qrss_action_pos;
+       int add_tag = 0;
        int ret = 0;
 
        if (priv->sampler_en)
@@ -5238,16 +5239,21 @@ flow_create_split_sample(struct rte_eth_dev *dev,
                                                  "sample flow");
                /* The representor_id is -1 for uplink. */
                fdb_tx = (attr->transfer && priv->representor_id != -1);
-               if (!fdb_tx)
+               /*
+                * When reg_c_preserve is set, metadata registers Cx preserve
+                * their value even through packet duplication.
+                */
+               add_tag = (!fdb_tx || priv->config.hca_attr.reg_c_preserve);
+               if (add_tag)
                        sfx_items = (struct rte_flow_item *)((char *)sfx_actions
                                        + act_size);
                pre_actions = sfx_actions + actions_n;
-               tag_id = flow_sample_split_prep(dev, fdb_tx, sfx_items,
+               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);
-               if (tag_id < 0 || (!fdb_tx && !tag_id)) {
+               if (tag_id < 0 || (add_tag && !tag_id)) {
                        ret = -rte_errno;
                        goto exit;
                }
index a9e33b8..8255627 100644 (file)
@@ -564,6 +564,7 @@ struct mlx5_flow_sub_actions_list {
        void *dr_cnt_action;
        void *dr_port_id_action;
        void *dr_encap_action;
+       void *dr_jump_action;
 };
 
 /* Sample sub-actions resource list. */
@@ -573,6 +574,7 @@ struct mlx5_flow_sub_actions_idx {
        uint32_t cnt;
        uint32_t rix_port_id_action; /**< Index to port ID action resource. */
        uint32_t rix_encap_decap; /**< Index to encap/decap resource. */
+       uint32_t rix_jump; /**< Index to the jump action resource. */
 };
 
 /* Sample action resource structure. */
index 707d674..f1ce648 100644 (file)
@@ -76,7 +76,7 @@ flow_dv_tbl_resource_release(struct mlx5_dev_ctx_shared *sh,
 
 static int
 flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
-                                     uint32_t encap_decap_idx);
+                                    uint32_t encap_decap_idx);
 
 static int
 flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
@@ -84,6 +84,10 @@ flow_dv_port_id_action_resource_release(struct rte_eth_dev *dev,
 static void
 flow_dv_shared_rss_action_release(struct rte_eth_dev *dev, uint32_t srss);
 
+static int
+flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
+                                 uint32_t rix_jump);
+
 /**
  * Initialize flow attributes structure according to flow items' types.
  *
@@ -3662,7 +3666,7 @@ flow_dv_create_action_push_vlan(struct rte_eth_dev *dev,
                                            (dev, &res, dev_flow, error);
 }
 
-static int fdb_mirror;
+static int fdb_mirror_limit;
 
 /**
  * Validate the modify-header actions.
@@ -3691,7 +3695,7 @@ 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)
+       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"
@@ -4027,12 +4031,6 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev,
                return rte_flow_error_set(error, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "jump with meter not support");
-       if ((action_flags & MLX5_FLOW_ACTION_SAMPLE) && fdb_mirror)
-               return rte_flow_error_set(error, EINVAL,
-                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
-                                         "E-Switch mirroring can't support"
-                                         " Sample action and jump action in"
-                                         " same flow now");
        if (!action->conf)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION_CONF,
@@ -4438,8 +4436,8 @@ flow_dv_validate_action_sample(uint64_t action_flags,
        uint16_t queue_index = 0xFFFF;
        int actions_n = 0;
        int ret;
-       fdb_mirror = 0;
 
+       fdb_mirror_limit = 0;
        if (!sample)
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, action,
@@ -4579,7 +4577,7 @@ flow_dv_validate_action_sample(uint64_t action_flags,
                                                  "E-Switch doesn't support "
                                                  "any optional action "
                                                  "for sampling");
-               fdb_mirror = 1;
+               fdb_mirror_limit = 1;
                if (sub_action_flags & MLX5_FLOW_ACTION_QUEUE)
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ACTION,
@@ -9072,6 +9070,10 @@ flow_dv_sample_sub_actions_release(struct rte_eth_dev *dev,
                flow_dv_counter_free(dev, act_res->cnt);
                act_res->cnt = 0;
        }
+       if (act_res->rix_jump) {
+               flow_dv_jump_tbl_resource_release(dev, act_res->rix_jump);
+               act_res->rix_jump = 0;
+       }
 }
 
 int
@@ -9284,6 +9286,7 @@ flow_dv_dest_array_create_cb(struct mlx5_cache_list *list __rte_unused,
        struct mlx5dv_dr_domain *domain;
        uint32_t idx = 0, res_idx = 0;
        struct rte_flow_error *error = ctx->error;
+       uint64_t action_flags;
        int ret;
 
        /* Register new destination array resource. */
@@ -9317,19 +9320,31 @@ flow_dv_dest_array_create_cb(struct mlx5_cache_list *list __rte_unused,
                }
                dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST;
                sample_act = &resource->sample_act[idx];
-               if (sample_act->action_flags == MLX5_FLOW_ACTION_QUEUE) {
+               action_flags = sample_act->action_flags;
+               switch (action_flags) {
+               case MLX5_FLOW_ACTION_QUEUE:
                        dest_attr[idx]->dest = sample_act->dr_queue_action;
-               } else if (sample_act->action_flags ==
-                         (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP)) {
+                       break;
+               case (MLX5_FLOW_ACTION_PORT_ID | MLX5_FLOW_ACTION_ENCAP):
                        dest_attr[idx]->type = MLX5DV_DR_ACTION_DEST_REFORMAT;
                        dest_attr[idx]->dest_reformat = &dest_reformat[idx];
                        dest_attr[idx]->dest_reformat->reformat =
                                        sample_act->dr_encap_action;
                        dest_attr[idx]->dest_reformat->dest =
                                        sample_act->dr_port_id_action;
-               } else if (sample_act->action_flags ==
-                          MLX5_FLOW_ACTION_PORT_ID) {
+                       break;
+               case MLX5_FLOW_ACTION_PORT_ID:
                        dest_attr[idx]->dest = sample_act->dr_port_id_action;
+                       break;
+               case MLX5_FLOW_ACTION_JUMP:
+                       dest_attr[idx]->dest = sample_act->dr_jump_action;
+                       break;
+               default:
+                       rte_flow_error_set(error, EINVAL,
+                                          RTE_FLOW_ERROR_TYPE_ACTION,
+                                          NULL,
+                                          "unsupported actions type");
+                       goto error;
                }
        }
        /* create a dest array actioin */
@@ -9366,6 +9381,10 @@ error:
                        !flow_dv_port_id_action_resource_release(dev,
                                act_res->rix_port_id_action))
                        act_res->rix_port_id_action = 0;
+               if (act_res->rix_jump &&
+                       !flow_dv_jump_tbl_resource_release(dev,
+                               act_res->rix_jump))
+                       act_res->rix_jump = 0;
                if (dest_attr[idx])
                        mlx5_free(dest_attr[idx]);
        }
@@ -9739,6 +9758,14 @@ flow_dv_create_action_sample(struct rte_eth_dev *dev,
                        sample_act->dr_port_id_action =
                                dev_flow->dv.port_id_action->action;
                }
+               if (sample_act->action_flags & MLX5_FLOW_ACTION_JUMP) {
+                       normal_idx++;
+                       mdest_res->sample_idx[dest_index].rix_jump =
+                               dev_flow->handle->rix_jump;
+                       sample_act->dr_jump_action =
+                               dev_flow->dv.jump->action;
+                       dev_flow->handle->rix_jump = 0;
+               }
                sample_act->actions_num = normal_idx;
                /* update sample action resource into first index of array */
                mdest_res->ft_type = res->ft_type;
@@ -10498,6 +10525,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
                                        dev_flow->dv.jump->action;
                        action_flags |= MLX5_FLOW_ACTION_JUMP;
                        dev_flow->handle->fate_action = MLX5_FLOW_FATE_JUMP;
+                       sample_act->action_flags |= MLX5_FLOW_ACTION_JUMP;
+                       num_of_dest++;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
                case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
@@ -10996,7 +11025,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
         * So need remove the original these actions in the flow and only
         * use the sample action instead of.
         */
-       if (num_of_dest > 1 && sample_act->dr_port_id_action) {
+       if (num_of_dest > 1 &&
+           (sample_act->dr_port_id_action || sample_act->dr_jump_action)) {
                int i;
                void *temp_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS] = {0};
 
@@ -11006,6 +11036,9 @@ flow_dv_translate(struct rte_eth_dev *dev,
                                dev_flow->dv.actions[i]) ||
                                (sample_act->dr_port_id_action &&
                                sample_act->dr_port_id_action ==
+                               dev_flow->dv.actions[i]) ||
+                               (sample_act->dr_jump_action &&
+                               sample_act->dr_jump_action ==
                                dev_flow->dv.actions[i]))
                                continue;
                        temp_actions[tmp_actions_n++] = dev_flow->dv.actions[i];
@@ -11280,8 +11313,8 @@ flow_dv_matcher_remove_cb(struct mlx5_cache_list *list __rte_unused,
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param handle
- *   Pointer to mlx5_flow_handle.
+ * @param port_id
+ *   Index to port ID action resource.
  *
  * @return
  *   1 while a reference on it exists, 0 when freed.
@@ -11353,21 +11386,21 @@ flow_dv_encap_decap_resource_release(struct rte_eth_dev *dev,
  *
  * @param dev
  *   Pointer to Ethernet device.
- * @param handle
- *   Pointer to mlx5_flow_handle.
+ * @param rix_jump
+ *   Index to the jump action resource.
  *
  * @return
  *   1 while a reference on it exists, 0 when freed.
  */
 static int
 flow_dv_jump_tbl_resource_release(struct rte_eth_dev *dev,
-                                 struct mlx5_flow_handle *handle)
+                                 uint32_t rix_jump)
 {
        struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_flow_tbl_data_entry *tbl_data;
 
        tbl_data = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_JUMP],
-                            handle->rix_jump);
+                                 rix_jump);
        if (!tbl_data)
                return 0;
        return flow_dv_tbl_resource_release(MLX5_SH(dev), &tbl_data->tbl);
@@ -11521,7 +11554,7 @@ flow_dv_fate_resource_release(struct rte_eth_dev *dev,
                mlx5_hrxq_release(dev, handle->rix_hrxq);
                break;
        case MLX5_FLOW_FATE_JUMP:
-               flow_dv_jump_tbl_resource_release(dev, handle);
+               flow_dv_jump_tbl_resource_release(dev, handle->rix_jump);
                break;
        case MLX5_FLOW_FATE_PORT_ID:
                flow_dv_port_id_action_resource_release(dev,