net/mlx5: support ASO meter action
authorLi Zhang <lizh@nvidia.com>
Tue, 20 Apr 2021 10:55:19 +0000 (13:55 +0300)
committerRaslan Darawsheh <rasland@nvidia.com>
Wed, 21 Apr 2021 06:28:08 +0000 (08:28 +0200)
When ASO action is available, use it as the meter action

Signed-off-by: Shun Hao <shunh@nvidia.com>
Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
doc/guides/rel_notes/release_21_05.rst
drivers/net/mlx5/linux/mlx5_os.c
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_flow.c
drivers/net/mlx5/mlx5_flow_dv.c
drivers/net/mlx5/mlx5_flow_meter.c

index b949e58..b136f1f 100644 (file)
@@ -156,6 +156,7 @@ New Features
 
   * Added support for VXLAN and NVGRE encap as sample actions.
   * Support push VLAN on ingress traffic and pop VLAN on egress traffic in E-Switch mode.
+  * Added support for ASO (Advanced Steering Operation) meter.
 
 * **Updated NXP DPAA driver.**
 
index 336cdbe..41622c1 100644 (file)
@@ -1255,7 +1255,9 @@ err_secondary:
                                "required for coalescing is %d bytes",
                                config->hca_attr.lro_min_mss_size);
                }
-#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+#if defined(HAVE_MLX5DV_DR) && \
+       (defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER) || \
+        defined(HAVE_MLX5_DR_CREATE_ACTION_ASO))
                if (config->hca_attr.qos.sup &&
                    config->hca_attr.qos.flow_meter_old &&
                    config->dv_flow_en) {
index 00055e3..e5ffb8f 100644 (file)
@@ -609,11 +609,23 @@ mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
        struct mlx5_aso_mtr_pool *mtr_pool;
        struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng;
        uint32_t idx;
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
+       struct mlx5_aso_mtr *aso_mtr;
+       int i;
+#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
 
        mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
        idx = mtrmng->n_valid;
        while (idx--) {
                mtr_pool = mtrmng->pools[idx];
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
+               for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
+                       aso_mtr = &mtr_pool->mtrs[i];
+                       if (aso_mtr->fm.meter_action)
+                               claim_zero(mlx5_glue->destroy_flow_action
+                                               (aso_mtr->fm.meter_action));
+               }
+#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
                claim_zero(mlx5_devx_cmd_destroy
                                                (mtr_pool->devx_obj));
                mtrmng->n_valid--;
index adf24f0..a045cf4 100644 (file)
@@ -634,8 +634,6 @@ struct mlx5_meter_domains_infos {
        /**< Counters for green rule. */
        void *drop_count;
        /**< Counters for green rule. */
-       void *meter_action;
-       /**< Flow meter action. */
 };
 
 /* Meter parameter structure. */
@@ -698,6 +696,8 @@ struct mlx5_flow_meter_info {
        /**< Use count. */
        struct mlx5_indexed_pool *flow_ipool;
        /**< Index pool for flow id. */
+       void *meter_action;
+       /**< Flow meter action. */
 };
 
 /* RFC2697 parameter structure. */
@@ -1487,7 +1487,8 @@ int mlx5_flow_meter_attach(struct mlx5_priv *priv,
                           struct mlx5_flow_meter_info *fm,
                           const struct rte_flow_attr *attr,
                           struct rte_flow_error *error);
-void mlx5_flow_meter_detach(struct mlx5_flow_meter_info *fm);
+void mlx5_flow_meter_detach(struct mlx5_priv *priv,
+                           struct mlx5_flow_meter_info *fm);
 
 /* mlx5_os.c */
 struct rte_pci_driver;
index 7a6d6f8..cf93ab0 100644 (file)
@@ -4363,6 +4363,8 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *   Parent flow structure pointer.
  * @param[in] fm
  *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Flow rule attributes.
  * @param[in] items
  *   Pattern specification (list terminated by the END pattern item).
  * @param[out] sfx_items
@@ -4383,6 +4385,7 @@ static uint32_t
 flow_meter_split_prep(struct rte_eth_dev *dev,
                      struct rte_flow *flow,
                      struct mlx5_flow_meter_info *fm,
+                     const struct rte_flow_attr *attr,
                      const struct rte_flow_item items[],
                      struct rte_flow_item sfx_items[],
                      const struct rte_flow_action actions[],
@@ -4400,6 +4403,12 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
        struct mlx5_rte_flow_item_tag *tag_item_mask;
        uint32_t tag_id = 0;
        bool copy_vlan = false;
+       struct rte_flow_action *hw_mtr_action;
+       struct rte_flow_action_jump *jump_data;
+       struct rte_flow_action *action_pre_head = NULL;
+       bool mtr_first = priv->sh->meter_aso_en &&
+                       (attr->egress ||
+                       (attr->transfer && priv->representor_id != UINT16_MAX));
        uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
        uint8_t mtr_reg_bits = priv->mtr_reg_share ?
                                MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
@@ -4408,29 +4417,39 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
        uint8_t flow_id_bits = 0;
        int shift;
 
+       /* For ASO meter, meter must be before tag in TX direction. */
+       if (mtr_first) {
+               action_pre_head = actions_pre++;
+               /* Leave space for tag action. */
+               tag_action = actions_pre++;
+       }
        /* Prepare the actions for prefix and suffix flow. */
        for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
-               struct rte_flow_action **action_cur = NULL;
+               struct rte_flow_action *action_cur = NULL;
 
                switch (actions->type) {
                case RTE_FLOW_ACTION_TYPE_METER:
-                       /* Add the extra tag action first. */
-                       tag_action = actions_pre++;
-                       action_cur = &actions_pre;
+                       if (mtr_first) {
+                               action_cur = action_pre_head;
+                       } else {
+                               /* Leave space for tag action. */
+                               tag_action = actions_pre++;
+                               action_cur = actions_pre++;
+                       }
                        break;
                case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
                case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
-                       action_cur = &actions_pre;
+                       action_cur = actions_pre++;
                        break;
                case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
                        raw_encap = actions->conf;
                        if (raw_encap->size < MLX5_ENCAPSULATION_DECISION_SIZE)
-                               action_cur = &actions_pre;
+                               action_cur = actions_pre++;
                        break;
                case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
                        raw_decap = actions->conf;
                        if (raw_decap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
-                               action_cur = &actions_pre;
+                               action_cur = actions_pre++;
                        break;
                case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
                case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
@@ -4440,14 +4459,32 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
                        break;
                }
                if (!action_cur)
-                       action_cur = &actions_sfx;
-               memcpy(*action_cur, actions, sizeof(struct rte_flow_action));
-               (*action_cur)++;
+                       action_cur = actions_sfx++;
+               memcpy(action_cur, actions, sizeof(struct rte_flow_action));
        }
        /* Add end action to the actions. */
        actions_sfx->type = RTE_FLOW_ACTION_TYPE_END;
-       actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
-       actions_pre++;
+       if (priv->sh->meter_aso_en) {
+               /**
+                * For ASO meter, need to add an extra jump action explicitly,
+                * to jump from meter to policer table.
+                */
+               hw_mtr_action = actions_pre;
+               hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
+               actions_pre++;
+               actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+               actions_pre++;
+               jump_data = (struct rte_flow_action_jump *)actions_pre;
+               jump_data->group = attr->transfer ?
+                               (MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+                                MLX5_FLOW_TABLE_LEVEL_METER;
+               hw_mtr_action->conf = jump_data;
+               actions_pre = (struct rte_flow_action *)(jump_data + 1);
+       } else {
+               actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+               actions_pre++;
+       }
+       /* Generate meter flow_id only if support multiple flows per meter. */
        mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
        if (!tag_id)
                return rte_flow_error_set(error, ENOMEM,
@@ -5272,10 +5309,11 @@ flow_create_split_meter(struct rte_eth_dev *dev,
                        flow->meter = mtr_idx;
                }
                wks->fm = fm;
-               /* The prefix actions: meter, decap, encap, tag, end. */
-               act_size = sizeof(struct rte_flow_action) * (actions_n + 5) +
-                          sizeof(struct mlx5_rte_flow_action_set_tag);
-               /* The suffix items: tag, vlan, port id, end. */
+               /* Prefix actions: meter, decap, encap, tag, jump, end. */
+               act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
+                          sizeof(struct mlx5_rte_flow_action_set_tag) +
+                          sizeof(struct rte_flow_action_jump);
+               /* Suffix items: tag, vlan, port id, end. */
 #define METER_SUFFIX_ITEM 4
                item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
                            sizeof(struct mlx5_rte_flow_item_tag) * 2;
@@ -5289,8 +5327,8 @@ flow_create_split_meter(struct rte_eth_dev *dev,
                sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
                             act_size);
                pre_actions = sfx_actions + actions_n;
-               mtr_tag_id = flow_meter_split_prep(dev, flow, fm, items,
-                                                  sfx_items, actions,
+               mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+                                                  items, sfx_items, actions,
                                                   sfx_actions, pre_actions,
                                                   error);
                if (!mtr_tag_id) {
index a621417..a649339 100644 (file)
@@ -4891,9 +4891,11 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "Meter not found");
-       if (fm->ref_cnt && (!(fm->transfer == attr->transfer ||
+       /* aso meter can always be shared by different domains */
+       if (fm->ref_cnt && !priv->sh->meter_aso_en &&
+           !(fm->transfer == attr->transfer ||
              (!fm->ingress && !attr->ingress && attr->egress) ||
-             (!fm->egress && !attr->egress && attr->ingress))))
+             (!fm->egress && !attr->egress && attr->ingress)))
                return rte_flow_error_set(error, EINVAL,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "Flow attributes are either invalid "
@@ -6096,6 +6098,25 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
                                        struct mlx5_aso_mtr_pool,
                                        mtrs[mtr_free->offset]);
        mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
+       if (!mtr_free->fm.meter_action) {
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
+               struct rte_flow_error error;
+               uint8_t reg_id;
+
+               reg_id = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &error);
+               mtr_free->fm.meter_action =
+                       mlx5_glue->dv_create_flow_action_aso
+                                               (priv->sh->rx_domain,
+                                                pool->devx_obj->obj,
+                                                mtr_free->offset,
+                                                (1 << MLX5_FLOW_COLOR_GREEN),
+                                                reg_id - REG_C_0);
+#endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
+               if (!mtr_free->fm.meter_action) {
+                       flow_dv_aso_mtr_release_to_pool(dev, mtr_idx);
+                       return 0;
+               }
+       }
        return mtr_idx;
 }
 
@@ -11595,7 +11616,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
                                        NULL, "Failed to get meter in flow.");
                        /* Set the meter action. */
                        dev_flow->dv.actions[actions_n++] =
-                               wks->fm->mfts->meter_action;
+                               wks->fm->meter_action;
                        action_flags |= MLX5_FLOW_ACTION_METER;
                        break;
                case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
@@ -12757,7 +12778,7 @@ flow_dv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
        if (flow->meter) {
                fm = flow_dv_meter_find_by_idx(priv, flow->meter);
                if (fm)
-                       mlx5_flow_meter_detach(fm);
+                       mlx5_flow_meter_detach(priv, fm);
                flow->meter = 0;
        }
        if (flow->age)
index fcefc13..714b382 100644 (file)
@@ -602,9 +602,9 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
                                ebs_mantissa, val);
                }
                /* Apply modifications to meter only if it was created. */
-               if (fm->mfts->meter_action) {
+               if (fm->meter_action) {
                        ret = mlx5_glue->dv_modify_flow_action_meter
-                                       (fm->mfts->meter_action, &mod_attr,
+                                       (fm->meter_action, &mod_attr,
                                        rte_cpu_to_be_64(modify_bits));
                        if (ret)
                                return ret;
@@ -620,6 +620,7 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
        (void)srtcm;
        (void)modify_bits;
        (void)active_state;
+       (void)is_enable;
        return -ENOTSUP;
 #endif
 }
@@ -1405,63 +1406,91 @@ mlx5_flow_meter_attach(struct mlx5_priv *priv,
 {
        int ret = 0;
 
-       rte_spinlock_lock(&fm->sl);
-       if (fm->mfts->meter_action) {
-               if (fm->shared &&
-                   attr->transfer == fm->transfer &&
-                   attr->ingress == fm->ingress &&
-                   attr->egress == fm->egress)
+       if (priv->sh->meter_aso_en) {
+               struct mlx5_aso_mtr *aso_mtr;
+
+               aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+               if (mlx5_aso_mtr_wait(priv->sh, aso_mtr)) {
+                       return rte_flow_error_set(error, ENOENT,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                       NULL,
+                                       "Timeout in meter configuration");
+               }
+               rte_spinlock_lock(&fm->sl);
+               if (fm->shared || !fm->ref_cnt) {
                        fm->ref_cnt++;
-               else
+               } else {
+                       rte_flow_error_set(error, EINVAL,
+                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                  "Meter cannot be shared");
                        ret = -1;
+               }
+               rte_spinlock_unlock(&fm->sl);
        } else {
-               fm->ingress = attr->ingress;
-               fm->egress = attr->egress;
-               fm->transfer = attr->transfer;
-                fm->ref_cnt = 1;
-               /* This also creates the meter object. */
-               fm->mfts->meter_action = mlx5_flow_meter_action_create(priv,
-                                                                      fm);
-               if (!fm->mfts->meter_action) {
-                       fm->ref_cnt = 0;
-                       fm->ingress = 0;
-                       fm->egress = 0;
-                       fm->transfer = 0;
-                       ret = -1;
-                       DRV_LOG(ERR, "Meter action create failed.");
+               rte_spinlock_lock(&fm->sl);
+               if (fm->meter_action) {
+                       if (fm->shared &&
+                           attr->transfer == fm->transfer &&
+                           attr->ingress == fm->ingress &&
+                           attr->egress == fm->egress) {
+                               fm->ref_cnt++;
+                       } else {
+                               rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                       fm->shared ?
+                                       "Meter attr not match." :
+                                       "Meter cannot be shared.");
+                               ret = -1;
+                       }
+               } else {
+                       fm->ingress = attr->ingress;
+                       fm->egress = attr->egress;
+                       fm->transfer = attr->transfer;
+                       fm->ref_cnt = 1;
+                       /* This also creates the meter object. */
+                       fm->meter_action = mlx5_flow_meter_action_create(priv,
+                                                                        fm);
+                       if (!fm->meter_action) {
+                               fm->ref_cnt = 0;
+                               fm->ingress = 0;
+                               fm->egress = 0;
+                               fm->transfer = 0;
+                               rte_flow_error_set(error, EINVAL,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                       "Meter action create failed.");
+                               ret = -1;
+                       }
                }
+               rte_spinlock_unlock(&fm->sl);
        }
-       rte_spinlock_unlock(&fm->sl);
-       if (ret)
-               rte_flow_error_set(error, EINVAL,
-                                  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-                                  fm->mfts->meter_action ?
-                                  "Meter attr not match" :
-                                  "Meter action create failed");
        return ret ? -rte_errno : 0;
 }
 
 /**
  * Detach meter from flow.
  *
+ * @param [in] priv
+ *  Pointer to mlx5 private data.
  * @param [in] fm
  *  Pointer to flow meter.
  */
 void
-mlx5_flow_meter_detach(struct mlx5_flow_meter_info *fm)
+mlx5_flow_meter_detach(struct mlx5_priv *priv,
+                      struct mlx5_flow_meter_info *fm)
 {
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
        rte_spinlock_lock(&fm->sl);
        MLX5_ASSERT(fm->ref_cnt);
-       if (--fm->ref_cnt == 0) {
-               mlx5_glue->destroy_flow_action(fm->mfts->meter_action);
-               fm->mfts->meter_action = NULL;
+       if (--fm->ref_cnt == 0 && !priv->sh->meter_aso_en) {
+               mlx5_glue->destroy_flow_action(fm->meter_action);
+               fm->meter_action = NULL;
                fm->ingress = 0;
                fm->egress = 0;
                fm->transfer = 0;
        }
        rte_spinlock_unlock(&fm->sl);
 #else
+       (void)priv;
        (void)fm;
 #endif
 }