diff mbox series

[v1,3/4] net/mlx5: meter hierarchy destroy and cleanup

Message ID 20210706131450.30917-4-shunh@nvidia.com (mailing list archive)
State Accepted, archived
Delegated to: Raslan Darawsheh
Headers show
Series Add support for meter hierarchy | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Shun Hao July 6, 2021, 1:14 p.m. UTC
When creating hierarchy meter, its color rules will increase next
meter's reference count, so when destroy the hierarchy meter, also
need to dereference the next meter's count.

During flushing all meters of a port, need to destroy all hierarchy
meters and their policies first, to dereference the last meter in
hierarchy. Then all meters have no reference and can be destroyed.

Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow_dv.c    |  15 +++-
 drivers/net/mlx5/mlx5_flow_meter.c | 132 +++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 119de09809..681e6fb07c 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -14588,12 +14588,20 @@  static void
 __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
 			     struct mlx5_flow_meter_sub_policy *sub_policy)
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_tbl_data_entry *tbl;
+	struct mlx5_flow_meter_policy *policy = sub_policy->main_policy;
+	struct mlx5_flow_meter_info *next_fm;
 	struct mlx5_sub_policy_color_rule *color_rule;
 	void *tmp;
-	int i;
+	uint32_t i;
 
 	for (i = 0; i < RTE_COLORS; i++) {
+		next_fm = NULL;
+		if (i == RTE_COLOR_GREEN && policy &&
+		    policy->act_cnt[i].fate_action == MLX5_FLOW_FATE_MTR)
+			next_fm = mlx5_flow_meter_find(priv,
+					policy->act_cnt[i].next_mtr_id, NULL);
 		TAILQ_FOREACH_SAFE(color_rule, &sub_policy->color_rules[i],
 				   next_port, tmp) {
 			claim_zero(mlx5_flow_os_destroy_flow(color_rule->rule));
@@ -14604,11 +14612,14 @@  __flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
 			TAILQ_REMOVE(&sub_policy->color_rules[i],
 					color_rule, next_port);
 			mlx5_free(color_rule);
+			if (next_fm)
+				mlx5_flow_meter_detach(priv, next_fm);
 		}
 	}
 	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
 		if (sub_policy->rix_hrxq[i]) {
-			mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+			if (policy && !policy->is_hierarchy)
+				mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
 			sub_policy->rix_hrxq[i] = 0;
 		}
 		if (sub_policy->jump_tbl[i]) {
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 03f7e120e1..78eb2a60f9 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -1891,6 +1891,136 @@  mlx5_flow_meter_rxq_flush(struct rte_eth_dev *dev)
 	}
 }
 
+/**
+ * Iterate a meter hierarchy and flush all meters and policies if possible.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter.
+ * @param[in] mtr_idx
+ *   .Meter's index
+ * @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_flush_hierarchy(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
+				uint32_t mtr_idx,
+				struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *policy;
+	uint32_t policy_id;
+	struct mlx5_flow_meter_info *next_fm;
+	uint32_t next_mtr_idx;
+	struct mlx5_flow_meter_policy *next_policy = NULL;
+
+	policy = mlx5_flow_meter_policy_find(dev, fm->policy_id, NULL);
+	MLX5_ASSERT(policy);
+	while (!fm->ref_cnt && policy->is_hierarchy) {
+		policy_id = fm->policy_id;
+		next_fm = mlx5_flow_meter_find(priv,
+				policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
+				&next_mtr_idx);
+		if (next_fm) {
+			next_policy = mlx5_flow_meter_policy_find(dev,
+							next_fm->policy_id,
+							NULL);
+			MLX5_ASSERT(next_policy);
+		}
+		if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
+			return -rte_mtr_error_set(error, ENOTSUP,
+						RTE_MTR_ERROR_TYPE_MTR_ID,
+						NULL,
+						"Failed to flush meter.");
+		if (policy->ref_cnt)
+			break;
+		if (__mlx5_flow_meter_policy_delete(dev, policy_id,
+						policy, error, true))
+			return -rte_errno;
+		mlx5_free(policy);
+		if (!next_fm || !next_policy)
+			break;
+		fm = next_fm;
+		mtr_idx = next_mtr_idx;
+		policy = next_policy;
+	}
+	return 0;
+}
+
+/**
+ * Flush all the hierarchy meters and their policies.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @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_flush_all_hierarchies(struct rte_eth_dev *dev,
+				      struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_info *fm;
+	struct mlx5_flow_meter_policy *policy;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	struct mlx5_flow_meter_info *next_fm;
+	struct mlx5_aso_mtr *aso_mtr;
+	uint32_t mtr_idx = 0;
+	uint32_t i, policy_idx;
+	void *entry;
+
+	if (!priv->mtr_idx_tbl || !priv->policy_idx_tbl)
+		return 0;
+	MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
+		mtr_idx = *(uint32_t *)entry;
+		if (!mtr_idx)
+			continue;
+		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+		fm = &aso_mtr->fm;
+		if (fm->ref_cnt || fm->def_policy)
+			continue;
+		if (mlx5_flow_meter_flush_hierarchy(dev, fm, mtr_idx, error))
+			return -rte_errno;
+	}
+	MLX5_L3T_FOREACH(priv->policy_idx_tbl, i, entry) {
+		policy_idx = *(uint32_t *)entry;
+		sub_policy = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				policy_idx);
+		if (!sub_policy)
+			return -rte_mtr_error_set(error,
+					EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+					NULL, "Meter policy invalid.");
+		policy = sub_policy->main_policy;
+		if (!policy || !policy->is_hierarchy || policy->ref_cnt)
+			continue;
+		next_fm = mlx5_flow_meter_find(priv,
+				policy->act_cnt[RTE_COLOR_GREEN].next_mtr_id,
+				&mtr_idx);
+		if (__mlx5_flow_meter_policy_delete(dev, i, policy,
+						    error, true))
+			return -rte_mtr_error_set(error,
+					EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+					NULL, "Meter policy invalid.");
+		mlx5_free(policy);
+		if (!next_fm || next_fm->ref_cnt || next_fm->def_policy)
+			continue;
+		if (mlx5_flow_meter_flush_hierarchy(dev, next_fm,
+						    mtr_idx, error))
+			return -rte_errno;
+	}
+	return 0;
+}
 /**
  * Flush meter configuration.
  *
@@ -1919,6 +2049,8 @@  mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 	if (!priv->mtr_en)
 		return 0;
 	if (priv->sh->meter_aso_en) {
+		if (mlx5_flow_meter_flush_all_hierarchies(dev, error))
+			return -rte_errno;
 		if (priv->mtr_idx_tbl) {
 			MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
 				mtr_idx = *(uint32_t *)entry;