[06/19] net/mlx5: prepare meter flow tables

Message ID 1573053090-179521-7-git-send-email-suanmingm@mellanox.com (mailing list archive)
State Superseded, archived
Delegated to: Raslan Darawsheh
Headers
Series net/mlx5: support meter |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/Intel-compilation fail apply issues

Commit Message

Suanming Mou Nov. 6, 2019, 3:11 p.m. UTC
  This commit prepare the meter table and suffix table.

A flow with meter will be split to three flows. The three flows are
created on differnet tables. The packets transfer between the flows
on the tables as below:

Prefix flow -> Meter flow -> Suffix flow

Prefix flow does the user defined match and the meter action. The meter
action colors the packet and set its destination to meter table to be
processed by the meter flow.
The meter flow judges if the packet can be passed or not. If packet can
be passed, it will be transferred to the suffix table.
The suffix flow on the suffix table will apply the left user defined
actions to the packet.

The ingress egress and transfer all have the independent meter and
suffix tables.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.h         |   8 ++
 drivers/net/mlx5/mlx5_flow.c    |  39 ++++++
 drivers/net/mlx5/mlx5_flow.h    |  50 ++++++++
 drivers/net/mlx5/mlx5_flow_dv.c | 260 ++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_prm.h     |   8 ++
 5 files changed, 365 insertions(+)
  

Patch

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index b1d5341..58bd7d0 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -576,6 +576,8 @@  struct mlx5_flow_tbl_resource {
 };
 
 #define MLX5_MAX_TABLES UINT16_MAX
+#define MLX5_FLOW_TABLE_LEVEL_METER (UINT16_MAX - 3)
+#define MLX5_FLOW_TABLE_LEVEL_SUFFIX (UINT16_MAX - 2)
 #define MLX5_HAIRPIN_TX_TABLE (UINT16_MAX - 1)
 /* Reserve the last two tables for metadata register copy. */
 #define MLX5_FLOW_MREG_ACT_TABLE_GROUP (MLX5_MAX_TABLES - 1)
@@ -642,12 +644,18 @@  struct mlx5_ibv_shared {
 	void *fdb_domain; /* FDB Direct Rules name space handle. */
 	struct mlx5_flow_tbl_resource fdb_tbl[MLX5_MAX_TABLES_FDB];
 	/* FDB Direct Rules tables. */
+	struct mlx5_flow_tbl_resource *fdb_mtr_sfx_tbl;
+	/* FDB meter suffix rules table. */
 	void *rx_domain; /* RX Direct Rules name space handle. */
 	struct mlx5_flow_tbl_resource rx_tbl[MLX5_MAX_TABLES];
 	/* RX Direct Rules tables. */
+	struct mlx5_flow_tbl_resource *rx_mtr_sfx_tbl;
+	/* RX meter suffix rules table. */
 	void *tx_domain; /* TX Direct Rules name space handle. */
 	struct mlx5_flow_tbl_resource tx_tbl[MLX5_MAX_TABLES];
 	/* TX Direct Rules tables. */
+	struct mlx5_flow_tbl_resource *tx_mtr_sfx_tbl;
+	/* TX meter suffix rules table. */
 	void *esw_drop_action; /* Pointer to DR E-Switch drop action. */
 	void *pop_vlan_action; /* Pointer to DR pop VLAN action. */
 	/* TX Direct Rules tables/ */
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index e569b90..6dcdb32 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4874,6 +4874,45 @@  struct rte_flow *
 	return 0;
 }
 
+/**
+ * Create the needed meter and suffix tables.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   Pointer to table set on success, NULL otherwise.
+ */
+struct mlx5_meter_domains_infos *
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_mtr_tbls(dev);
+}
+
+/**
+ * Destroy the meter table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] tbl
+ *   Pointer to the meter table set.
+ *
+ * @return
+ *   0 on success.
+ */
+int
+mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			   struct mlx5_meter_domains_infos *tbls)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->destroy_mtr_tbls(dev, tbls);
+}
+
 #define MLX5_POOL_QUERY_FREQ_US 1000000
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 922d6b6..14d437b 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -524,6 +524,46 @@  struct mlx5_flow {
 };
 
 #define MLX5_MAN_WIDTH 8
+/* Modify this value if enum rte_mtr_color changes. */
+#define RTE_MTR_DROPPED RTE_COLORS
+
+/* Meter table structure. */
+struct mlx5_meter_domain_info {
+	struct mlx5_flow_tbl_resource *tbl;
+	/**< Meter table. */
+	void *any_matcher;
+	/**< Meter color not match default criteria. */
+	void *color_matcher;
+	/**< Meter color match criteria. */
+	void *jump_actn;
+	/**< Meter match action. */
+	void *policer_rules[RTE_MTR_DROPPED + 1];
+	/**< Meter policer for the match. */
+};
+
+/* Meter table set for TX RX FDB. */
+struct mlx5_meter_domains_infos {
+	uint32_t ref_cnt;
+	/**< Table user count. */
+	struct mlx5_meter_domain_info egress;
+	/**< TX meter table. */
+	struct mlx5_meter_domain_info ingress;
+	/**< RX meter table. */
+	struct mlx5_meter_domain_info transfer;
+	/**< FDB meter table. */
+	void *drop_actn;
+	/**< Drop action as not matched. */
+};
+
+/* Meter parameter structure. */
+struct mlx5_flow_meter {
+	uint32_t meter_id;
+	/**< Meter id. */
+	struct mlx5_meter_domains_infos *mfts;
+	/**< Flow table created for this meter. */
+	uint32_t ref_cnt;
+	/**< Use count. */
+};
 
 /* RFC2697 parameter structure. */
 struct mlx5_flow_meter_srtcm_rfc2697_prm {
@@ -592,6 +632,10 @@  typedef int (*mlx5_flow_query_t)(struct rte_eth_dev *dev,
 				 const struct rte_flow_action *actions,
 				 void *data,
 				 struct rte_flow_error *error);
+typedef struct mlx5_meter_domains_infos *(*mlx5_flow_create_mtr_tbls_t)
+					    (struct rte_eth_dev *dev);
+typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
+					struct mlx5_meter_domains_infos *tbls);
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
 	mlx5_flow_prepare_t prepare;
@@ -600,6 +644,8 @@  struct mlx5_flow_driver_ops {
 	mlx5_flow_remove_t remove;
 	mlx5_flow_destroy_t destroy;
 	mlx5_flow_query_t query;
+	mlx5_flow_create_mtr_tbls_t create_mtr_tbls;
+	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
 };
 
 
@@ -722,4 +768,8 @@  int mlx5_flow_validate_item_geneve(const struct rte_flow_item *item,
 				   uint64_t item_flags,
 				   struct rte_eth_dev *dev,
 				   struct rte_flow_error *error);
+struct mlx5_meter_domains_infos *mlx5_flow_create_mtr_tbls
+					(struct rte_eth_dev *dev);
+int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			       struct mlx5_meter_domains_infos *tbl);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 6a7e612..75ba133 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -102,6 +102,31 @@ 
 	attr->valid = 1;
 }
 
+/**
+ * Convert rte_mtr_color to mlx5 color.
+ *
+ * @param[in] rcol
+ *   rte_mtr_color.
+ *
+ * @return
+ *   mlx5 color.
+ */
+static int
+rte_col_2_mlx5_col(enum rte_color rcol)
+{
+	switch (rcol) {
+	case RTE_COLOR_GREEN:
+		return MLX5_FLOW_COLOR_GREEN;
+	case RTE_COLOR_YELLOW:
+		return MLX5_FLOW_COLOR_YELLOW;
+	case RTE_COLOR_RED:
+		return MLX5_FLOW_COLOR_RED;
+	default:
+		break;
+	}
+	return MLX5_FLOW_COLOR_UNDEFINED;
+}
+
 struct field_modify_info {
 	uint32_t size; /* Size of field in protocol header, in bytes. */
 	uint32_t offset; /* Offset of field in protocol header, in bytes. */
@@ -7525,6 +7550,239 @@  struct field_modify_info modify_tcp[] = {
 	return ret;
 }
 
+/**
+ * Destroy the meter table set.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] tbl
+ *   Pointer to the meter table set.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
+			struct mlx5_meter_domains_infos *tbl)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_domains_infos *mtd =
+				(struct mlx5_meter_domains_infos *)tbl;
+
+	if (!mtd || !priv->config.dv_flow_en)
+		return 0;
+	if (mtd->ingress.policer_rules[RTE_MTR_DROPPED])
+		claim_zero(mlx5_glue->dv_destroy_flow
+			  (mtd->ingress.policer_rules[RTE_MTR_DROPPED]));
+	if (mtd->egress.policer_rules[RTE_MTR_DROPPED])
+		claim_zero(mlx5_glue->dv_destroy_flow
+			  (mtd->egress.policer_rules[RTE_MTR_DROPPED]));
+	if (mtd->transfer.policer_rules[RTE_MTR_DROPPED])
+		claim_zero(mlx5_glue->dv_destroy_flow
+			  (mtd->transfer.policer_rules[RTE_MTR_DROPPED]));
+	if (mtd->egress.color_matcher)
+		claim_zero(mlx5_glue->dv_destroy_flow_matcher
+			  (mtd->egress.color_matcher));
+	if (mtd->egress.any_matcher)
+		claim_zero(mlx5_glue->dv_destroy_flow_matcher
+			  (mtd->egress.any_matcher));
+	if (mtd->egress.tbl)
+		claim_zero(flow_dv_tbl_resource_release(mtd->egress.tbl));
+	if (mtd->ingress.color_matcher)
+		claim_zero(mlx5_glue->dv_destroy_flow_matcher
+			  (mtd->ingress.color_matcher));
+	if (mtd->ingress.any_matcher)
+		claim_zero(mlx5_glue->dv_destroy_flow_matcher
+			  (mtd->ingress.any_matcher));
+	if (mtd->ingress.tbl)
+		claim_zero(flow_dv_tbl_resource_release(mtd->ingress.tbl));
+	if (mtd->transfer.color_matcher)
+		claim_zero(mlx5_glue->dv_destroy_flow_matcher
+			  (mtd->transfer.color_matcher));
+	if (mtd->transfer.any_matcher)
+		claim_zero(mlx5_glue->dv_destroy_flow_matcher
+			  (mtd->transfer.any_matcher));
+	if (mtd->transfer.tbl)
+		claim_zero(flow_dv_tbl_resource_release(mtd->transfer.tbl));
+	if (mtd->drop_actn)
+		claim_zero(mlx5_glue->destroy_flow_action(mtd->drop_actn));
+	rte_free(mtd);
+	return 0;
+}
+
+/**
+ * Create specify domain meter table and suffix table.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in,out] mtb
+ *   Pointer to DV meter table set.
+ * @param[in] egress
+ *   Table attribute.
+ * @param[in] transfer
+ *   Table attribute.
+ * @param[in] color_reg_c_idx
+ *   Reg C index for color match.
+ *
+ * @return
+ *   0 on success, -1 otherwise and rte_errno is set.
+ */
+static int
+flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
+			   struct mlx5_meter_domains_infos *mtb,
+			   uint8_t egress, uint8_t transfer,
+			   uint32_t color_reg_c_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_ibv_shared *sh = priv->sh;
+	struct mlx5_flow_dv_match_params mask = {
+		.size = sizeof(mask.buf),
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf),
+	};
+	struct mlx5dv_flow_matcher_attr dv_attr = {
+		.type = IBV_FLOW_ATTR_NORMAL,
+		.priority = 0,
+		.match_criteria_enable = 0,
+		.match_mask = (void *)&mask,
+	};
+	/*
+	 * Need reserve two actions here. As for the meter flow, the action
+	 * to be performed will be jump or drop. The other reserve action is
+	 * for count.
+	 */
+#define METER_ACTIONS 2
+	void *actions[METER_ACTIONS];
+	struct mlx5_flow_tbl_resource **sfx_tbl;
+	struct mlx5_meter_domain_info *dtb;
+	struct rte_flow_error error;
+	int i = 0;
+
+	if (transfer) {
+		sfx_tbl = &sh->fdb_mtr_sfx_tbl;
+		dtb = &mtb->transfer;
+	} else if (egress) {
+		sfx_tbl = &sh->tx_mtr_sfx_tbl;
+		dtb = &mtb->egress;
+	} else {
+		sfx_tbl = &sh->rx_mtr_sfx_tbl;
+		dtb = &mtb->ingress;
+	}
+	/* If the suffix table in missing, create it. */
+	if (!(*sfx_tbl)) {
+		*sfx_tbl = flow_dv_tbl_resource_get(dev,
+						MLX5_FLOW_TABLE_LEVEL_SUFFIX,
+						egress, transfer, &error);
+		if (!(*sfx_tbl)) {
+			DRV_LOG(ERR, "Failed to create meter suffix table.");
+			return -1;
+		}
+	}
+	/* Create the meter table with METER level. */
+	dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
+					    egress, transfer, &error);
+	if (!dtb->tbl) {
+		DRV_LOG(ERR, "Failed to create meter policer table.");
+		return -1;
+	}
+	/* Create matchers, Any and Color. */
+	dv_attr.priority = 3;
+	dv_attr.match_criteria_enable = 0;
+	dtb->any_matcher = mlx5_glue->dv_create_flow_matcher(sh->ctx,
+							     &dv_attr,
+							     dtb->tbl->obj);
+	if (!dtb->any_matcher) {
+		DRV_LOG(ERR, "Failed to create meter"
+			     " policer default matcher.");
+		goto error_exit;
+	}
+	dv_attr.priority = 0;
+	dv_attr.match_criteria_enable =
+				1 << MLX5_MATCH_CRITERIA_ENABLE_MISC2_BIT;
+	flow_dv_match_meta_reg(mask.buf, value.buf, color_reg_c_idx,
+			       rte_col_2_mlx5_col(RTE_COLORS), UINT32_MAX);
+	dtb->color_matcher = mlx5_glue->dv_create_flow_matcher(sh->ctx,
+							       &dv_attr,
+							       dtb->tbl->obj);
+	if (!dtb->color_matcher) {
+		DRV_LOG(ERR, "Failed to create meter policer color matcher.");
+		goto error_exit;
+	}
+	actions[i++] = mtb->drop_actn;
+	/* Default rule: lowest priority, match any, actions: drop. */
+	dtb->policer_rules[RTE_MTR_DROPPED] =
+			mlx5_glue->dv_create_flow(dtb->any_matcher,
+						 (void *)&value, i, actions);
+	if (!dtb->policer_rules[RTE_MTR_DROPPED]) {
+		DRV_LOG(ERR, "Failed to create meter policer drop rule.");
+		goto error_exit;
+	}
+	return 0;
+error_exit:
+	return -1;
+}
+
+/**
+ * Create the needed meter and suffix tables.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_meter_domains_infos *
+flow_dv_create_mtr_tbl(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_domains_infos *mtb;
+	int ret;
+
+	if (!priv->mtr_en) {
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+	mtb = rte_calloc(__func__, 1, sizeof(*mtb), 0);
+	if (!mtb) {
+		DRV_LOG(ERR, "Failed to allocate memory for meter.");
+		return NULL;
+	}
+	/* Create drop action. */
+	mtb->drop_actn = mlx5_glue->dr_create_flow_action_drop();
+	if (!mtb->drop_actn) {
+		DRV_LOG(ERR, "Failed to create drop action.");
+		goto error_exit;
+	}
+	/* Egress meter table. */
+	ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0, priv->mtr_color_reg);
+	if (ret) {
+		DRV_LOG(ERR, "Failed to prepare egress meter table.");
+		goto error_exit;
+	}
+	/* Ingress meter table. */
+	ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 0, priv->mtr_color_reg);
+	if (ret) {
+		DRV_LOG(ERR, "Failed to prepare ingress meter table.");
+		goto error_exit;
+	}
+	/* FDB meter table. */
+	if (priv->config.dv_esw_en) {
+		ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 1,
+						 priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to prepare fdb meter table.");
+			goto error_exit;
+		}
+	}
+	return mtb;
+error_exit:
+	flow_dv_destroy_mtr_tbl(dev, mtb);
+	return NULL;
+}
+
 /*
  * Mutex-protected thunk to lock-free  __flow_dv_translate().
  */
@@ -7590,6 +7848,8 @@  struct field_modify_info modify_tcp[] = {
 	.remove = flow_dv_remove,
 	.destroy = flow_dv_destroy,
 	.query = flow_dv_query,
+	.create_mtr_tbls = flow_dv_create_mtr_tbl,
+	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
 };
 
 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h
index 3ebf191..ebedc90 100644
--- a/drivers/net/mlx5/mlx5_prm.h
+++ b/drivers/net/mlx5/mlx5_prm.h
@@ -1768,6 +1768,14 @@  struct mlx5_mini_cqe8 {
 	uint32_t byte_cnt;
 };
 
+/* srTCM PRM flow meter parameters. */
+enum {
+	MLX5_FLOW_COLOR_RED = 0,
+	MLX5_FLOW_COLOR_YELLOW,
+	MLX5_FLOW_COLOR_GREEN,
+	MLX5_FLOW_COLOR_UNDEFINED,
+};
+
 /* Maximum value of srTCM metering parameters. */
 #define MLX5_SRTCM_CBS_MAX (0xFF * (1ULL << 0x1F))
 #define MLX5_SRTCM_CIR_MAX (8 * (1ULL << 30) * 0xFF)