net/mlx5: support basic meter operations
authorSuanming Mou <suanmingm@mellanox.com>
Fri, 8 Nov 2019 03:49:14 +0000 (05:49 +0200)
committerFerruh Yigit <ferruh.yigit@intel.com>
Mon, 11 Nov 2019 13:23:02 +0000 (14:23 +0100)
This commit add the basic meter operations for meter create and destroy.

New internal functions in rte_mtr_ops callback:
1. create()
2. destroy()

The create() callback will create the corresponding flow rules on the
meter table.
The destroy() callback destroys the flow rules on the meter table.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
Acked-by: Matan Azrad <matan@mellanox.com>
drivers/net/mlx5/mlx5.c
drivers/net/mlx5/mlx5.h
drivers/net/mlx5/mlx5_flow.h
drivers/net/mlx5/mlx5_flow_meter.c

index 3bebad3..b1921c3 100644 (file)
@@ -2403,6 +2403,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
                mlx5_nl_mac_addr_sync(eth_dev);
        TAILQ_INIT(&priv->flows);
        TAILQ_INIT(&priv->ctrl_flows);
+       TAILQ_INIT(&priv->flow_meters);
        TAILQ_INIT(&priv->flow_meter_profiles);
        /* Hint libmlx5 to use PMD allocator for data plane resources */
        struct mlx5dv_ctx_allocators alctr = {
index 8f2c541..d8a3d40 100644 (file)
@@ -694,6 +694,8 @@ struct mlx5_proc_priv {
 
 /* MTR profile list. */
 TAILQ_HEAD(mlx5_mtr_profiles, mlx5_flow_meter_profile);
+/* MTR list. */
+TAILQ_HEAD(mlx5_flow_meters, mlx5_flow_meter);
 
 #define MLX5_PROC_PRIV(port_id) \
        ((struct mlx5_proc_priv *)rte_eth_devices[port_id].process_private)
@@ -766,6 +768,7 @@ struct mlx5_priv {
        uint8_t mtr_sfx_reg; /* Meter prefix-suffix flow match REG_C. */
        uint8_t mtr_color_reg; /* Meter color match REG_C. */
        struct mlx5_mtr_profiles flow_meter_profiles; /* MTR profile list. */
+       struct mlx5_flow_meters flow_meters; /* MTR list. */
 #ifndef RTE_ARCH_64
        rte_spinlock_t uar_lock_cq; /* CQs share a common distinct UAR */
        rte_spinlock_t uar_lock[MLX5_UAR_PAGE_NUM_MAX];
@@ -1031,5 +1034,7 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_td(struct ibv_context *ctx);
 /* mlx5_flow_meter.c */
 
 int mlx5_flow_meter_ops_get(struct rte_eth_dev *dev, void *arg);
+struct mlx5_flow_meter *mlx5_flow_meter_find(struct mlx5_priv *priv,
+                                            uint32_t meter_id);
 
 #endif /* RTE_PMD_MLX5_H_ */
index 489d7c0..aaeb5b3 100644 (file)
@@ -557,14 +557,22 @@ struct mlx5_meter_domains_infos {
 
 /* Meter parameter structure. */
 struct mlx5_flow_meter {
+       TAILQ_ENTRY(mlx5_flow_meter) next;
+       /**< Pointer to the next flow meter structure. */
        uint32_t meter_id;
        /**< Meter id. */
        struct rte_mtr_params params;
        /**< Meter rule parameters. */
+       struct mlx5_flow_meter_profile *profile;
+       /**< Meter profile parameters. */
        struct mlx5_meter_domains_infos *mfts;
        /**< Flow table created for this meter. */
        uint32_t ref_cnt;
        /**< Use count. */
+       uint32_t active_state:1;
+       /**< Meter state. */
+       uint32_t shared:1;
+       /**< Meter shared or not. */
 };
 
 /* RFC2697 parameter structure. */
index 5ad5e14..76a3180 100644 (file)
@@ -362,12 +362,227 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
        return 0;
 }
 
+/**
+ * Convert wrong color setting action to verbose error.
+ *
+ * @param[in] action
+ *   Policy color action.
+ *
+ * @return
+ *   Verbose meter color error type.
+ */
+static inline enum rte_mtr_error_type
+action2error(enum rte_mtr_policer_action action)
+{
+       switch (action) {
+       case MTR_POLICER_ACTION_COLOR_GREEN:
+               return RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN;
+       case MTR_POLICER_ACTION_COLOR_YELLOW:
+               return RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW;
+       case MTR_POLICER_ACTION_COLOR_RED:
+               return RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED;
+       default:
+               break;
+       }
+       return RTE_MTR_ERROR_TYPE_UNSPECIFIED;
+}
+
+/**
+ * Check meter validation.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5 private data structure.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[in] params
+ *   Pointer to rte meter parameters.
+ * @param[out] error
+ *   Pointer to rte meter error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
+                        struct rte_mtr_params *params,
+                        struct rte_mtr_error *error)
+{
+       static enum rte_mtr_policer_action
+                               valid_recol_action[RTE_COLORS] = {
+                                              MTR_POLICER_ACTION_COLOR_GREEN,
+                                              MTR_POLICER_ACTION_COLOR_YELLOW,
+                                              MTR_POLICER_ACTION_COLOR_RED };
+       int i;
+
+       /* Meter params must not be NULL. */
+       if (params == NULL)
+               return -rte_mtr_error_set(error, EINVAL,
+                                         RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+                                         NULL, "Meter object params null.");
+       /* Previous meter color is not supported. */
+       if (params->use_prev_mtr_color)
+               return -rte_mtr_error_set(error, ENOTSUP,
+                                         RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+                                         NULL,
+                                         "Previous meter color "
+                                         "not supported.");
+       /* Validate policer settings. */
+       for (i = 0; i < RTE_COLORS; i++)
+               if (params->action[i] != valid_recol_action[i] &&
+                   params->action[i] != MTR_POLICER_ACTION_DROP)
+                       return -rte_mtr_error_set
+                                       (error, ENOTSUP,
+                                        action2error(params->action[i]), NULL,
+                                        "Recolor action not supported.");
+       /* Validate meter id. */
+       if (mlx5_flow_meter_find(priv, meter_id))
+               return -rte_mtr_error_set(error, EEXIST,
+                                         RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+                                         "Meter object already exists.");
+       return 0;
+}
+
+/**
+ * Create meter rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[in] params
+ *   Pointer to rte meter parameters.
+ * @param[in] shared
+ *   Meter shared with other flow or not.
+ * @param[out] error
+ *   Pointer to rte meter error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_create(struct rte_eth_dev *dev, uint32_t meter_id,
+                      struct rte_mtr_params *params, int shared,
+                      struct rte_mtr_error *error)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_flow_meters *fms = &priv->flow_meters;
+       struct mlx5_flow_meter_profile *fmp;
+       struct mlx5_flow_meter *fm;
+       const struct rte_flow_attr attr = {
+                               .ingress = 1,
+                               .egress = 1,
+                               .transfer = priv->config.dv_esw_en ? 1 : 0,
+                       };
+       int ret;
+
+       if (!priv->mtr_en)
+               return -rte_mtr_error_set(error, ENOTSUP,
+                                         RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+                                         "Meter is not support");
+       /* Validate the parameters. */
+       ret = mlx5_flow_meter_validate(priv, meter_id, params, error);
+       if (ret)
+               return ret;
+       /* Meter profile must exist. */
+       fmp = mlx5_flow_meter_profile_find(priv, params->meter_profile_id);
+       if (fmp == NULL)
+               return -rte_mtr_error_set(error, ENOENT,
+                                         RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+                                         NULL, "Meter profile id not valid.");
+       /* Allocate the flow meter memory. */
+       fm = rte_calloc(__func__, 1,
+                       sizeof(struct mlx5_flow_meter), RTE_CACHE_LINE_SIZE);
+       if (fm == NULL)
+               return -rte_mtr_error_set(error, ENOMEM,
+                                         RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+                                         "Memory alloc failed for meter.");
+       /* Fill the flow meter parameters. */
+       fm->meter_id = meter_id;
+       fm->profile = fmp;
+       fm->params = *params;
+       fm->mfts = mlx5_flow_create_mtr_tbls(dev);
+       if (!fm->mfts)
+               goto error;
+       ret = mlx5_flow_create_policer_rules(dev, fm, &attr);
+       if (ret)
+               goto error;
+       /* Add to the flow meter list. */
+       TAILQ_INSERT_TAIL(fms, fm, next);
+       fm->active_state = 1; /* Config meter starts as active. */
+       fm->shared = !!shared;
+       fm->profile->ref_cnt++;
+       return 0;
+error:
+       mlx5_flow_destroy_policer_rules(dev, fm, &attr);
+       mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
+       rte_free(fm);
+       return -rte_mtr_error_set(error, -ret,
+                                 RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+                                 NULL, "Failed to create devx meter.");
+}
+
+/**
+ * Destroy meter rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[out] error
+ *   Pointer to rte meter error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
+                       struct rte_mtr_error *error)
+{
+       struct mlx5_priv *priv = dev->data->dev_private;
+       struct mlx5_flow_meters *fms = &priv->flow_meters;
+       struct mlx5_flow_meter_profile *fmp;
+       struct mlx5_flow_meter *fm;
+       const struct rte_flow_attr attr = {
+                               .ingress = 1,
+                               .egress = 1,
+                               .transfer = priv->config.dv_esw_en ? 1 : 0,
+                       };
+
+       if (!priv->mtr_en)
+               return -rte_mtr_error_set(error, ENOTSUP,
+                                         RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+                                         "Meter is not support");
+       /* Meter object must exist. */
+       fm = mlx5_flow_meter_find(priv, meter_id);
+       if (fm == NULL)
+               return -rte_mtr_error_set(error, ENOENT,
+                                         RTE_MTR_ERROR_TYPE_MTR_ID,
+                                         NULL, "Meter object id not valid.");
+       /* Meter object must not have any owner. */
+       if (fm->ref_cnt > 0)
+               return -rte_mtr_error_set(error, EBUSY,
+                                         RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+                                         NULL, "Meter object is being used.");
+       /* Get the meter profile. */
+       fmp = fm->profile;
+       RTE_ASSERT(fmp);
+       /* Update dependencies. */
+       fmp->ref_cnt--;
+       /* Remove from the flow meter list. */
+       TAILQ_REMOVE(fms, fm, next);
+       /* Free meter flow table */
+       mlx5_flow_destroy_policer_rules(dev, fm, &attr);
+       mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
+       rte_free(fm);
+       return 0;
+}
+
 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
        .capabilities_get = mlx5_flow_mtr_cap_get,
        .meter_profile_add = mlx5_flow_meter_profile_add,
        .meter_profile_delete = mlx5_flow_meter_profile_delete,
-       .create = NULL,
-       .destroy = NULL,
+       .create = mlx5_flow_meter_create,
+       .destroy = mlx5_flow_meter_destroy,
        .meter_enable = NULL,
        .meter_disable = NULL,
        .meter_profile_update = NULL,
@@ -394,3 +609,26 @@ mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
        *(const struct rte_mtr_ops **)arg = &mlx5_flow_mtr_ops;
        return 0;
 }
+
+/**
+ * Find meter by id.
+ *
+ * @param priv
+ *   Pointer to mlx5_priv.
+ * @param meter_id
+ *   Meter id.
+ *
+ * @return
+ *   Pointer to the profile found on success, NULL otherwise.
+ */
+struct mlx5_flow_meter *
+mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id)
+{
+       struct mlx5_flow_meters *fms = &priv->flow_meters;
+       struct mlx5_flow_meter *fm;
+
+       TAILQ_FOREACH(fm, fms, next)
+               if (meter_id == fm->meter_id)
+                       return fm;
+       return NULL;
+}