DPDK-dev Archive on lore.kernel.org
 help / color / Atom feed
* [dpdk-dev] [PATCH 00/19] net/mlx5: support meter
@ 2019-11-06 15:11 Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 01/19] net/mlx5: add meter operation callback Suanming Mou
                   ` (19 more replies)
  0 siblings, 20 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  Cc: dev

The patches introduce the meter action support for mlx5.
The design of the implementation was introduced in RFC as below:
http://inbox.dpdk.org/dev/b994cd03-02f6-cd50-120f-dcf0941e4485@mellanox.com

The implementation is followed RFC to split flow with meter to three
sub flows.
Prefix flow -> Meter flow -> Suffix flow

The srTCM color blind mode is supported only, color aware mode and
multiple meter chaining are not supported.

The patch set add the operations to get the capabilities of the meter
action, create/destroy the action, validate the action, attach/detach
the action, update the action, query the action statistics and flush
the actions resources.

Besides these, as the flow with meter action is split to three sub
flows for coloring(in prefix flow), color checking(in meter flow),
left actions applying (in suffix flow), two registers are used for the
color match and prefix-suffix flow match. That's what the "allocate
flow meter registers" patch does.

As with the three sub flows, two more flow tables are created for the
meter flow and suffix flow in patch "prepare meter flow tables". As
wrote in the RFC, meter flow and suffix flow are separated since meter
maybe shared with multiple flows.

For the meter action statistics's query, the DevX flow counter is
exposed to meter action in patch "expose flow counters management".

In the "split meter flow" patch, flow with meter is split to three
sub flow. The *_DECAP and meter action will be in the prefix flow.
And an extra tag action with unique flow id to match with the suffix
flow is also added to the prefix flow. The suffix flow will apply
all the left actions while the flow id in tag item matches.

Since the metadata copy mark action is in the meter suffix flow,
the REG_C for cpoy mark and prefix-suffix flow match is shared.
Once the meter suffix flow add the tag, metadata suffix sub flow
won't add the tag anymore but share the tag is enough. It's done
in the "share tag between meter and metadata" patch.

The meter patch set should be applied after the extensive metadata
feature:
https://patches.dpdk.org/project/dpdk/list/?series=7242


Suanming Mou (19):
  net/mlx5: add meter operation callback
  net/mlx5: fill meter capabilities using DevX
  net/mlx5: allocate flow meter registers
  net/mlx5: support meter profile operations
  net/mlx5: validate meter profile
  net/mlx5: prepare meter flow tables
  net/mlx5: add policer rules operations
  net/mlx5: support basic meter operations
  net/mlx5: add meter action creation to the glue
  net/mlx5: support meter modification operations
  net/mlx5: support meter profile update
  net/mlx5: expose flow counters management
  net/mlx5: add count action to meter
  net/mlx5: add meter statistics read and update
  net/mlx5: add meter attach and detach
  net/mlx5: support meter flow action
  net/mlx5: split meter flow
  net/mlx5: share tag between meter and metadata
  net/mlx5: clean meter resources

 drivers/net/mlx5/Makefile          |    7 +
 drivers/net/mlx5/meson.build       |    3 +
 drivers/net/mlx5/mlx5.c            |   29 +
 drivers/net/mlx5/mlx5.h            |   46 ++
 drivers/net/mlx5/mlx5_devx_cmds.c  |   23 +
 drivers/net/mlx5/mlx5_flow.c       |  617 +++++++++++++++--
 drivers/net/mlx5/mlx5_flow.h       |  153 ++++-
 drivers/net/mlx5/mlx5_flow_dv.c    |  612 +++++++++++++++++
 drivers/net/mlx5/mlx5_flow_meter.c | 1283 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.c       |   30 +
 drivers/net/mlx5/mlx5_glue.h       |    9 +
 drivers/net/mlx5/mlx5_prm.h        |   45 ++
 12 files changed, 2804 insertions(+), 53 deletions(-)
 create mode 100644 drivers/net/mlx5/mlx5_flow_meter.c

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 01/19] net/mlx5: add meter operation callback
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 02/19] net/mlx5: fill meter capabilities using DevX Suanming Mou
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

Add the new mlx5_flow_meter.c file for metering support.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/Makefile          |  6 ++++++
 drivers/net/mlx5/meson.build       |  3 +++
 drivers/net/mlx5/mlx5.c            |  2 ++
 drivers/net/mlx5/mlx5.h            |  4 ++++
 drivers/net/mlx5/mlx5_flow_meter.c | 43 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 drivers/net/mlx5/mlx5_flow_meter.c

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index dae5b9f..c60f97c 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -32,6 +32,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_stats.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_meter.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_dv.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_verbs.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mp.c
@@ -198,6 +199,11 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh
 		func mlx5dv_dr_action_create_dest_devx_tir \
 		$(AUTOCONF_OUTPUT)
 	$Q sh -- '$<' '$@' \
+		HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER \
+		infiniband/mlx5dv.h \
+		func mlx5dv_dr_action_create_flow_meter \
+		$(AUTOCONF_OUTPUT)
+	$Q sh -- '$<' '$@' \
 		HAVE_ETHTOOL_LINK_MODE_25G \
 		/usr/include/linux/ethtool.h \
 		enum ETHTOOL_LINK_MODE_25000baseCR_Full_BIT \
diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build
index 02494cf..403c107 100644
--- a/drivers/net/mlx5/meson.build
+++ b/drivers/net/mlx5/meson.build
@@ -43,6 +43,7 @@ if build
 		'mlx5.c',
 		'mlx5_ethdev.c',
 		'mlx5_flow.c',
+		'mlx5_flow_meter.c',
 		'mlx5_flow_dv.c',
 		'mlx5_flow_verbs.c',
 		'mlx5_mac.c',
@@ -129,6 +130,8 @@ if build
 		'mlx5dv_devx_obj_query_async' ],
 		[ 'HAVE_MLX5DV_DR_ACTION_DEST_DEVX_TIR', 'infiniband/mlx5dv.h',
 		'mlx5dv_dr_action_create_dest_devx_tir' ],
+		[ 'HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER', 'infiniband/mlx5dv.h',
+		'mlx5dv_dr_action_create_flow_meter' ],
 		[ 'HAVE_MLX5DV_DR', 'infiniband/mlx5dv.h',
 		'MLX5DV_DR_DOMAIN_TYPE_NIC_RX' ],
 		[ 'HAVE_MLX5DV_DR_ESWITCH', 'infiniband/mlx5dv.h',
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 62a9547..e244800 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -1171,6 +1171,7 @@ struct mlx5_flow_id_pool *
 	.get_module_info = mlx5_get_module_info,
 	.get_module_eeprom = mlx5_get_module_eeprom,
 	.hairpin_cap_get = mlx5_hairpin_cap_get,
+	.mtr_ops_get = mlx5_flow_meter_ops_get,
 };
 
 /* Available operations from secondary process. */
@@ -1234,6 +1235,7 @@ struct mlx5_flow_id_pool *
 	.get_module_info = mlx5_get_module_info,
 	.get_module_eeprom = mlx5_get_module_eeprom,
 	.hairpin_cap_get = mlx5_hairpin_cap_get,
+	.mtr_ops_get = mlx5_flow_meter_ops_get,
 };
 
 /**
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 470778b..e219cbc 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -999,4 +999,8 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_tis
 	(struct ibv_context *ctx, struct mlx5_devx_tis_attr *tis_attr);
 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);
+
 #endif /* RTE_PMD_MLX5_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
new file mode 100644
index 0000000..6c7a005
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2018 Mellanox Technologies, Ltd
+ */
+#include <math.h>
+
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
+
+#include "mlx5.h"
+
+static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
+	.capabilities_get = NULL,
+	.meter_profile_add = NULL,
+	.meter_profile_delete = NULL,
+	.create = NULL,
+	.destroy = NULL,
+	.meter_enable = NULL,
+	.meter_disable = NULL,
+	.meter_profile_update = NULL,
+	.meter_dscp_table_update = NULL,
+	.policer_actions_update = NULL,
+	.stats_update = NULL,
+	.stats_read = NULL,
+};
+
+/**
+ * Get meter operations.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param arg
+ *   Pointer to set the mtr operations.
+ *
+ * @return
+ *   Always 0.
+ */
+int
+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;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 02/19] net/mlx5: fill meter capabilities using DevX
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 01/19] net/mlx5: add meter operation callback Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 03/19] net/mlx5: allocate flow meter registers Suanming Mou
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

This commit add the support of fill and get the meter capabilities
from DevX.

Support items:
1. The srTCM color bind mode.
2. Meter share with multiple flows.
3. Action drop.

The color aware mode and multiple meter chaining in a flow are not
supported.

New internal function in rte_mtr_ops callback:
1. capabilities_get()

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.c            |  6 ++++++
 drivers/net/mlx5/mlx5.h            | 13 +++++++++++
 drivers/net/mlx5/mlx5_devx_cmds.c  | 23 ++++++++++++++++++++
 drivers/net/mlx5/mlx5_flow_meter.c | 44 +++++++++++++++++++++++++++++++++++++-
 4 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index e244800..6705236 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2292,6 +2292,12 @@ struct mlx5_flow_id_pool *
 			DRV_LOG(DEBUG, "LRO session timeout set to %d usec",
 				config.lro.timeout);
 		}
+#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+		if (config.hca_attr.qos.sup && config.hca_attr.qos.srtcm_sup &&
+		    config.dv_flow_en) {
+			priv->mtr_en = 1;
+		}
+#endif
 	}
 	if (config.mprq.enabled && mprq) {
 		if (config.mprq.stride_num_n > mprq_max_stride_num_n ||
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index e219cbc..7ed69a7 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -167,6 +167,17 @@ struct mlx5_devx_mkey_attr {
 	uint32_t pd;
 };
 
+/* HCA qos attributes. */
+struct mlx5_hca_qos_attr {
+	uint32_t sup:1;	/* Whether QOS is supported. */
+	uint32_t srtcm_sup:1; /* Whether srTCM mode is supported. */
+	uint8_t log_max_flow_meter;
+	/* Power of the maximum supported meters. */
+	uint8_t flow_meter_reg_c_ids;
+	/* Bitmap of the reg_Cs available for flow meter to use. */
+
+};
+
 /* HCA supports this number of time periods for LRO. */
 #define MLX5_LRO_NUM_SUPP_PERIODS 4
 
@@ -193,6 +204,7 @@ struct mlx5_hca_attr {
 	uint32_t log_max_hairpin_wq_data_sz:5;
 	uint32_t log_max_hairpin_num_packets:5;
 	uint32_t vhca_id:16;
+	struct mlx5_hca_qos_attr qos;
 };
 
 /* Flow list . */
@@ -690,6 +702,7 @@ struct mlx5_priv {
 	unsigned int master:1; /* Device is a E-Switch master. */
 	unsigned int dr_shared:1; /* DV/DR data is shared. */
 	unsigned int counter_fallback:1; /* Use counter fallback management. */
+	unsigned int mtr_en:1; /* Whether support meter. */
 	uint16_t domain_id; /* Switch domain identifier. */
 	uint16_t vport_id; /* Associated VF vport index (if any). */
 	uint32_t vport_meta_tag; /* Used for vport index match ove VF LAG. */
diff --git a/drivers/net/mlx5/mlx5_devx_cmds.c b/drivers/net/mlx5/mlx5_devx_cmds.c
index d6e89b6..dcb7609 100644
--- a/drivers/net/mlx5/mlx5_devx_cmds.c
+++ b/drivers/net/mlx5/mlx5_devx_cmds.c
@@ -335,6 +335,29 @@ struct mlx5_devx_obj *
 	attr->log_max_hairpin_num_packets = MLX5_GET
 		(cmd_hca_cap, hcattr, log_min_hairpin_wq_data_sz);
 	attr->vhca_id = MLX5_GET(cmd_hca_cap, hcattr, vhca_id);
+	attr->qos.sup = MLX5_GET(cmd_hca_cap, hcattr, qos);
+	if (attr->qos.sup) {
+		MLX5_SET(query_hca_cap_in, in, op_mod,
+			 MLX5_GET_HCA_CAP_OP_MOD_QOS_CAP |
+			 MLX5_HCA_CAP_OPMOD_GET_CUR);
+		rc = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in),
+						 out, sizeof(out));
+		if (rc)
+			goto error;
+		if (status) {
+			DRV_LOG(DEBUG, "Failed to query devx QOS capabilities,"
+				" status %x, syndrome = %x",
+				status, syndrome);
+			return -1;
+		}
+		hcattr = MLX5_ADDR_OF(query_hca_cap_out, out, capability);
+		attr->qos.srtcm_sup =
+				MLX5_GET(qos_cap, hcattr, flow_meter_srtcm);
+		attr->qos.log_max_flow_meter =
+				MLX5_GET(qos_cap, hcattr, log_max_flow_meter);
+		attr->qos.flow_meter_reg_c_ids =
+			MLX5_GET(qos_cap, hcattr, flow_meter_reg_id);
+	}
 	attr->eth_net_offloads = MLX5_GET(cmd_hca_cap, hcattr,
 					  eth_net_offloads);
 	attr->eth_virt = MLX5_GET(cmd_hca_cap, hcattr, eth_virt);
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 6c7a005..9103b6d 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -8,9 +8,51 @@
 #include <rte_mtr_driver.h>
 
 #include "mlx5.h"
+#include "mlx5_flow.h"
+
+/**
+ * Callback to get MTR capabilities.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] cap
+ *   Pointer to save MTR capabilities.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
+		 struct rte_mtr_capabilities *cap,
+		 struct rte_mtr_error *error __rte_unused)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	memset(cap, 0, sizeof(*cap));
+	cap->n_max = 1 << qattr->log_max_flow_meter;
+	cap->n_shared_max = cap->n_max;
+	cap->identical = 1;
+	cap->shared_identical = 1;
+	cap->shared_n_flows_per_mtr_max = 4 << 20;
+	/* 2M flows can share the same meter. */
+	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
+	cap->meter_srtcm_rfc2697_n_max = qattr->srtcm_sup ? cap->n_max : 0;
+	cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
+	cap->policer_action_drop_supported = 1;
+	cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
+			  RTE_MTR_STATS_N_PKTS_DROPPED;
+	return 0;
+}
 
 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
-	.capabilities_get = NULL,
+	.capabilities_get = mlx5_flow_mtr_cap_get,
 	.meter_profile_add = NULL,
 	.meter_profile_delete = NULL,
 	.create = NULL,
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 03/19] net/mlx5: allocate flow meter registers
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 01/19] net/mlx5: add meter operation callback Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 02/19] net/mlx5: fill meter capabilities using DevX Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 04/19] net/mlx5: support meter profile operations Suanming Mou
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

Meter need the metadata REG_C to have the color match between the prefix
flow and the meter flow.

As the user define or metadata feature will both use the REG_C in the
suffix flow, the color match register meter uses will not impact the
register use in the later sub flow.

Another case is that tag is add before meter flow. In this case, meter
should not touch the register the tag action is using. To avoid that
case, meter should reserve the REG_C's used by user defined MLX5_APP_TAG.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.c      | 20 +++++++++++++++++++-
 drivers/net/mlx5/mlx5.h      |  2 ++
 drivers/net/mlx5/mlx5_flow.c | 45 ++++++++++++++++++++++++++++++++++++++------
 drivers/net/mlx5/mlx5_flow.h |  2 ++
 4 files changed, 62 insertions(+), 7 deletions(-)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 6705236..ebe748b 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2295,7 +2295,25 @@ struct mlx5_flow_id_pool *
 #if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
 		if (config.hca_attr.qos.sup && config.hca_attr.qos.srtcm_sup &&
 		    config.dv_flow_en) {
-			priv->mtr_en = 1;
+			uint8_t reg_c_mask =
+				config.hca_attr.qos.flow_meter_reg_c_ids;
+			/*
+			 * Meter needs two REG_C's for color match and pre-sfx
+			 * flow match. Here get the REG_C for color match.
+			 * REG_C_0 and REG_C_1 is reserved for metadata feature.
+			 */
+			reg_c_mask &= 0xfc;
+			if (__builtin_popcount(reg_c_mask) < 1) {
+				priv->mtr_en = 0;
+				DRV_LOG(WARNING, "No available register for"
+					" meter.");
+			} else {
+				priv->mtr_color_reg = ffs(reg_c_mask) - 1 +
+						      REG_C_0;
+				priv->mtr_en = 1;
+				DRV_LOG(DEBUG, "The REG_C meter uses is %d",
+					priv->mtr_color_reg);
+			}
 		}
 #endif
 	}
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 7ed69a7..650f2d1 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -750,6 +750,8 @@ struct mlx5_priv {
 	struct mlx5_flow_id_pool *qrss_id_pool;
 	struct mlx5_shtable_bucket mreg_cp_tbl[MLX5_FLOW_MREG_HTABLE_SZ];
 	/* Hash table of Rx metadata register copy table. */
+	uint8_t mtr_sfx_reg; /* Meter prefix-suffix flow match REG_C. */
+	uint8_t mtr_color_reg; /* Meter color match REG_C. */
 #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];
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 7e97b0b..e569b90 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -340,6 +340,7 @@ enum modify_reg
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_dev_config *config = &priv->config;
+	enum modify_reg start_reg;
 
 	switch (feature) {
 	case MLX5_HAIRPIN_RX:
@@ -371,21 +372,53 @@ enum modify_reg
 		}
 		break;
 	case MLX5_COPY_MARK:
-		return REG_C_2;
+	case MLX5_MTR_SFX:
+		/*
+		 * Metadata COPY_MARK register using is in meter suffix sub
+		 * flow while with meter. It's safe to share the same register.
+		 */
+		return priv->mtr_color_reg != REG_C_2 ? REG_C_2 : REG_C_3;
+	case MLX5_MTR_COLOR:
+		RTE_ASSERT(priv->mtr_color_reg < 8);
+		return priv->mtr_color_reg;
 	case MLX5_APP_TAG:
 		/*
-		 * Suppose engaging reg_c_2 .. reg_c_7 registers.
-		 * reg_c_2 is reserved for coloring by meters.
+		 * If meter is enable, it will engage two registers for color
+		 * match and flow match. If meter color match is not using the
+		 * REG_C_2, need to skip the REG_C_x be used by meter color
+		 * match.
+		 * If meter is disable, free to use all available registers.
 		 */
-		if (id > (REG_C_7 - REG_C_3))
+		if (priv->mtr_color_reg != REG_NONE)
+			start_reg = priv->mtr_color_reg != REG_C_2 ? REG_C_3 :
+				    REG_C_4;
+		else
+			start_reg = REG_C_2;
+		if (id > (REG_C_7 - start_reg))
 			return rte_flow_error_set(error, EINVAL,
 						  RTE_FLOW_ERROR_TYPE_ITEM,
 						  NULL, "invalid tag id");
-		if (config->flow_mreg_c[id + REG_C_3 - REG_C_0] == REG_NONE)
+		if (config->flow_mreg_c[id + start_reg - REG_C_0] == REG_NONE)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ITEM,
+						  NULL, "unsupported tag id");
+		/*
+		 * This case means meter is using the REG_C_x great than 2.
+		 * Take care not to conflict with meter color REG_C_x.
+		 * If the available index REG_C_y >= REG_C_x, skip the
+		 * color register.
+		 */
+		if (start_reg == REG_C_3 && config->flow_mreg_c
+		    [id + REG_C_3 - REG_C_0] >= priv->mtr_color_reg) {
+			if (config->flow_mreg_c[id + 1 + REG_C_3 - REG_C_0] !=
+			    REG_NONE)
+				return config->flow_mreg_c
+						[id + 1 + REG_C_3 - REG_C_0];
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ITEM,
 						  NULL, "unsupported tag id");
-		return config->flow_mreg_c[id + REG_C_3 - REG_C_0];
+		}
+		return config->flow_mreg_c[id + start_reg - REG_C_0];
 	}
 	assert(false);
 	return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ITEM,
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 1fa5fb9..1ca7dd9 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -74,6 +74,8 @@ enum mlx5_feature_name {
 	MLX5_FLOW_MARK,
 	MLX5_APP_TAG,
 	MLX5_COPY_MARK,
+	MLX5_MTR_COLOR,
+	MLX5_MTR_SFX,
 };
 
 /* Pattern outer Layer bits. */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 04/19] net/mlx5: support meter profile operations
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (2 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 03/19] net/mlx5: allocate flow meter registers Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 05/19] net/mlx5: validate meter profile Suanming Mou
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

This commit add the support of meter profile add and delete operations.

New internal functions in rte_mtr_ops callback:
1. meter_profile_add()
2. meter_profile_delete()

Only RTE_MTR_SRTCM_RFC2697 algorithm is supported and can be added. To
add other algorithm will report an error.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/Makefile          |   1 +
 drivers/net/mlx5/mlx5.c            |   1 +
 drivers/net/mlx5/mlx5.h            |   4 +
 drivers/net/mlx5/mlx5_flow.h       |  29 +++++
 drivers/net/mlx5/mlx5_flow_meter.c | 245 ++++++++++++++++++++++++++++++++++++-
 5 files changed, 278 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index c60f97c..e8d6195 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -63,6 +63,7 @@ LDLIBS += $(shell $(RTE_SDK)/buildtools/options-ibverbs-static.sh)
 else
 LDLIBS += -libverbs -lmlx5
 endif
+LDLIBS += -lm
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index ebe748b..7958067 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2405,6 +2405,7 @@ struct mlx5_flow_id_pool *
 		mlx5_nl_mac_addr_sync(eth_dev);
 	TAILQ_INIT(&priv->flows);
 	TAILQ_INIT(&priv->ctrl_flows);
+	TAILQ_INIT(&priv->flow_meter_profiles);
 	/* Hint libmlx5 to use PMD allocator for data plane resources */
 	struct mlx5dv_ctx_allocators alctr = {
 		.alloc = &mlx5_alloc_verbs_buf,
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 650f2d1..b1d5341 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -682,6 +682,9 @@ struct mlx5_proc_priv {
 	/* Table of UAR registers for each process. */
 };
 
+/* MTR profile list. */
+TAILQ_HEAD(mlx5_mtr_profiles, mlx5_flow_meter_profile);
+
 #define MLX5_PROC_PRIV(port_id) \
 	((struct mlx5_proc_priv *)rte_eth_devices[port_id].process_private)
 
@@ -752,6 +755,7 @@ struct mlx5_priv {
 	/* Hash table of Rx metadata register copy table. */
 	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. */
 #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];
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 1ca7dd9..922d6b6 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -23,6 +23,7 @@
 
 #include <rte_atomic.h>
 #include <rte_alarm.h>
+#include <rte_mtr.h>
 
 #include "mlx5.h"
 #include "mlx5_prm.h"
@@ -522,6 +523,34 @@ struct mlx5_flow {
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
+#define MLX5_MAN_WIDTH 8
+
+/* RFC2697 parameter structure. */
+struct mlx5_flow_meter_srtcm_rfc2697_prm {
+	/* green_saturation_value = cbs_mantissa * 2^cbs_exponent */
+	uint32_t cbs_exponent:5;
+	uint32_t cbs_mantissa:8;
+	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent) Bytes/Sec */
+	uint32_t cir_exponent:5;
+	uint32_t cir_mantissa:8;
+	/* yellow _saturation_value = ebs_mantissa * 2^ebs_exponent */
+	uint32_t ebs_exponent:5;
+	uint32_t ebs_mantissa:8;
+};
+
+/* Flow meter profile structure. */
+struct mlx5_flow_meter_profile {
+	TAILQ_ENTRY(mlx5_flow_meter_profile) next;
+	/**< Pointer to the next flow meter structure. */
+	uint32_t meter_profile_id; /**< Profile id. */
+	struct rte_mtr_meter_profile profile; /**< Profile detail. */
+	union {
+		struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm_prm;
+		/**< srtcm_rfc2697 struct. */
+	};
+	uint32_t ref_cnt; /**< Use count. */
+};
+
 /* Flow structure. */
 struct rte_flow {
 	TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 9103b6d..b11962f 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -4,6 +4,7 @@
  */
 #include <math.h>
 
+#include <rte_malloc.h>
 #include <rte_mtr.h>
 #include <rte_mtr_driver.h>
 
@@ -11,6 +12,150 @@
 #include "mlx5_flow.h"
 
 /**
+ * Find meter profile by id.
+ *
+ * @param priv
+ *   Pointer to mlx5_priv.
+ * @param meter_profile_id
+ *   Meter profile id.
+ *
+ * @return
+ *   Pointer to the profile found on success, NULL otherwise.
+ */
+static struct mlx5_flow_meter_profile *
+mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
+{
+	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
+	struct mlx5_flow_meter_profile *fmp;
+
+	TAILQ_FOREACH(fmp, fmps, next)
+		if (meter_profile_id == fmp->meter_profile_id)
+			return fmp;
+	return NULL;
+}
+
+/**
+ * Calculate mantissa and exponent for cir.
+ *
+ * @param[in] cir
+ *   Value to be calculated.
+ * @param[out] man
+ *   Pointer to the mantissa.
+ * @param[out] exp
+ *   Pointer to the exp.
+ */
+static void
+mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
+{
+	int64_t _cir;
+	int64_t delta = INT64_MAX;
+	uint8_t _man = 0;
+	uint8_t _exp = 0;
+	uint64_t m, e;
+
+	for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
+		for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
+			_cir = (1000000000ULL * m) >> e;
+			if (llabs(cir - _cir) <= delta) {
+				delta = llabs(cir - _cir);
+				_man = m;
+				_exp = e;
+			}
+		}
+	}
+	*man = _man;
+	*exp = _exp;
+}
+
+/**
+ * Calculate mantissa and exponent for xbs.
+ *
+ * @param[in] xbs
+ *   Value to be calculated.
+ * @param[out] man
+ *   Pointer to the mantissa.
+ * @param[out] exp
+ *   Pointer to the exp.
+ */
+static void
+mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
+{
+	int _exp;
+	double _man;
+
+	/* Special case xbs == 0 ? both exp and matissa are 0. */
+	if (xbs == 0) {
+		*man = 0;
+		*exp = 0;
+		return;
+	}
+	/* xbs = xbs_mantissa * 2^xbs_exponent */
+	_man = frexp(xbs, &_exp);
+	_man = _man * pow(2, MLX5_MAN_WIDTH);
+	_exp = _exp - MLX5_MAN_WIDTH;
+	*man = (uint8_t)ceil(_man);
+	*exp = _exp;
+}
+
+/**
+ * Fill the prm meter parameter.
+ *
+ * @param[in,out] fmp
+ *   Pointer to meter profie to be converted.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
+	uint8_t man, exp;
+
+	if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_PROFILE,
+				NULL, "Metering algorithm not supported.");
+	 /* cbs = cbs_mantissa * 2^cbs_exponent */
+	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
+				    &man, &exp);
+	srtcm->cbs_mantissa = man;
+	srtcm->cbs_exponent = exp;
+	/* Check if cbs mantissa is too large. */
+	if (srtcm->cbs_exponent != exp)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+					  "Metering profile parameter cbs is"
+					  " invalid.");
+	/* ebs = ebs_mantissa * 2^ebs_exponent */
+	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
+				    &man, &exp);
+	srtcm->ebs_mantissa = man;
+	srtcm->ebs_exponent = exp;
+	/* Check if ebs mantissa is too large. */
+	if (srtcm->ebs_exponent != exp)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+					  "Metering profile parameter ebs is"
+					  " invalid.");
+	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
+	mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
+				    &man, &exp);
+	srtcm->cir_mantissa = man;
+	srtcm->cir_exponent = exp;
+	/* Check if cir mantissa is too large. */
+	if (srtcm->cir_exponent != exp)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+					  "Metering profile parameter cir is"
+					  " invalid.");
+	return 0;
+}
+
+/**
  * Callback to get MTR capabilities.
  *
  * @param[in] dev
@@ -51,10 +196,106 @@
 	return 0;
 }
 
+/**
+ * Callback to add MTR profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_profile_id
+ *   Meter profile id.
+ * @param[in] profile
+ *   Pointer to meter profile detail.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
+		       uint32_t meter_profile_id,
+		       struct rte_mtr_meter_profile *profile,
+		       struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
+	struct mlx5_flow_meter_profile *fmp;
+	int ret;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	/* Meter profile memory allocation. */
+	fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile),
+			 RTE_CACHE_LINE_SIZE);
+	if (fmp == NULL)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Meter profile memory "
+					  "alloc failed.");
+	/* Fill profile info. */
+	fmp->meter_profile_id = meter_profile_id;
+	fmp->profile = *profile;
+	/* Fill the flow meter parameters for the PRM. */
+	ret = mlx5_flow_meter_param_fill(fmp, error);
+	if (ret)
+		goto error;
+	/* Add to list. */
+	TAILQ_INSERT_TAIL(fmps, fmp, next);
+	return 0;
+error:
+	rte_free(fmp);
+	return ret;
+}
+
+/**
+ * Callback to delete MTR profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_profile_id
+ *   Meter profile id.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
+			  uint32_t meter_profile_id,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_profile *fmp;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	/* Meter profile must exist. */
+	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
+	if (fmp == NULL)
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  &meter_profile_id,
+					  "Meter profile id invalid.");
+	/* Check profile is unused. */
+	if (fmp->ref_cnt)
+		return -rte_mtr_error_set(error, EBUSY,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Meter profile in use.");
+	/* Remove from list. */
+	TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
+	rte_free(fmp);
+	return 0;
+}
+
 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.capabilities_get = mlx5_flow_mtr_cap_get,
-	.meter_profile_add = NULL,
-	.meter_profile_delete = NULL,
+	.meter_profile_add = mlx5_flow_meter_profile_add,
+	.meter_profile_delete = mlx5_flow_meter_profile_delete,
 	.create = NULL,
 	.destroy = NULL,
 	.meter_enable = NULL,
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 05/19] net/mlx5: validate meter profile
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (3 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 04/19] net/mlx5: support meter profile operations Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 06/19] net/mlx5: prepare meter flow tables Suanming Mou
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

The add meter profile should be validated if it is valid or has been add
to the list. Invalid and exist profile should not be add to the list.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_meter.c | 70 ++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_prm.h        |  5 +++
 2 files changed, 75 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index b11962f..5ad5e14 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -35,6 +35,71 @@
 }
 
 /**
+ * Validate the MTR profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_profile_id
+ *   Meter profile id.
+ * @param[in] profile
+ *   Pointer to meter profile detail.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
+				 uint32_t meter_profile_id,
+				 struct rte_mtr_meter_profile *profile,
+				 struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_profile *fmp;
+
+	/* Profile must not be NULL. */
+	if (profile == NULL)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE,
+					  NULL, "Meter profile is null.");
+	/* Meter profile ID must be valid. */
+	if (meter_profile_id == UINT32_MAX)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Meter profile id not valid.");
+	/* Meter profile must not exist. */
+	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
+	if (fmp)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL,
+					  "Meter profile already exists.");
+	if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
+		if (priv->config.hca_attr.qos.srtcm_sup) {
+			/* Verify support for flow meter parameters. */
+			if (profile->srtcm_rfc2697.cir > 0 &&
+			    profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX &&
+			    profile->srtcm_rfc2697.cbs > 0 &&
+			    profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX &&
+			    profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX)
+				return 0;
+			else
+				return -rte_mtr_error_set
+					     (error, ENOTSUP,
+					      RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					      NULL,
+					      profile->srtcm_rfc2697.ebs ?
+					      "Metering value ebs must be 0." :
+					      "Invalid metering parameters.");
+		}
+	}
+	return -rte_mtr_error_set(error, ENOTSUP,
+				  RTE_MTR_ERROR_TYPE_METER_PROFILE,
+				  NULL, "Metering algorithm not supported.");
+}
+
+/**
  * Calculate mantissa and exponent for cir.
  *
  * @param[in] cir
@@ -226,6 +291,11 @@
 		return -rte_mtr_error_set(error, ENOTSUP,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not support");
+	/* Check input params. */
+	ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
+					       profile, error);
+	if (ret)
+		return ret;
 	/* Meter profile memory allocation. */
 	fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile),
 			 RTE_CACHE_LINE_SIZE);
diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h
index a0c37c8..3ebf191 100644
--- a/drivers/net/mlx5/mlx5_prm.h
+++ b/drivers/net/mlx5/mlx5_prm.h
@@ -1768,6 +1768,11 @@ struct mlx5_mini_cqe8 {
 	uint32_t byte_cnt;
 };
 
+/* Maximum value of srTCM metering parameters. */
+#define MLX5_SRTCM_CBS_MAX (0xFF * (1ULL << 0x1F))
+#define MLX5_SRTCM_CIR_MAX (8 * (1ULL << 30) * 0xFF)
+#define MLX5_SRTCM_EBS_MAX 0
+
 /**
  * Convert a user mark to flow mark.
  *
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 06/19] net/mlx5: prepare meter flow tables
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (4 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 05/19] net/mlx5: validate meter profile Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 07/19] net/mlx5: add policer rules operations Suanming Mou
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

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(+)

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)
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 07/19] net/mlx5: add policer rules operations
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (5 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 06/19] net/mlx5: prepare meter flow tables Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 08/19] net/mlx5: support basic meter operations Suanming Mou
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

This commit create the color rules on the meter table for the packets.

As the prefix flow with meter action colors the packets, the packets
are transferred to the meter table with meter color match flows. Here
we create the flow rules  with green yellow red actions on the meter
table. Packets match the color will be processed by the related color
flow rule.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c    |  46 ++++++++++
 drivers/net/mlx5/mlx5_flow.h    |  18 ++++
 drivers/net/mlx5/mlx5_flow_dv.c | 187 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 245 insertions(+), 6 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 6dcdb32..9824b93 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4913,6 +4913,52 @@ struct mlx5_meter_domains_infos *
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
+/**
+ * Create policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter *fm,
+			       const struct rte_flow_attr *attr)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policer_rules(dev, fm, attr);
+}
+
+/**
+ * Destroy policer rules.
+ *
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter *fm,
+				const struct rte_flow_attr *attr)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->destroy_policer_rules(dev, fm, attr);
+}
+
 #define MLX5_POOL_QUERY_FREQ_US 1000000
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 14d437b..ca0a98d 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -559,6 +559,8 @@ struct mlx5_meter_domains_infos {
 struct mlx5_flow_meter {
 	uint32_t meter_id;
 	/**< Meter id. */
+	struct rte_mtr_params params;
+	/**< Meter rule parameters. */
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
 	uint32_t ref_cnt;
@@ -636,6 +638,14 @@ typedef int (*mlx5_flow_query_t)(struct rte_eth_dev *dev,
 					    (struct rte_eth_dev *dev);
 typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 					struct mlx5_meter_domains_infos *tbls);
+typedef int (*mlx5_flow_create_policer_rules_t)
+					(struct rte_eth_dev *dev,
+					 struct mlx5_flow_meter *fm,
+					 const struct rte_flow_attr *attr);
+typedef int (*mlx5_flow_destroy_policer_rules_t)
+					(struct rte_eth_dev *dev,
+					 const struct mlx5_flow_meter *fm,
+					 const struct rte_flow_attr *attr);
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
 	mlx5_flow_prepare_t prepare;
@@ -646,6 +656,8 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_query_t query;
 	mlx5_flow_create_mtr_tbls_t create_mtr_tbls;
 	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
+	mlx5_flow_create_policer_rules_t create_policer_rules;
+	mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
 };
 
 
@@ -772,4 +784,10 @@ 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);
+int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
+				   struct mlx5_flow_meter *fm,
+				   const struct rte_flow_attr *attr);
+int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
+				    struct mlx5_flow_meter *fm,
+				    const struct rte_flow_attr *attr);
 #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 75ba133..d6e4e45 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7611,6 +7611,9 @@ struct field_modify_info modify_tcp[] = {
 	return 0;
 }
 
+/* Number of meter flow actions, count and jump or count and drop. */
+#define METER_ACTIONS 2
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -7648,12 +7651,6 @@ struct field_modify_info modify_tcp[] = {
 		.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;
@@ -7783,6 +7780,182 @@ struct field_modify_info modify_tcp[] = {
 	return NULL;
 }
 
+/**
+ * Destroy domain policer rule.
+ *
+ * @param[in] dt
+ *   Pointer to domain table.
+ */
+static void
+flow_dv_destroy_domain_policer_rule(struct mlx5_meter_domain_info *dt)
+{
+	int i;
+
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		if (dt->policer_rules[i]) {
+			claim_zero(mlx5_glue->dv_destroy_flow
+				  (dt->policer_rules[i]));
+			dt->policer_rules[i] = NULL;
+		}
+	}
+	if (dt->jump_actn) {
+		claim_zero(mlx5_glue->destroy_flow_action(dt->jump_actn));
+		dt->jump_actn = NULL;
+	}
+}
+
+/**
+ * Destroy policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,
+			      const struct mlx5_flow_meter *fm,
+			      const struct rte_flow_attr *attr)
+{
+	struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
+
+	if (!mtb)
+		return 0;
+	if (attr->egress)
+		flow_dv_destroy_domain_policer_rule(&mtb->egress);
+	if (attr->ingress)
+		flow_dv_destroy_domain_policer_rule(&mtb->ingress);
+	if (attr->transfer)
+		flow_dv_destroy_domain_policer_rule(&mtb->transfer);
+	return 0;
+}
+
+/**
+ * Create specify domain meter policer rule.
+ *
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] mtb
+ *   Pointer to DV meter table set.
+ * @param[in] sfx_tb
+ *   Pointer to suffix table.
+ * @param[in] mtr_reg_c
+ *   Color match REG_C.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
+				    struct mlx5_meter_domain_info *dtb,
+				    struct mlx5_flow_tbl_resource *sfx_tb,
+				    uint8_t mtr_reg_c)
+{
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf),
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf),
+	};
+	struct mlx5_meter_domains_infos *mtb = fm->mfts;
+	void *actions[METER_ACTIONS];
+	int i;
+
+	/* Create jump action. */
+	if (!sfx_tb)
+		return -1;
+	if (!dtb->jump_actn)
+		dtb->jump_actn =
+			mlx5_glue->dr_create_flow_action_dest_flow_tbl
+							(sfx_tb->obj);
+	if (!dtb->jump_actn) {
+		DRV_LOG(ERR, "Failed to create policer jump action.");
+		goto error;
+	}
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		int j = 0;
+
+		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,
+				       rte_col_2_mlx5_col(i), UINT32_MAX);
+		if (fm->params.action[i] == MTR_POLICER_ACTION_DROP)
+			actions[j++] = mtb->drop_actn;
+		else
+			actions[j++] = dtb->jump_actn;
+		dtb->policer_rules[i] =
+			mlx5_glue->dv_create_flow(dtb->color_matcher,
+						 (void *)&value,
+						  j, actions);
+		if (!dtb->policer_rules[i]) {
+			DRV_LOG(ERR, "Failed to create policer rule.");
+			goto error;
+		}
+	}
+	return 0;
+error:
+	rte_errno = errno;
+	return -1;
+}
+
+/**
+ * Create policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter *fm,
+			     const struct rte_flow_attr *attr)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_domains_infos *mtb = fm->mfts;
+	int ret;
+
+	if (attr->egress) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->egress,
+						priv->sh->tx_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create egress policer.");
+			goto error;
+		}
+	}
+	if (attr->ingress) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->ingress,
+						priv->sh->rx_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create ingress policer.");
+			goto error;
+		}
+	}
+	if (attr->transfer) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->transfer,
+						priv->sh->fdb_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create transfer policer.");
+			goto error;
+		}
+	}
+	return 0;
+error:
+	flow_dv_destroy_policer_rules(dev, fm, attr);
+	return -1;
+}
+
 /*
  * Mutex-protected thunk to lock-free  __flow_dv_translate().
  */
@@ -7850,6 +8023,8 @@ struct field_modify_info modify_tcp[] = {
 	.query = flow_dv_query,
 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
+	.create_policer_rules = flow_dv_create_policer_rules,
+	.destroy_policer_rules = flow_dv_destroy_policer_rules,
 };
 
 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 08/19] net/mlx5: support basic meter operations
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (6 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 07/19] net/mlx5: add policer rules operations Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 09/19] net/mlx5: add meter action creation to the glue Suanming Mou
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

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>
---
 drivers/net/mlx5/mlx5.c            |   1 +
 drivers/net/mlx5/mlx5.h            |   5 +
 drivers/net/mlx5/mlx5_flow.h       |   8 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 242 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 254 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 7958067..1a2fef6 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2405,6 +2405,7 @@ struct mlx5_flow_id_pool *
 		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 = {
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 58bd7d0..35abb3f 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -692,6 +692,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)
@@ -764,6 +766,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];
@@ -1029,5 +1032,7 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_tis
 /* 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_ */
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index ca0a98d..e7bd787 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -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. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 5ad5e14..76a3180 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -362,12 +362,227 @@
 	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 @@
 	*(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;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 09/19] net/mlx5: add meter action creation to the glue
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (7 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 08/19] net/mlx5: support basic meter operations Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 10/19] net/mlx5: support meter modification operations Suanming Mou
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

This commit add the meter action creation to the glue code.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_glue.c | 30 ++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h |  9 +++++++++
 2 files changed, 39 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c
index 58c9a82..15197cf 100644
--- a/drivers/net/mlx5/mlx5_glue.c
+++ b/drivers/net/mlx5/mlx5_glue.c
@@ -765,6 +765,34 @@
 	return NULL;
 }
 
+static void *
+mlx5_glue_dv_create_flow_action_meter(struct mlx5dv_dr_flow_meter_attr *attr)
+{
+#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+	return mlx5dv_dr_action_create_flow_meter(attr);
+#else
+	(void)attr;
+	errno = ENOTSUP;
+	return NULL;
+#endif
+}
+
+static int
+mlx5_glue_dv_modify_flow_action_meter(void *action,
+				      struct mlx5dv_dr_flow_meter_attr *attr,
+				      uint64_t modify_bits)
+{
+#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+	return mlx5dv_dr_action_modify_flow_meter(action, attr, modify_bits);
+#else
+	(void)action;
+	(void)attr;
+	(void)modify_bits;
+	errno = ENOTSUP;
+	return errno;
+#endif
+}
+
 static int
 mlx5_glue_dv_destroy_flow(void *flow_id)
 {
@@ -1084,6 +1112,8 @@
 	.dv_create_flow_action_packet_reformat =
 		mlx5_glue_dv_create_flow_action_packet_reformat,
 	.dv_create_flow_action_tag =  mlx5_glue_dv_create_flow_action_tag,
+	.dv_create_flow_action_meter = mlx5_glue_dv_create_flow_action_meter,
+	.dv_modify_flow_action_meter = mlx5_glue_dv_modify_flow_action_meter,
 	.dv_destroy_flow = mlx5_glue_dv_destroy_flow,
 	.dv_destroy_flow_matcher = mlx5_glue_dv_destroy_flow_matcher,
 	.dv_open_device = mlx5_glue_dv_open_device,
diff --git a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h
index 7fa8349..7ad6379 100644
--- a/drivers/net/mlx5/mlx5_glue.h
+++ b/drivers/net/mlx5/mlx5_glue.h
@@ -52,6 +52,7 @@
 struct mlx5dv_flow_matcher_attr;
 struct mlx5dv_flow_action_attr;
 struct mlx5dv_flow_match_parameters;
+struct mlx5dv_dr_flow_meter_attr;
 struct ibv_flow_action;
 enum mlx5dv_flow_action_packet_reformat_type { packet_reformat_type = 0, };
 enum mlx5dv_flow_table_type { flow_table_type = 0, };
@@ -80,6 +81,10 @@
 struct mlx5dv_devx_port;
 #endif
 
+#ifndef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
+struct mlx5dv_dr_flow_meter_attr;
+#endif
+
 /* LIB_GLUE_VERSION must be updated every time this structure is modified. */
 struct mlx5_glue {
 	const char *version;
@@ -209,6 +214,10 @@ struct mlx5_glue {
 		 struct mlx5dv_dr_domain *domain,
 		 uint32_t flags, size_t data_sz, void *data);
 	void *(*dv_create_flow_action_tag)(uint32_t tag);
+	void *(*dv_create_flow_action_meter)
+		(struct mlx5dv_dr_flow_meter_attr *attr);
+	int (*dv_modify_flow_action_meter)(void *action,
+		struct mlx5dv_dr_flow_meter_attr *attr, uint64_t modify_bits);
 	int (*dv_destroy_flow)(void *flow);
 	int (*dv_destroy_flow_matcher)(void *matcher);
 	struct ibv_context *(*dv_open_device)(struct ibv_device *device);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 10/19] net/mlx5: support meter modification operations
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (8 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 09/19] net/mlx5: add meter action creation to the glue Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 11/19] net/mlx5: support meter profile update Suanming Mou
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

This commit add meter enable and disable supoort.

New internal functions in rte_mtr_ops callback:
1. meter_enable()
2. meter_disable()

The meter_enable() enables the meter action and the meter_disable()
disables the meter action.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.h       |  10 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 232 ++++++++++++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_prm.h        |  32 +++++
 3 files changed, 272 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index e7bd787..c613019 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -523,6 +523,10 @@ struct mlx5_flow {
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
+/* Flow meter state. */
+#define MLX5_FLOW_METER_DISABLE 0
+#define MLX5_FLOW_METER_ENABLE 1
+
 #define MLX5_MAN_WIDTH 8
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
@@ -553,6 +557,12 @@ struct mlx5_meter_domains_infos {
 	/**< FDB meter table. */
 	void *drop_actn;
 	/**< Drop action as not matched. */
+	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
+	/**< Flow meter parameter. */
+	size_t fmp_size;
+	/**< Flow meter parameter size. */
+	void *meter_action;
+	/**< Flow meter action. */
 };
 
 /* Meter parameter structure. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 76a3180..7efb669 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -443,6 +443,102 @@
 }
 
 /**
+ * Modify the flow meter action.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5 private data structure.
+ * @param[in] fm
+ *   Pointer to flow meter to be modified.
+ * @param[in] srtcm
+ *   Pointer to meter srtcm description parameter.
+ * @param[in] modify_bits
+ *   The bit in srtcm to be updated.
+ * @param[in] active_state
+ *   The state to be updated.
+ * @return
+ *   0 on success, o negative value otherwise.
+ */
+static int
+mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
+		struct mlx5_flow_meter *fm,
+		const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
+		uint64_t modify_bits, uint32_t active_state)
+{
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
+	uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
+	uint32_t *attr;
+	struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
+	int ret;
+
+	/* Fill command parameters. */
+	mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
+	mod_attr.flow_meter_parameter = in;
+	mod_attr.flow_meter_parameter_sz = fm->mfts->fmp_size;
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
+		mod_attr.active = !!active_state;
+	else
+		mod_attr.active = 0;
+	attr = in;
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_exponent, srtcm->cbs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_mantissa, srtcm->cbs_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_exponent, srtcm->cir_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_mantissa, srtcm->cir_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_exponent, srtcm->ebs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_mantissa, srtcm->ebs_mantissa);
+	}
+	/* Apply modifications to meter only if it was created. */
+	if (fm->mfts->meter_action) {
+		ret = mlx5_glue->dv_modify_flow_action_meter
+					(fm->mfts->meter_action, &mod_attr,
+					rte_cpu_to_be_64(modify_bits));
+		if (ret)
+			return ret;
+	}
+	/* Update succeedded modify meter parameters. */
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
+		fm->active_state = !!active_state;
+	attr = fm->mfts->fmp;
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_exponent, srtcm->cbs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_mantissa, srtcm->cbs_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_exponent, srtcm->cir_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_mantissa, srtcm->cir_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_exponent, srtcm->ebs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_mantissa, srtcm->ebs_mantissa);
+	}
+
+	return 0;
+#else
+	(void)fm;
+	(void)srtcm;
+	(void)modify_bits;
+	(void)active_state;
+	return -ENOTSUP;
+#endif
+}
+
+/**
  * Create meter rules.
  *
  * @param[in] dev
@@ -577,14 +673,146 @@
 	return 0;
 }
 
+/**
+ * Modify meter state.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5 private data structure.
+ * @param[in] fm
+ *   Pointer to flow meter.
+ * @param[in] new_state
+ *   New state to update.
+ * @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_modify_state(struct mlx5_priv *priv,
+			     struct mlx5_flow_meter *fm,
+			     uint32_t new_state,
+			     struct rte_mtr_error *error)
+{
+	static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
+		.cbs_exponent = 20,
+		.cbs_mantissa = 191,
+		.cir_exponent = 0,
+		.cir_mantissa = 200,
+		.ebs_exponent = 0,
+		.ebs_mantissa = 0,
+	};
+	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
+			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
+	int ret;
+
+	if (new_state == MLX5_FLOW_METER_DISABLE)
+		ret = mlx5_flow_meter_action_modify(priv, fm, &srtcm,
+						    modify_bits, 0);
+	else
+		ret = mlx5_flow_meter_action_modify(priv, fm,
+						   &fm->profile->srtcm_prm,
+						    modify_bits, 0);
+	if (ret)
+		return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL,
+					  new_state ?
+					  "Failed to enable meter." :
+					  "Failed to disable meter.");
+	return 0;
+}
+
+/**
+ * Callback to enable flow meter.
+ *
+ * @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_enable(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_meter *fm;
+	int ret;
+
+	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 not found.");
+	if (fm->active_state == MLX5_FLOW_METER_ENABLE)
+		return 0;
+	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
+					   error);
+	if (!ret)
+		fm->active_state = MLX5_FLOW_METER_ENABLE;
+	return ret;
+}
+
+/**
+ * Callback to disable flow meter.
+ *
+ * @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_disable(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_meter *fm;
+	int ret;
+
+	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 not found.");
+	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
+		return 0;
+	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
+					   error);
+	if (!ret)
+		fm->active_state = MLX5_FLOW_METER_DISABLE;
+	return ret;
+}
+
 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 = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
-	.meter_enable = NULL,
-	.meter_disable = NULL,
+	.meter_enable = mlx5_flow_meter_enable,
+	.meter_disable = mlx5_flow_meter_disable,
 	.meter_profile_update = NULL,
 	.meter_dscp_table_update = NULL,
 	.policer_actions_update = NULL,
diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h
index ebedc90..651006b 100644
--- a/drivers/net/mlx5/mlx5_prm.h
+++ b/drivers/net/mlx5/mlx5_prm.h
@@ -1745,6 +1745,38 @@ struct mlx5_ifc_create_sq_in_bits {
 	struct mlx5_ifc_sqc_bits ctx;
 };
 
+enum {
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE = (1ULL << 0),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS = (1ULL << 1),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR = (1ULL << 2),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS = (1ULL << 3),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EIR = (1ULL << 4),
+};
+
+struct mlx5_ifc_flow_meter_parameters_bits {
+	u8         valid[0x1];			// 00h
+	u8         bucket_overflow[0x1];
+	u8         start_color[0x2];
+	u8         both_buckets_on_green[0x1];
+	u8         meter_mode[0x2];
+	u8         reserved_at_1[0x19];
+	u8         reserved_at_2[0x20]; //04h
+	u8         reserved_at_3[0x3];
+	u8         cbs_exponent[0x5];		// 08h
+	u8         cbs_mantissa[0x8];
+	u8         reserved_at_4[0x3];
+	u8         cir_exponent[0x5];
+	u8         cir_mantissa[0x8];
+	u8         reserved_at_5[0x20];		// 0Ch
+	u8         reserved_at_6[0x3];
+	u8         ebs_exponent[0x5];		// 10h
+	u8         ebs_mantissa[0x8];
+	u8         reserved_at_7[0x3];
+	u8         eir_exponent[0x5];
+	u8         eir_mantissa[0x8];
+	u8         reserved_at_8[0x60];		// 14h-1Ch
+};
+
 /* CQE format mask. */
 #define MLX5E_CQE_FORMAT_MASK 0xc
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 11/19] net/mlx5: support meter profile update
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (9 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 10/19] net/mlx5: support meter modification operations Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 12/19] net/mlx5: expose flow counters management Suanming Mou
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

This commit add the meter profile update support.

New internal function in rte_mtr_ops callback:
1. meter_profile_update()

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_meter.c | 70 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 7efb669..20a57b5 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -805,6 +805,74 @@
 	return ret;
 }
 
+/**
+ * Callback to update meter profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[in] meter_profile_id
+ *   To be updated meter profile 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_profile_update(struct rte_eth_dev *dev,
+			       uint32_t meter_id,
+			       uint32_t meter_profile_id,
+			       struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_flow_meter_profile *old_fmp;
+	struct mlx5_flow_meter *fm;
+	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
+			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
+	int ret;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	/* Meter profile must exist. */
+	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
+	if (fmp == NULL)
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Meter profile not found.");
+	/* 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 not found.");
+	/* MTR object already set to meter profile id. */
+	old_fmp = fm->profile;
+	if (fmp == old_fmp)
+		return 0;
+	/* Update the profile. */
+	fm->profile = fmp;
+	/* Update meter params in HW (if not disabled). */
+	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
+		return 0;
+	ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
+					      modify_bits, fm->active_state);
+	if (ret) {
+		fm->profile = old_fmp;
+		return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL, "Failed to update meter"
+					  " parmeters in hardware.");
+	}
+	old_fmp->ref_cnt--;
+	fmp->ref_cnt++;
+	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,
@@ -813,7 +881,7 @@
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
-	.meter_profile_update = NULL,
+	.meter_profile_update = mlx5_flow_meter_profile_update,
 	.meter_dscp_table_update = NULL,
 	.policer_actions_update = NULL,
 	.stats_update = NULL,
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 12/19] net/mlx5: expose flow counters management
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (10 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 11/19] net/mlx5: support meter profile update Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 13/19] net/mlx5: add count action to meter Suanming Mou
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

Expose the flow counter management mechanism for other components to
use.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.h         |  4 ++
 drivers/net/mlx5/mlx5_flow.c    | 83 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_flow.h    | 11 ++++++
 drivers/net/mlx5/mlx5_flow_dv.c | 68 +++++++++++++++++++++++++++++++++
 4 files changed, 166 insertions(+)

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 35abb3f..2e35f00 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -957,6 +957,10 @@ void mlx5_flow_async_pool_query_handle(struct mlx5_ibv_shared *sh,
 				       uint64_t async_id, int status);
 void mlx5_set_query_alarm(struct mlx5_ibv_shared *sh);
 void mlx5_flow_query_alarm(void *arg);
+struct mlx5_flow_counter *mlx5_counter_alloc(struct rte_eth_dev *dev);
+void mlx5_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt);
+int mlx5_counter_query(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt,
+		       bool clear, uint64_t *pkts, uint64_t *bytes);
 
 /* mlx5_mp.c */
 void mlx5_mp_req_start_rxtx(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 9824b93..88590a1 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4959,6 +4959,89 @@ struct mlx5_meter_domains_infos *
 	return fops->destroy_policer_rules(dev, fm, attr);
 }
 
+/**
+ * Allocate a counter.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   Pointer to allocated counter  on success, NULL otherwise.
+ */
+struct mlx5_flow_counter *
+mlx5_counter_alloc(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+	struct rte_flow_attr attr = { .transfer = 0 };
+
+	if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) {
+		fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+		return fops->counter_alloc(dev);
+	}
+	DRV_LOG(ERR,
+		"port %u counter allocate is not supported.",
+		 dev->data->port_id);
+	return NULL;
+}
+
+/**
+ * Free a counter.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device structure.
+ * @param[in] cnt
+ *   Pointer to counter to be free.
+ */
+void
+mlx5_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt)
+{
+	const struct mlx5_flow_driver_ops *fops;
+	struct rte_flow_attr attr = { .transfer = 0 };
+
+	if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) {
+		fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+		fops->counter_free(dev, cnt);
+		return;
+	}
+	DRV_LOG(ERR,
+		"port %u counter free is not supported.",
+		 dev->data->port_id);
+}
+
+/**
+ * Query counter statistics.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device structure.
+ * @param[in] cnt
+ *   Pointer to counter to query.
+ * @param[in] clear
+ *   Set to clear counter statistics.
+ * @param[out] pkts
+ *   The counter hits packets number to save.
+ * @param[out] bytes
+ *   The counter hits bytes number to save.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+mlx5_counter_query(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt,
+		   bool clear, uint64_t *pkts, uint64_t *bytes)
+{
+	const struct mlx5_flow_driver_ops *fops;
+	struct rte_flow_attr attr = { .transfer = 0 };
+
+	if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) {
+		fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+		return fops->counter_query(dev, cnt, clear, pkts, bytes);
+	}
+	DRV_LOG(ERR,
+		"port %u counter query is not supported.",
+		 dev->data->port_id);
+	return -ENOTSUP;
+}
+
 #define MLX5_POOL_QUERY_FREQ_US 1000000
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index c613019..0004227 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -664,6 +664,14 @@ typedef int (*mlx5_flow_destroy_policer_rules_t)
 					(struct rte_eth_dev *dev,
 					 const struct mlx5_flow_meter *fm,
 					 const struct rte_flow_attr *attr);
+typedef struct mlx5_flow_counter * (*mlx5_flow_counter_alloc_t)
+				   (struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_counter_free_t)(struct rte_eth_dev *dev,
+					 struct mlx5_flow_counter *cnt);
+typedef int (*mlx5_flow_counter_query_t)(struct rte_eth_dev *dev,
+					 struct mlx5_flow_counter *cnt,
+					 bool clear, uint64_t *pkts,
+					 uint64_t *bytes);
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
 	mlx5_flow_prepare_t prepare;
@@ -676,6 +684,9 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
 	mlx5_flow_create_policer_rules_t create_policer_rules;
 	mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
+	mlx5_flow_counter_alloc_t counter_alloc;
+	mlx5_flow_counter_free_t counter_free;
+	mlx5_flow_counter_query_t counter_query;
 };
 
 
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index d6e4e45..2e92878 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7956,6 +7956,46 @@ struct field_modify_info modify_tcp[] = {
 	return -1;
 }
 
+/**
+ * Query a devx counter.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] cnt
+ *   Pointer to the flow counter.
+ * @param[in] clear
+ *   Set to clear the counter statistics.
+ * @param[out] pkts
+ *   The statistics value of packets.
+ * @param[out] bytes
+ *   The statistics value of bytes.
+ *
+ * @return
+ *   0 on success, otherwise return -1.
+ */
+static int
+flow_dv_counter_query(struct rte_eth_dev *dev,
+		      struct mlx5_flow_counter *cnt, bool clear,
+		      uint64_t *pkts, uint64_t *bytes)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	uint64_t inn_pkts, inn_bytes;
+	int ret;
+
+	if (!priv->config.devx)
+		return -1;
+	ret = _flow_dv_query_count(dev, cnt, &inn_pkts, &inn_bytes);
+	if (ret)
+		return -1;
+	*pkts = inn_pkts - cnt->hits;
+	*bytes = inn_bytes - cnt->bytes;
+	if (clear) {
+		cnt->hits = inn_pkts;
+		cnt->bytes = inn_bytes;
+	}
+	return 0;
+}
+
 /*
  * Mutex-protected thunk to lock-free  __flow_dv_translate().
  */
@@ -8013,6 +8053,31 @@ struct field_modify_info modify_tcp[] = {
 	flow_dv_shared_unlock(dev);
 }
 
+/*
+ * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
+ */
+static struct mlx5_flow_counter *
+flow_dv_counter_allocate(struct rte_eth_dev *dev)
+{
+	struct mlx5_flow_counter *cnt;
+
+	flow_dv_shared_lock(dev);
+	cnt = flow_dv_counter_alloc(dev, 0, 0, 1);
+	flow_dv_shared_unlock(dev);
+	return cnt;
+}
+
+/*
+ * Mutex-protected thunk to lock-free flow_dv_counter_release().
+ */
+static void
+flow_dv_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt)
+{
+	flow_dv_shared_lock(dev);
+	flow_dv_counter_release(dev, cnt);
+	flow_dv_shared_unlock(dev);
+}
+
 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.validate = flow_dv_validate,
 	.prepare = flow_dv_prepare,
@@ -8025,6 +8090,9 @@ struct field_modify_info modify_tcp[] = {
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
 	.create_policer_rules = flow_dv_create_policer_rules,
 	.destroy_policer_rules = flow_dv_destroy_policer_rules,
+	.counter_alloc = flow_dv_counter_allocate,
+	.counter_free = flow_dv_counter_free,
+	.counter_query = flow_dv_counter_query,
 };
 
 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 13/19] net/mlx5: add count action to meter
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (11 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 12/19] net/mlx5: expose flow counters management Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 14/19] net/mlx5: add meter statistics read and update Suanming Mou
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

Add count action to meter for metering packet statistics. All the
packets be colored and dropped will be recorded.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c       |  7 +++++--
 drivers/net/mlx5/mlx5_flow.h       | 18 ++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_dv.c    | 16 +++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c | 18 +++++++++++++++++-
 4 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 88590a1..e07c58d 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4879,17 +4879,20 @@ struct rte_flow *
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to the flow meter.
  *
  * @return
  *   Pointer to table set on success, NULL otherwise.
  */
 struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+			  const struct mlx5_flow_meter *fm)
 {
 	const struct mlx5_flow_driver_ops *fops;
 
 	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->create_mtr_tbls(dev);
+	return fops->create_mtr_tbls(dev, fm);
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 0004227..aee340f 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -531,6 +531,14 @@ struct mlx5_flow {
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
 
+/* Meter policer statistics */
+struct mlx5_flow_policer_stats {
+	struct mlx5_flow_counter *cnt[RTE_COLORS + 1];
+	/**< Color counter, extra for drop. */
+	uint64_t stats_mask;
+	/**< Statistics mask for the colors. */
+};
+
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
 	struct mlx5_flow_tbl_resource *tbl;
@@ -557,6 +565,8 @@ struct mlx5_meter_domains_infos {
 	/**< FDB meter table. */
 	void *drop_actn;
 	/**< Drop action as not matched. */
+	void *count_actns[RTE_MTR_DROPPED + 1];
+	/**< Counters for match and unmatched statistics. */
 	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
 	/**< Flow meter parameter. */
 	size_t fmp_size;
@@ -577,6 +587,8 @@ struct mlx5_flow_meter {
 	/**< Meter profile parameters. */
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
+	struct mlx5_flow_policer_stats policer_stats;
+	/**< Meter policer statistics. */
 	uint32_t ref_cnt;
 	/**< Use count. */
 	uint32_t active_state:1;
@@ -653,7 +665,8 @@ typedef int (*mlx5_flow_query_t)(struct rte_eth_dev *dev,
 				 void *data,
 				 struct rte_flow_error *error);
 typedef struct mlx5_meter_domains_infos *(*mlx5_flow_create_mtr_tbls_t)
-					    (struct rte_eth_dev *dev);
+					    (struct rte_eth_dev *dev,
+					     const struct mlx5_flow_meter *fm);
 typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 					struct mlx5_meter_domains_infos *tbls);
 typedef int (*mlx5_flow_create_policer_rules_t)
@@ -810,7 +823,8 @@ int mlx5_flow_validate_item_geneve(const struct rte_flow_item *item,
 				   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);
+					(struct rte_eth_dev *dev,
+					 const struct mlx5_flow_meter *fm);
 int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_meter_domains_infos *tbl);
 int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 2e92878..ded492d 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7707,6 +7707,8 @@ struct field_modify_info modify_tcp[] = {
 		DRV_LOG(ERR, "Failed to create meter policer color matcher.");
 		goto error_exit;
 	}
+	if (mtb->count_actns[RTE_MTR_DROPPED])
+		actions[i++] = mtb->count_actns[RTE_MTR_DROPPED];
 	actions[i++] = mtb->drop_actn;
 	/* Default rule: lowest priority, match any, actions: drop. */
 	dtb->policer_rules[RTE_MTR_DROPPED] =
@@ -7727,16 +7729,20 @@ struct field_modify_info modify_tcp[] = {
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to the flow meter.
  *
  * @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)
+flow_dv_create_mtr_tbl(struct rte_eth_dev *dev,
+		       const struct mlx5_flow_meter *fm)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_meter_domains_infos *mtb;
 	int ret;
+	int i;
 
 	if (!priv->mtr_en) {
 		rte_errno = ENOTSUP;
@@ -7747,6 +7753,12 @@ struct field_modify_info modify_tcp[] = {
 		DRV_LOG(ERR, "Failed to allocate memory for meter.");
 		return NULL;
 	}
+	/* Create meter count actions */
+	for (i = 0; i <= RTE_MTR_DROPPED; i++) {
+		if (!fm->policer_stats.cnt[i])
+			continue;
+		mtb->count_actns[i] = fm->policer_stats.cnt[i]->action;
+	}
 	/* Create drop action. */
 	mtb->drop_actn = mlx5_glue->dr_create_flow_action_drop();
 	if (!mtb->drop_actn) {
@@ -7882,6 +7894,8 @@ struct field_modify_info modify_tcp[] = {
 
 		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,
 				       rte_col_2_mlx5_col(i), UINT32_MAX);
+		if (mtb->count_actns[i])
+			actions[j++] = mtb->count_actns[i];
 		if (fm->params.action[i] == MTR_POLICER_ACTION_DROP)
 			actions[j++] = mtb->drop_actn;
 		else
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 20a57b5..ec4dfb4 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -570,6 +570,7 @@
 				.transfer = priv->config.dv_esw_en ? 1 : 0,
 			};
 	int ret;
+	unsigned int i;
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
@@ -596,7 +597,13 @@
 	fm->meter_id = meter_id;
 	fm->profile = fmp;
 	fm->params = *params;
-	fm->mfts = mlx5_flow_create_mtr_tbls(dev);
+	/* Alloc policer counters. */
+	for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) {
+		fm->policer_stats.cnt[i] = mlx5_counter_alloc(dev);
+		if (!fm->policer_stats.cnt[i])
+			goto error;
+	}
+	fm->mfts = mlx5_flow_create_mtr_tbls(dev, fm);
 	if (!fm->mfts)
 		goto error;
 	ret = mlx5_flow_create_policer_rules(dev, fm, &attr);
@@ -611,6 +618,10 @@
 error:
 	mlx5_flow_destroy_policer_rules(dev, fm, &attr);
 	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
+	/* Free policer counters. */
+	for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
+		if (fm->policer_stats.cnt[i])
+			mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
 	rte_free(fm);
 	return -rte_mtr_error_set(error, -ret,
 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
@@ -643,6 +654,7 @@
 				.egress = 1,
 				.transfer = priv->config.dv_esw_en ? 1 : 0,
 			};
+	unsigned int i;
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
@@ -666,6 +678,10 @@
 	fmp->ref_cnt--;
 	/* Remove from the flow meter list. */
 	TAILQ_REMOVE(fms, fm, next);
+	/* Free policer counters. */
+	for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
+		if (fm->policer_stats.cnt[i])
+			mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
 	/* Free meter flow table */
 	mlx5_flow_destroy_policer_rules(dev, fm, &attr);
 	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 14/19] net/mlx5: add meter statistics read and update
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (12 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 13/19] net/mlx5: add count action to meter Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 15/19] net/mlx5: add meter attach and detach Suanming Mou
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

This commit add the meter statistics read and update to check the meter
statistics.

New internal functions in rte_mtr_ops callback:
1. stats_update()
2. stats_read()

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_meter.c | 140 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 138 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index ec4dfb4..9efb2d4 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -613,6 +613,7 @@
 	TAILQ_INSERT_TAIL(fms, fm, next);
 	fm->active_state = 1; /* Config meter starts as active. */
 	fm->shared = !!shared;
+	fm->policer_stats.stats_mask = params->stats_mask;
 	fm->profile->ref_cnt++;
 	return 0;
 error:
@@ -889,6 +890,141 @@
 	return 0;
 }
 
+/**
+ * Callback to update meter stats mask.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[in] stats_mask
+ *   To be updated stats_mask.
+ * @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_stats_update(struct rte_eth_dev *dev,
+			     uint32_t meter_id,
+			     uint64_t stats_mask,
+			     struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter *fm;
+
+	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.");
+	fm->policer_stats.stats_mask = stats_mask;
+	return 0;
+}
+
+/**
+ * Callback to read meter statistics.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[out] stats
+ *   Pointer to store the statistics.
+ * @param[out] stats_mask
+ *   Pointer to store the stats_mask.
+ * @param[in] clear
+ *   Statistic to be cleared after read 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_stats_read(struct rte_eth_dev *dev,
+			   uint32_t meter_id,
+			   struct rte_mtr_stats *stats,
+			   uint64_t *stats_mask,
+			   int clear,
+			   struct rte_mtr_error *error)
+{
+	static uint64_t meter2mask[RTE_MTR_DROPPED + 1] = {
+		RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_BYTES_GREEN,
+		RTE_MTR_STATS_N_PKTS_YELLOW | RTE_MTR_STATS_N_BYTES_YELLOW,
+		RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED,
+		RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED
+	};
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_policer_stats *ps;
+	uint64_t pkts_dropped = 0;
+	uint64_t bytes_dropped = 0;
+	uint64_t pkts;
+	uint64_t bytes;
+	int i;
+	int ret = 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.");
+	ps = &fm->policer_stats;
+	*stats_mask = ps->stats_mask;
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		if (*stats_mask & meter2mask[i]) {
+			ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
+						 &bytes);
+			if (ret)
+				goto error;
+			if (fm->params.action[i] == MTR_POLICER_ACTION_DROP) {
+				pkts_dropped += pkts;
+				bytes_dropped += bytes;
+			}
+			/* If need to read the packets, set it. */
+			if ((1 << i) & (*stats_mask & meter2mask[i]))
+				stats->n_pkts[i] = pkts;
+			/* If need to read the bytes, set it. */
+			if ((1 << (RTE_MTR_DROPPED + 1 + i)) &
+			   (*stats_mask & meter2mask[i]))
+				stats->n_bytes[i] = bytes;
+		}
+	}
+	/* Dropped packets/bytes are treated differently. */
+	if (*stats_mask & meter2mask[i]) {
+		ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
+					 &bytes);
+		if (ret)
+			goto error;
+		pkts += pkts_dropped;
+		bytes += bytes_dropped;
+		/* If need to read the packets, set it. */
+		if ((*stats_mask & meter2mask[i]) &
+		   RTE_MTR_STATS_N_PKTS_DROPPED)
+			stats->n_pkts_dropped = pkts;
+		/* If need to read the bytes, set it. */
+		if ((*stats_mask & meter2mask[i]) &
+		   RTE_MTR_STATS_N_BYTES_DROPPED)
+			stats->n_bytes_dropped = bytes;
+	}
+	return 0;
+error:
+	return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
+				 "Failed to read policer counters.");
+}
+
 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,
@@ -900,8 +1036,8 @@
 	.meter_profile_update = mlx5_flow_meter_profile_update,
 	.meter_dscp_table_update = NULL,
 	.policer_actions_update = NULL,
-	.stats_update = NULL,
-	.stats_read = NULL,
+	.stats_update = mlx5_flow_meter_stats_update,
+	.stats_read = mlx5_flow_meter_stats_read,
 };
 
 /**
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 15/19] net/mlx5: add meter attach and detach
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (13 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 14/19] net/mlx5: add meter statistics read and update Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 16/19] net/mlx5: support meter flow action Suanming Mou
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

Add the meter attach and detach for the flow create.

When create the flow with meter, first try to find any created meter
action matches the flow meter id. If the meter action is already
created, just attach to it and increase the ref_cnt. If not, create
one.

For the dettach, decrease the ref_cnt, destroy the meter action while
the ref_cnt decreased to zero.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.h            |   6 ++
 drivers/net/mlx5/mlx5_flow.h       |   4 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 140 +++++++++++++++++++++++++++++++++++++
 3 files changed, 150 insertions(+)

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 2e35f00..aaf2ed5 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1038,5 +1038,11 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_tis
 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);
+struct mlx5_flow_meter *mlx5_flow_meter_attach
+					(struct mlx5_priv *priv,
+					 uint32_t meter_id,
+					 const struct rte_flow_attr *attr,
+					 struct rte_flow_error *error);
+void mlx5_flow_meter_detach(struct mlx5_flow_meter *fm);
 
 #endif /* RTE_PMD_MLX5_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index aee340f..ff89ae4 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -201,6 +201,7 @@ enum mlx5_feature_name {
 #define MLX5_FLOW_ACTION_SET_TAG (1ull << 32)
 #define MLX5_FLOW_ACTION_MARK_EXT (1ull << 33)
 #define MLX5_FLOW_ACTION_SET_META (1ull << 34)
+#define MLX5_FLOW_ACTION_METER (1ull << 35)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \
@@ -585,6 +586,8 @@ struct mlx5_flow_meter {
 	/**< Meter rule parameters. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
+	struct rte_flow_attr attr;
+	/**< Flow attributes. */
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
 	struct mlx5_flow_policer_stats policer_stats;
@@ -631,6 +634,7 @@ struct rte_flow {
 	struct mlx5_flow_counter *counter; /**< Holds flow counter. */
 	struct mlx5_flow_mreg_copy_resource *mreg_copy;
 	/**< pointer to metadata register copy table resource. */
+	struct mlx5_flow_meter *meter; /**< Holds flow meter. */
 	LIST_HEAD(dev_flows, mlx5_flow) dev_flows;
 	/**< Device flows that are part of the flow. */
 	struct mlx5_fdir *fdir; /**< Pointer to associated FDIR if any. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 9efb2d4..bd2bf7c 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -12,6 +12,61 @@
 #include "mlx5_flow.h"
 
 /**
+ * Create the meter action.
+ *
+ * @param priv
+ *   Pointer to mlx5_priv.
+ * @param[in] fm
+ *   Pointer to flow meter to be converted.
+ *
+ * @return
+ *   Pointer to the meter action on success, NULL otherwise.
+ */
+static void *
+mlx5_flow_meter_action_create(struct mlx5_priv *priv,
+			      struct mlx5_flow_meter *fm)
+{
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
+	struct mlx5dv_dr_flow_meter_attr mtr_init;
+	void *attr = fm->mfts->fmp;
+	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
+						     &fm->profile->srtcm_prm;
+
+	fm->mfts->fmp_size = MLX5_ST_SZ_BYTES(flow_meter_parameters);
+	memset(attr, 0, fm->mfts->fmp_size);
+	MLX5_SET(flow_meter_parameters, attr, valid, 1);
+	MLX5_SET(flow_meter_parameters, attr, bucket_overflow, 1);
+	MLX5_SET(flow_meter_parameters, attr,
+		 start_color, MLX5_FLOW_COLOR_GREEN);
+	MLX5_SET(flow_meter_parameters, attr, both_buckets_on_green, 0);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cbs_exponent, srtcm->cbs_exponent);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cbs_mantissa, srtcm->cbs_mantissa);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cir_exponent, srtcm->cir_exponent);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cir_mantissa, srtcm->cir_mantissa);
+	MLX5_SET(flow_meter_parameters,
+		 attr, ebs_exponent, srtcm->ebs_exponent);
+	MLX5_SET(flow_meter_parameters,
+		 attr, ebs_mantissa, srtcm->ebs_mantissa);
+	mtr_init.next_table =
+		fm->attr.transfer ? fm->mfts->transfer.tbl->obj :
+		    fm->attr.egress ? fm->mfts->egress.tbl->obj :
+				       fm->mfts->ingress.tbl->obj;
+	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
+	mtr_init.flow_meter_parameter = fm->mfts->fmp;
+	mtr_init.flow_meter_parameter_sz = fm->mfts->fmp_size;
+	mtr_init.active = fm->active_state;
+	return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
+#else
+	(void)fm;
+	return NULL;
+#endif
+}
+
+/**
  * Find meter profile by id.
  *
  * @param priv
@@ -1080,3 +1135,88 @@ struct mlx5_flow_meter *
 			return fm;
 	return NULL;
 }
+
+/**
+ * Attach meter to flow.
+ * Unidirectional Meter creation can only be done
+ * when flow direction is known, i.e. when calling meter_attach.
+ *
+ * @param [in] priv
+ *  Pointer to mlx5 private data.
+ * @param [in] meter_id
+ *  Flow meter id.
+ * @param [in] attr
+ *  Pointer to flow attributes.
+ * @param [out] error
+ *  Pointer to error structure.
+ *
+ * @return the flow meter pointer, NULL otherwise.
+ */
+struct mlx5_flow_meter *
+mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id,
+		       const struct rte_flow_attr *attr,
+		       struct rte_flow_error *error)
+{
+	struct mlx5_flow_meter *fm;
+
+	fm = mlx5_flow_meter_find(priv, meter_id);
+	if (fm == NULL) {
+		rte_flow_error_set(error, ENOENT,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Meter object id not valid");
+		goto error;
+	}
+	if (!fm->shared && fm->ref_cnt) {
+		DRV_LOG(ERR, "Cannot share a non-shared meter.");
+		rte_flow_error_set(error, EINVAL,
+				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				  "Meter can't be shared");
+		goto error;
+	}
+	if (!fm->ref_cnt++) {
+		RTE_ASSERT(!fm->mfts->meter_action);
+		fm->attr = *attr;
+		/* This also creates the meter object. */
+		fm->mfts->meter_action = mlx5_flow_meter_action_create(priv,
+								       fm);
+		if (!fm->mfts->meter_action)
+			goto error_detach;
+	} else {
+		RTE_ASSERT(fm->mfts->meter_action);
+		if (attr->transfer != fm->attr.transfer ||
+		    attr->ingress != fm->attr.ingress ||
+		    attr->egress != fm->attr.egress) {
+			DRV_LOG(ERR, "meter I/O attributes do not "
+				"match flow I/O attributes.");
+			goto error_detach;
+		}
+	}
+	return fm;
+error_detach:
+	mlx5_flow_meter_detach(fm);
+	rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			  fm->mfts->meter_action ? "Meter attr not match" :
+			  "Meter action create failed");
+error:
+	return NULL;
+}
+
+/**
+ * Detach meter from flow.
+ *
+ * @param [in] fm
+ *  Pointer to flow meter.
+ */
+void
+mlx5_flow_meter_detach(struct mlx5_flow_meter *fm)
+{
+	const struct rte_flow_attr attr = { 0 };
+
+	RTE_ASSERT(fm->ref_cnt);
+	if (--fm->ref_cnt)
+		return;
+	if (fm->mfts->meter_action)
+		mlx5_glue->destroy_flow_action(fm->mfts->meter_action);
+	fm->mfts->meter_action = NULL;
+	fm->attr = attr;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 16/19] net/mlx5: support meter flow action
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (14 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 15/19] net/mlx5: add meter attach and detach Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 17/19] net/mlx5: split meter flow Suanming Mou
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

Add meter flow action support in flow validate and translate.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_dv.c | 95 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index ded492d..b553787 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -3244,6 +3244,10 @@ struct field_modify_info modify_tcp[] = {
 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					  "can't have 2 fate actions in"
 					  " same flow");
+	if (action_flags & MLX5_FLOW_ACTION_METER)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "jump with meter not support");
 	if (!action->conf)
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
@@ -3357,6 +3361,63 @@ struct field_modify_info modify_tcp[] = {
 	return mlx5_flow_ext_mreg_supported(dev) ? MLX5_MODIFY_NUM :
 						   MLX5_MODIFY_NUM_NO_MREG;
 }
+
+/**
+ * Validate the meter action.
+ *
+ * @param[in] dev
+ *   Pointer to rte_eth_dev structure.
+ * @param[in] action_flags
+ *   Bit-fields that holds the actions detected until now.
+ * @param[in] action
+ *   Pointer to the meter action.
+ * @param[in] attr
+ *   Attributes of flow that includes this action.
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_ernno is set.
+ */
+static int
+mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
+				uint64_t action_flags,
+				const struct rte_flow_action *action,
+				const struct rte_flow_attr *attr,
+				struct rte_flow_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	const struct rte_flow_action_meter *am = action->conf;
+	struct mlx5_flow_meter *fm = mlx5_flow_meter_find(priv, am->mtr_id);
+
+	if (action_flags & MLX5_FLOW_ACTION_METER)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "meter chaining not support");
+	if (action_flags & MLX5_FLOW_ACTION_JUMP)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "meter with jump not support");
+	if (!priv->mtr_en)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "meter action not supported");
+	if (!fm)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Meter not found");
+	if (fm->ref_cnt && (!(fm->attr.transfer == attr->transfer ||
+	      (!fm->attr.ingress && !attr->ingress && attr->egress) ||
+	      (!fm->attr.egress && !attr->egress && attr->ingress))))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Flow attributes are either invalid "
+					  "or have a conflict with current "
+					  "meter attributes");
+	return 0;
+}
+
 /**
  * Find existing modify-header resource or create and register a new one.
  *
@@ -4703,6 +4764,16 @@ struct field_modify_info modify_tcp[] = {
 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
 			break;
+		case RTE_FLOW_ACTION_TYPE_METER:
+			ret = mlx5_flow_validate_action_meter(dev,
+							      action_flags,
+							      actions, attr,
+							      error);
+			if (ret < 0)
+				return ret;
+			action_flags |= MLX5_FLOW_ACTION_METER;
+			++actions_n;
+			break;
 		default:
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
@@ -6478,6 +6549,7 @@ struct field_modify_info modify_tcp[] = {
 		const struct rte_flow_action_count *count = action->conf;
 		const uint8_t *rss_key;
 		const struct rte_flow_action_jump *jump_data;
+		const struct rte_flow_action_meter *mtr;
 		struct mlx5_flow_dv_jump_tbl_resource jump_tbl_resource;
 		struct mlx5_flow_tbl_resource *tbl;
 		uint32_t port_id = 0;
@@ -6844,6 +6916,25 @@ struct field_modify_info modify_tcp[] = {
 				return -rte_errno;
 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
 			break;
+		case RTE_FLOW_ACTION_TYPE_METER:
+			mtr = actions->conf;
+			if (!flow->meter) {
+				flow->meter = mlx5_flow_meter_attach(priv,
+							mtr->mtr_id, attr,
+							error);
+				if (!flow->meter)
+					return rte_flow_error_set(error,
+						rte_errno,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"meter not found "
+						"or invalid parameters");
+			}
+			/* Set the meter action. */
+			dev_flow->dv.actions[actions_n++] =
+				flow->meter->mfts->meter_action;
+			action_flags |= MLX5_FLOW_ACTION_METER;
+			break;
 		case RTE_FLOW_ACTION_TYPE_END:
 			actions_end = true;
 			if (mhdr_res.actions_num) {
@@ -7445,6 +7536,10 @@ struct field_modify_info modify_tcp[] = {
 		flow_dv_counter_release(dev, flow->counter);
 		flow->counter = NULL;
 	}
+	if (flow->meter) {
+		mlx5_flow_meter_detach(flow->meter);
+		flow->meter = NULL;
+	}
 	while (!LIST_EMPTY(&flow->dev_flows)) {
 		dev_flow = LIST_FIRST(&flow->dev_flows);
 		LIST_REMOVE(dev_flow, next);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 17/19] net/mlx5: split meter flow
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (15 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 16/19] net/mlx5: support meter flow action Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 18/19] net/mlx5: share tag between meter and metadata Suanming Mou
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

The flow with meter action will be divided to three sub flows, the
prefix flow, the meter flow and the suffix flow.

For these three sub flows, as the prefix flow and meter flow have the
meter color match. In order the make the packet from prefix flow to
match with the suffix flow, an extra metadata register is allocated.
The prefix flow will add a unique id to the register and the suffix
flow matches on that unique id.

As RSS will also divided the flow to several sub flows, flow with meter
will be divided as the sub flow of the RSS sub flows if have as below:

Original flow ->
	RSS sub flow 1 ->
		Meter sub flow 1 (Contain three sub flows.)
	RSS sub flow 2 ->
		Meter sub flow 2 (Contain three sub flows.)
	......
	RSS sub flow n ->
		Meter sub flow n (Contain three sub flows.)

The metadata feature flow will be split as the sub flow of the meter
suffix flow.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c | 299 ++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow.h |   1 +
 2 files changed, 299 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index e07c58d..5df9da8 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -2309,6 +2309,27 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 			flow_qrss_free_id(dev, dev_flow->qrss_id);
 }
 
+/**
+ * Release meter prefix suffix flow match id.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param flow
+ *   Flow to release id's from.
+ */
+static void
+flow_meter_split_id_release(struct rte_eth_dev *dev,
+			    struct rte_flow *flow)
+{
+	struct mlx5_flow *dev_flow;
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	LIST_FOREACH(dev_flow, &flow->dev_flows, next)
+		if (dev_flow->qrss_id)
+			mlx5_flow_id_release(priv->sh->flow_id_pool,
+					     dev_flow->mtr_flow_id);
+}
+
 static int
 flow_null_validate(struct rte_eth_dev *dev __rte_unused,
 		   const struct rte_flow_attr *attr __rte_unused,
@@ -2599,6 +2620,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	enum mlx5_flow_drv_type type = flow->drv_type;
 
 	flow_mreg_split_qrss_release(dev, flow);
+	flow_meter_split_id_release(dev, flow);
 	assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
 	fops = flow_get_drv_ops(type);
 	fops->destroy(dev, flow);
@@ -2626,6 +2648,26 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * Get port id item from the item list.
+ *
+ * @param[in] item
+ *   Pointer to the list of items.
+ *
+ * @return
+ *   Pointer to the port id item if exist, else return NULL.
+ */
+static const struct rte_flow_item *
+find_port_id_item(const struct rte_flow_item *item)
+{
+	assert(item);
+	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+		if (item->type == RTE_FLOW_ITEM_TYPE_PORT_ID)
+			return item;
+	}
+	return NULL;
+}
+
+/**
  * Get RSS action from the action list.
  *
  * @param[in] actions
@@ -2704,6 +2746,38 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * Check meter action from the action list.
+ *
+ * @param[in] actions
+ *   Pointer to the list of actions.
+ * @param[out] mtr
+ *   Pointer to the meter exist flag.
+ *
+ * @return
+ *   Total number of actions.
+ */
+static int
+flow_check_meter_action(const struct rte_flow_action actions[], uint32_t *mtr)
+{
+	int actions_n = 0;
+
+	assert(mtr);
+	*mtr = 0;
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_METER:
+			*mtr = 1;
+			break;
+		default:
+			break;
+		}
+		actions_n++;
+	}
+	/* Count RTE_FLOW_ACTION_TYPE_END. */
+	return actions_n + 1;
+}
+
+/**
  * Check if the flow should be splited due to hairpin.
  * The reason for the split is that in current HW we can't
  * support encap on Rx, so if a flow have encap we move it
@@ -3334,6 +3408,111 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * Split the meter flow.
+ *
+ * As meter flow will split to three sub flow, other than meter
+ * action, the other actions make sense to only meter accepts
+ * the packet. If it need to be dropped, no other additional
+ * actions should be take.
+ *
+ * One kind of special action which decapsulates the L3 tunnel
+ * header will be in the prefix sub flow, as not to take the
+ * L3 tunnel header into account.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] actions
+ *   Associated actions (list terminated by the END action).
+ * @param[out] actions_sfx
+ *   Suffix flow actions.
+ * @param[out] actions_pre
+ *   Prefix flow actions.
+ * @param[out] pattern_sfx
+ *   The pattern items for the suffix flow.
+ * @param[out] tag_sfx
+ *   Pointer to suffix flow tag.
+ *
+ * @return
+ *   0 on success.
+ */
+static int
+flow_meter_split_prep(struct rte_eth_dev *dev,
+		 const struct rte_flow_action actions[],
+		 struct rte_flow_action actions_sfx[],
+		 struct rte_flow_action actions_pre[])
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_action *tag_action;
+	struct mlx5_rte_flow_action_set_tag *set_tag;
+	struct rte_flow_error error;
+	const struct rte_flow_action_raw_encap *raw_encap;
+	const struct rte_flow_action_raw_decap *raw_decap;
+	uint32_t tag_id;
+
+	/* Add the extra tag action first. */
+	tag_action = actions_pre;
+	tag_action->type = MLX5_RTE_FLOW_ACTION_TYPE_TAG;
+	actions_pre++;
+	/* Prepare the actions for prefix and suffix flow. */
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_METER:
+		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+			memcpy(actions_pre, actions,
+			       sizeof(struct rte_flow_action));
+			actions_pre++;
+			break;
+		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+			raw_encap = actions->conf;
+			if (raw_encap->size >
+			    (sizeof(struct rte_flow_item_eth) +
+			     sizeof(struct rte_flow_item_ipv4))) {
+				memcpy(actions_sfx, actions,
+				       sizeof(struct rte_flow_action));
+				actions_sfx++;
+			} else {
+				rte_memcpy(actions_pre, actions,
+					   sizeof(struct rte_flow_action));
+				actions_pre++;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+			raw_decap = actions->conf;
+			/* Size 0 decap means 50 bytes as vxlan decap. */
+			if (raw_decap->size && (raw_decap->size <
+			    (sizeof(struct rte_flow_item_eth) +
+			     sizeof(struct rte_flow_item_ipv4)))) {
+				memcpy(actions_sfx, actions,
+				       sizeof(struct rte_flow_action));
+				actions_sfx++;
+			} else {
+				rte_memcpy(actions_pre, actions,
+					   sizeof(struct rte_flow_action));
+				actions_pre++;
+			}
+			break;
+		default:
+			memcpy(actions_sfx, actions,
+				sizeof(struct rte_flow_action));
+			actions_sfx++;
+			break;
+		}
+	}
+	/* Add end action to the actions. */
+	actions_sfx->type = RTE_FLOW_ACTION_TYPE_END;
+	actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+	actions_pre++;
+	/* Set the tag. */
+	set_tag = (void *)actions_pre;
+	set_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);
+	mlx5_flow_id_get(priv->sh->flow_id_pool, &tag_id);
+	set_tag->data = rte_cpu_to_be_32(tag_id);
+	tag_action->conf = set_tag;
+	return tag_id;
+}
+
+/**
  * Split action list having QUEUE/RSS for metadata register copy.
  *
  * Once Q/RSS action is detected in user's action list, the flow action
@@ -3679,6 +3858,124 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * The splitting for meter feature.
+ *
+ * - The meter flow will be split to two flows as prefix and
+ *   suffix flow. The packets make sense only it pass the prefix
+ *   meter action.
+ *
+ * - Reg_C_5 is used for the packet to match betweend prefix and
+ *   suffix flow.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
+ * @param[in] attr
+ *   Flow rule attributes.
+ * @param[in] items
+ *   Pattern specification (list terminated by the END pattern item).
+ * @param[in] actions
+ *   Associated actions (list terminated by the END action).
+ * @param[in] external
+ *   This flow rule is created by request external to PMD.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   0 on success, negative value otherwise
+ */
+static int
+flow_create_split_meter(struct rte_eth_dev *dev,
+			   struct rte_flow *flow,
+			   const struct rte_flow_attr *attr,
+			   const struct rte_flow_item items[],
+			   const struct rte_flow_action actions[],
+			   bool external, struct rte_flow_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_action *sfx_actions = NULL;
+	struct rte_flow_action *pre_actions = NULL;
+	struct rte_flow_item *sfx_items = NULL;
+	const  struct rte_flow_item *sfx_port_id_item;
+	struct mlx5_flow *dev_flow = NULL;
+	struct rte_flow_attr sfx_attr = *attr;
+	uint32_t mtr = 0;
+	uint32_t mtr_tag_id = 0;
+	size_t act_size;
+	size_t item_size;
+	int actions_n = 0;
+	int ret;
+
+	if (priv->mtr_en)
+		actions_n = flow_check_meter_action(actions, &mtr);
+	if (mtr) {
+		struct mlx5_rte_flow_item_tag *tag_spec;
+		/* The five prefix actions: meter, decap, encap, tag, end. */
+		act_size = sizeof(struct rte_flow_action) * (actions_n + 5) +
+			   sizeof(struct rte_flow_action_set_tag);
+		/* tag, end. */
+#define METER_SUFFIX_ITEM 3
+		item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
+			    sizeof(struct mlx5_rte_flow_item_tag);
+		sfx_actions = rte_zmalloc(__func__, (act_size + item_size), 0);
+		if (!sfx_actions)
+			return rte_flow_error_set(error, ENOMEM,
+						  RTE_FLOW_ERROR_TYPE_ACTION,
+						  NULL, "no memory to split "
+						  "meter flow");
+		pre_actions = sfx_actions + actions_n;
+		mtr_tag_id = flow_meter_split_prep(dev, actions, sfx_actions,
+						     pre_actions);
+		if (!mtr_tag_id) {
+			ret = -rte_errno;
+			goto exit;
+		}
+		/* Add the prefix subflow. */
+		ret = flow_create_split_inner(dev, flow, &dev_flow, attr, items,
+						  pre_actions, external, error);
+		if (ret) {
+			ret = -rte_errno;
+			goto exit;
+		}
+		dev_flow->mtr_flow_id = mtr_tag_id;
+		/* Prepare the suffix flow match pattern. */
+		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
+			     act_size);
+		tag_spec = (struct mlx5_rte_flow_item_tag *)(sfx_items +
+			    METER_SUFFIX_ITEM);
+		tag_spec->data = rte_cpu_to_be_32(dev_flow->mtr_flow_id);
+		tag_spec->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0,
+						    error);
+		sfx_items->type = MLX5_RTE_FLOW_ITEM_TYPE_TAG;
+		sfx_items->spec = tag_spec;
+		sfx_items->last = NULL;
+		sfx_items->mask = NULL;
+		sfx_items++;
+		sfx_port_id_item = find_port_id_item(items);
+		if (sfx_port_id_item) {
+			memcpy(sfx_items, sfx_port_id_item,
+			       sizeof(*sfx_items));
+			sfx_items++;
+		}
+		sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
+		sfx_items -= METER_SUFFIX_ITEM;
+		/* Setting the sfx group atrr. */
+		sfx_attr.group = sfx_attr.transfer ?
+				(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_SUFFIX;
+	}
+	/* Add the prefix subflow. */
+	ret = flow_create_split_metadata(dev, flow, &sfx_attr,
+					 sfx_items ? sfx_items : items,
+					 sfx_actions ? sfx_actions : actions,
+					 external, error);
+exit:
+	if (sfx_actions)
+		rte_free(sfx_actions);
+	return ret;
+}
+
+/**
  * Split the flow to subflow set. The splitters might be linked
  * in the chain, like this:
  * flow_create_split_outer() calls:
@@ -3723,7 +4020,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 {
 	int ret;
 
-	ret = flow_create_split_metadata(dev, flow, attr, items,
+	ret = flow_create_split_meter(dev, flow, attr, items,
 					 actions, external, error);
 	assert(ret <= 0);
 	return ret;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index ff89ae4..b0a5678 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -521,6 +521,7 @@ struct mlx5_flow {
 		struct mlx5_flow_verbs verbs;
 	};
 	uint32_t qrss_id; /**< Uniqie Q/RSS suffix subflow tag. */
+	uint32_t mtr_flow_id; /**< Unique meter match flow id. */
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 18/19] net/mlx5: share tag between meter and metadata
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (16 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 17/19] net/mlx5: split meter flow Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 19/19] net/mlx5: clean meter resources Suanming Mou
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

In the meter flow split, metadata flow will be as the sub flow of meter
suffix flow. In meter suffix flow, there is already a unique id tag
exist as for the meter prefix and suffix flow match.

Make metadata feature and meter both share the unique id tag for match.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c | 150 +++++++++++++++++++++++--------------------
 drivers/net/mlx5/mlx5_flow.h |   6 +-
 2 files changed, 85 insertions(+), 71 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 5df9da8..9a8148b 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -2309,27 +2309,6 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 			flow_qrss_free_id(dev, dev_flow->qrss_id);
 }
 
-/**
- * Release meter prefix suffix flow match id.
- *
- * @param dev
- *   Pointer to Ethernet device.
- * @param flow
- *   Flow to release id's from.
- */
-static void
-flow_meter_split_id_release(struct rte_eth_dev *dev,
-			    struct rte_flow *flow)
-{
-	struct mlx5_flow *dev_flow;
-	struct mlx5_priv *priv = dev->data->dev_private;
-
-	LIST_FOREACH(dev_flow, &flow->dev_flows, next)
-		if (dev_flow->qrss_id)
-			mlx5_flow_id_release(priv->sh->flow_id_pool,
-					     dev_flow->mtr_flow_id);
-}
-
 static int
 flow_null_validate(struct rte_eth_dev *dev __rte_unused,
 		   const struct rte_flow_attr *attr __rte_unused,
@@ -2620,7 +2599,6 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	enum mlx5_flow_drv_type type = flow->drv_type;
 
 	flow_mreg_split_qrss_release(dev, flow);
-	flow_meter_split_id_release(dev, flow);
 	assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
 	fops = flow_get_drv_ops(type);
 	fops->destroy(dev, flow);
@@ -3441,7 +3419,6 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 		 struct rte_flow_action actions_sfx[],
 		 struct rte_flow_action actions_pre[])
 {
-	struct mlx5_priv *priv = dev->data->dev_private;
 	struct rte_flow_action *tag_action;
 	struct mlx5_rte_flow_action_set_tag *set_tag;
 	struct rte_flow_error error;
@@ -3506,7 +3483,10 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	/* Set the tag. */
 	set_tag = (void *)actions_pre;
 	set_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);
-	mlx5_flow_id_get(priv->sh->flow_id_pool, &tag_id);
+	/*
+	 * Get the id from the qrss_pool to make qrss share the id with meter.
+	 */
+	tag_id = flow_qrss_get_id(dev);
 	set_tag->data = rte_cpu_to_be_32(tag_id);
 	tag_action->conf = set_tag;
 	return tag_id;
@@ -3563,7 +3543,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	struct mlx5_rte_flow_action_set_tag *set_tag;
 	struct rte_flow_action_jump *jump;
 	const int qrss_idx = qrss - actions;
-	uint32_t flow_id;
+	uint32_t flow_id = 0;
 	int ret = 0;
 
 	/*
@@ -3573,43 +3553,50 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	 * As a result, there will be one more action.
 	 */
 	++actions_n;
+	memcpy(split_actions, actions, sizeof(*split_actions) * actions_n);
+	set_tag = (void *)(split_actions + actions_n);
 	/*
-	 * Allocate the new subflow ID. This one is unique within
-	 * device and not shared with representors. Otherwise,
-	 * we would have to resolve multi-thread access synch
-	 * issue. Each flow on the shared device is appended
-	 * with source vport identifier, so the resulting
-	 * flows will be unique in the shared (by master and
-	 * representors) domain even if they have coinciding
-	 * IDs.
+	 * If tag action is not set to void(it means we are not the meter
+	 * suffix flow), add the tag action. Since meter suffix flow already
+	 * has the tag added.
 	 */
-	flow_id = flow_qrss_get_id(dev);
-	if (!flow_id)
-		return rte_flow_error_set(error, ENOMEM,
-					  RTE_FLOW_ERROR_TYPE_ACTION,
-					  NULL, "can't allocate id "
-					  "for split Q/RSS subflow");
-	/* Internal SET_TAG action to set flow ID. */
-	set_tag = (void *)(split_actions + actions_n);
-	*set_tag = (struct mlx5_rte_flow_action_set_tag){
-		.data = flow_id,
-	};
-	ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error);
-	if (ret < 0)
-		return ret;
-	set_tag->id = ret;
+	if (split_actions[qrss_idx].type != RTE_FLOW_ACTION_TYPE_VOID) {
+		/*
+		 * Allocate the new subflow ID. This one is unique within
+		 * device and not shared with representors. Otherwise,
+		 * we would have to resolve multi-thread access synch
+		 * issue. Each flow on the shared device is appended
+		 * with source vport identifier, so the resulting
+		 * flows will be unique in the shared (by master and
+		 * representors) domain even if they have coinciding
+		 * IDs.
+		 */
+		flow_id = flow_qrss_get_id(dev);
+		if (!flow_id)
+			return rte_flow_error_set(error, ENOMEM,
+						  RTE_FLOW_ERROR_TYPE_ACTION,
+						  NULL, "can't allocate id "
+						  "for split Q/RSS subflow");
+		/* Internal SET_TAG action to set flow ID. */
+		*set_tag = (struct mlx5_rte_flow_action_set_tag){
+			.data = flow_id,
+		};
+		ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error);
+		if (ret < 0)
+			return ret;
+		set_tag->id = ret;
+		/* Construct new actions array. */
+		/* Replace QUEUE/RSS action. */
+		split_actions[qrss_idx] = (struct rte_flow_action){
+			.type = MLX5_RTE_FLOW_ACTION_TYPE_TAG,
+			.conf = set_tag,
+		};
+	}
 	/* JUMP action to jump to mreg copy table (CP_TBL). */
 	jump = (void *)(set_tag + 1);
 	*jump = (struct rte_flow_action_jump){
 		.group = MLX5_FLOW_MREG_CP_TABLE_GROUP,
 	};
-	/* Construct new actions array. */
-	memcpy(split_actions, actions, sizeof(*split_actions) * actions_n);
-	/* Replace QUEUE/RSS action. */
-	split_actions[qrss_idx] = (struct rte_flow_action){
-		.type = MLX5_RTE_FLOW_ACTION_TYPE_TAG,
-		.conf = set_tag,
-	};
 	split_actions[actions_n - 2] = (struct rte_flow_action){
 		.type = RTE_FLOW_ACTION_TYPE_JUMP,
 		.conf = jump,
@@ -3710,6 +3697,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	struct rte_flow_action *ext_actions = NULL;
 	struct mlx5_flow *dev_flow = NULL;
 	uint32_t qrss_id = 0;
+	int mtr_sfx = 0;
 	size_t act_size;
 	int actions_n;
 	int ret;
@@ -3740,6 +3728,10 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 		}
 	}
 	if (qrss) {
+		/* Check if it is in meter suffix table. */
+		mtr_sfx = attr->group == (attr->transfer ?
+			  (MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
+			  MLX5_FLOW_TABLE_LEVEL_SUFFIX);
 		/*
 		 * Q/RSS action on NIC Rx should be split in order to pass by
 		 * the mreg copy table (RX_CP_TBL) and then it jumps to the
@@ -3755,6 +3747,16 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 						  NULL, "no memory to split "
 						  "metadata flow");
 		/*
+		 * If we are the suffix flow of meter, tag already exist.
+		 * Set the tag action to void.
+		 */
+		if (mtr_sfx)
+			ext_actions[qrss - actions].type =
+						RTE_FLOW_ACTION_TYPE_VOID;
+		else
+			ext_actions[qrss - actions].type =
+						MLX5_RTE_FLOW_ACTION_TYPE_TAG;
+		/*
 		 * Create the new actions list with removed Q/RSS action
 		 * and appended set tag and jump to register copy table
 		 * (RX_CP_TBL). We should preallocate unique tag ID here
@@ -3762,7 +3764,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 		 */
 		qrss_id = flow_mreg_split_qrss_prep(dev, ext_actions, actions,
 						    qrss, actions_n, error);
-		if (!qrss_id) {
+		if (!mtr_sfx && !qrss_id) {
 			ret = -rte_errno;
 			goto exit;
 		}
@@ -3792,7 +3794,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	if (ret < 0)
 		goto exit;
 	assert(dev_flow);
-	if (qrss_id) {
+	if (qrss) {
 		const struct rte_flow_attr q_attr = {
 			.group = MLX5_FLOW_MREG_ACT_TABLE_GROUP,
 			.ingress = 1,
@@ -3823,22 +3825,32 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 			},
 		};
 		uint64_t hash_fields = dev_flow->hash_fields;
+		dev_flow = NULL;
 		/*
-		 * Put unique id in prefix flow due to it is destroyed after
-		 * prefix flow and id will be freed after there is no actual
-		 * flows with this id and identifier reallocation becomes
-		 * possible (for example, for other flows in other threads).
+		 * Configure the tag action only if we are not the meter sub
+		 * flow. Since tag is already marked in the meter suffix sub
+		 * flow.
 		 */
-		dev_flow->qrss_id = qrss_id;
-		qrss_id = 0;
-		dev_flow = NULL;
-		ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error);
-		if (ret < 0)
-			goto exit;
-		q_tag_spec.id = ret;
+		if (qrss_id) {
+			/*
+			 * Put unique id in prefix flow due to it is destroyed
+			 * after prefix flow and id will be freed after there
+			 * is no actual flows with this id and identifier
+			 * reallocation becomes possible (for example, for
+			 * other flows in other threads).
+			 */
+			dev_flow->qrss_id = qrss_id;
+			qrss_id = 0;
+			ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0,
+						   error);
+			if (ret < 0)
+				goto exit;
+			q_tag_spec.id = ret;
+		}
 		/* Add suffix subflow to execute Q/RSS. */
 		ret = flow_create_split_inner(dev, flow, &dev_flow,
-					      &q_attr, q_items, q_actions,
+					      &q_attr, mtr_sfx ? items :
+					      q_items, q_actions,
 					      external, error);
 		if (ret < 0)
 			goto exit;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index b0a5678..e38d3c0 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -520,8 +520,10 @@ struct mlx5_flow {
 #endif
 		struct mlx5_flow_verbs verbs;
 	};
-	uint32_t qrss_id; /**< Uniqie Q/RSS suffix subflow tag. */
-	uint32_t mtr_flow_id; /**< Unique meter match flow id. */
+	union {
+		uint32_t qrss_id; /**< Uniqie Q/RSS suffix subflow tag. */
+		uint32_t mtr_flow_id; /**< Unique meter match flow id. */
+	};
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH 19/19] net/mlx5: clean meter resources
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (17 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 18/19] net/mlx5: share tag between meter and metadata Suanming Mou
@ 2019-11-06 15:11 ` Suanming Mou
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
  19 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-06 15:11 UTC (permalink / raw)
  To: Matan Azrad, Shahaf Shuler, Viacheslav Ovsiienko; +Cc: dev

When the port is closed or program exits ungraceful, the meter rulers
should be flushed after the flow destroyed.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.c            |  1 +
 drivers/net/mlx5/mlx5_flow.h       |  2 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 61 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 1a2fef6..da79c14 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -1016,6 +1016,7 @@ struct mlx5_flow_id_pool *
 	mlx5_dev_interrupt_handler_devx_uninstall(dev);
 	mlx5_traffic_disable(dev);
 	mlx5_flow_flush(dev, NULL);
+	mlx5_flow_meter_flush(dev, NULL);
 	/* Prevent crashes when queues are still in use. */
 	dev->rx_pkt_burst = removed_rx_burst;
 	dev->tx_pkt_burst = removed_tx_burst;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index e38d3c0..c37adfe 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -840,4 +840,6 @@ int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
 int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
 				    struct mlx5_flow_meter *fm,
 				    const struct rte_flow_attr *attr);
+int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
+			  struct rte_mtr_error *error);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index bd2bf7c..f8e7e11 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -4,6 +4,7 @@
  */
 #include <math.h>
 
+#include <rte_tailq.h>
 #include <rte_malloc.h>
 #include <rte_mtr.h>
 #include <rte_mtr_driver.h>
@@ -1220,3 +1221,63 @@ struct mlx5_flow_meter *
 	fm->mfts->meter_action = NULL;
 	fm->attr = attr;
 }
+
+/**
+ * Flush meter configuration.
+ *
+ * @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.
+ */
+int
+mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
+	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,
+			};
+	void *tmp;
+	uint32_t i;
+
+	TAILQ_FOREACH_SAFE(fm, fms, next, tmp) {
+		/* Meter object must not have any owner. */
+		RTE_ASSERT(!fm->ref_cnt);
+		/* Get meter profile. */
+		fmp = fm->profile;
+		if (fmp == NULL)
+			return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+				NULL, "MTR object meter profile invalid.");
+		/* Update dependencies. */
+		fmp->ref_cnt--;
+		/* Remove from list. */
+		TAILQ_REMOVE(fms, fm, next);
+		/* Free policer counters. */
+		for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
+			if (fm->policer_stats.cnt[i])
+				mlx5_counter_free(dev,
+						  fm->policer_stats.cnt[i]);
+		/* Free meter flow table. */
+		mlx5_flow_destroy_policer_rules(dev, fm, &attr);
+		mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
+		rte_free(fm);
+	}
+	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
+		/* Check unused. */
+		RTE_ASSERT(!fmp->ref_cnt);
+		/* Remove from list. */
+		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
+		rte_free(fmp);
+	}
+	return 0;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter
  2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
                   ` (18 preceding siblings ...)
  2019-11-06 15:11 ` [dpdk-dev] [PATCH 19/19] net/mlx5: clean meter resources Suanming Mou
@ 2019-11-08  3:49 ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 01/19] net/mlx5: add meter operation callback Suanming Mou
                     ` (20 more replies)
  19 siblings, 21 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

The patches introduce the meter action support for mlx5.
The design of the implementation was introduced in RFC as below:
http://inbox.dpdk.org/dev/b994cd03-02f6-cd50-120f-dcf0941e4485@mellanox.com

The implementation is followed RFC to split flow with meter to three
sub flows.
Prefix flow -> Meter flow -> Suffix flow

The srTCM color blind mode is supported only, color aware mode and
multiple meter chaining are not supported.

The patch set add the operations to get the capabilities of the meter
action, create/destroy the action, validate the action, attach/detach
the action, update the action, query the action statistics and flush
the actions resources.

Besides these, as the flow with meter action is split to three sub
flows for coloring(in prefix flow), color checking(in meter flow),
left actions applying (in suffix flow), two registers are used for the
color match and prefix-suffix flow match. That's what the "allocate
flow meter registers" patch does.

As with the three sub flows, two more flow tables are created for the
meter flow and suffix flow in patch "prepare meter flow tables". As
wrote in the RFC, meter flow and suffix flow are separated since meter
maybe shared with multiple flows.

For the meter action statistics's query, the DevX flow counter is
exposed to meter action in patch "expose flow counters management".

In the "split meter flow" patch, flow with meter is split to three
sub flow. The *_DECAP and meter action will be in the prefix flow.
And an extra tag action with unique flow id to match with the suffix
flow is also added to the prefix flow. The suffix flow will apply
all the left actions while the flow id in tag item matches.

Since the metadata copy mark action is in the meter suffix flow,
the REG_C for cpoy mark and prefix-suffix flow match is shared.
Once the meter suffix flow add the tag, metadata suffix sub flow
won't add the tag anymore but share the tag is enough. It's done
in the "share tag between meter and metadata" patch.

---
v2: rebased on top of the latest code with metadata feature

Suanming Mou (19):
  net/mlx5: add meter operation callback
  net/mlx5: fill meter capabilities using DevX
  net/mlx5: allocate flow meter registers
  net/mlx5: support meter profile operations
  net/mlx5: validate meter profile
  net/mlx5: prepare meter flow tables
  net/mlx5: add policer rules operations
  net/mlx5: support basic meter operations
  net/mlx5: add meter action creation to the glue
  net/mlx5: support meter modification operations
  net/mlx5: support meter profile update
  net/mlx5: expose flow counters management
  net/mlx5: add count action to meter
  net/mlx5: add meter statistics read and update
  net/mlx5: add meter attach and detach
  net/mlx5: support meter flow action
  net/mlx5: split meter flow
  net/mlx5: share tag between meter and metadata
  net/mlx5: clean meter resources

 drivers/net/mlx5/Makefile          |    7 +
 drivers/net/mlx5/meson.build       |    3 +
 drivers/net/mlx5/mlx5.c            |   29 +
 drivers/net/mlx5/mlx5.h            |   46 ++
 drivers/net/mlx5/mlx5_devx_cmds.c  |   23 +
 drivers/net/mlx5/mlx5_flow.c       |  632 ++++++++++++++++--
 drivers/net/mlx5/mlx5_flow.h       |  153 ++++-
 drivers/net/mlx5/mlx5_flow_dv.c    |  612 +++++++++++++++++
 drivers/net/mlx5/mlx5_flow_meter.c | 1285 ++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.c       |   30 +
 drivers/net/mlx5/mlx5_glue.h       |    9 +
 drivers/net/mlx5/mlx5_prm.h        |   45 ++
 12 files changed, 2812 insertions(+), 62 deletions(-)
 create mode 100644 drivers/net/mlx5/mlx5_flow_meter.c

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 01/19] net/mlx5: add meter operation callback
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 02/19] net/mlx5: fill meter capabilities using DevX Suanming Mou
                     ` (19 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

Add the new mlx5_flow_meter.c file for metering support.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/Makefile          |  6 ++++++
 drivers/net/mlx5/meson.build       |  3 +++
 drivers/net/mlx5/mlx5.c            |  2 ++
 drivers/net/mlx5/mlx5.h            |  4 ++++
 drivers/net/mlx5/mlx5_flow_meter.c | 43 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 58 insertions(+)
 create mode 100644 drivers/net/mlx5/mlx5_flow_meter.c

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index 44cc26a..0065e55 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -32,6 +32,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_stats.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mr.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow.c
+SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_meter.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_dv.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_flow_verbs.c
 SRCS-$(CONFIG_RTE_LIBRTE_MLX5_PMD) += mlx5_mp.c
@@ -199,6 +200,11 @@ mlx5_autoconf.h.new: $(RTE_SDK)/buildtools/auto-config-h.sh
 		func mlx5dv_dr_action_create_dest_devx_tir \
 		$(AUTOCONF_OUTPUT)
 	$Q sh -- '$<' '$@' \
+		HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER \
+		infiniband/mlx5dv.h \
+		func mlx5dv_dr_action_create_flow_meter \
+		$(AUTOCONF_OUTPUT)
+	$Q sh -- '$<' '$@' \
 		HAVE_ETHTOOL_LINK_MODE_25G \
 		/usr/include/linux/ethtool.h \
 		enum ETHTOOL_LINK_MODE_25000baseCR_Full_BIT \
diff --git a/drivers/net/mlx5/meson.build b/drivers/net/mlx5/meson.build
index b72ddb4..511f5b7 100644
--- a/drivers/net/mlx5/meson.build
+++ b/drivers/net/mlx5/meson.build
@@ -44,6 +44,7 @@ if build
 		'mlx5.c',
 		'mlx5_ethdev.c',
 		'mlx5_flow.c',
+		'mlx5_flow_meter.c',
 		'mlx5_flow_dv.c',
 		'mlx5_flow_verbs.c',
 		'mlx5_mac.c',
@@ -131,6 +132,8 @@ if build
 		'mlx5dv_devx_obj_query_async' ],
 		[ 'HAVE_MLX5DV_DR_ACTION_DEST_DEVX_TIR', 'infiniband/mlx5dv.h',
 		'mlx5dv_dr_action_create_dest_devx_tir' ],
+		[ 'HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER', 'infiniband/mlx5dv.h',
+		'mlx5dv_dr_action_create_flow_meter' ],
 		[ 'HAVE_MLX5DV_DR', 'infiniband/mlx5dv.h',
 		'MLX5DV_DR_DOMAIN_TYPE_NIC_RX' ],
 		[ 'HAVE_MLX5DV_DR_ESWITCH', 'infiniband/mlx5dv.h',
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 91aaa9b..062666c 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -1173,6 +1173,7 @@ struct mlx5_flow_id_pool *
 	.get_module_info = mlx5_get_module_info,
 	.get_module_eeprom = mlx5_get_module_eeprom,
 	.hairpin_cap_get = mlx5_hairpin_cap_get,
+	.mtr_ops_get = mlx5_flow_meter_ops_get,
 };
 
 /* Available operations from secondary process. */
@@ -1236,6 +1237,7 @@ struct mlx5_flow_id_pool *
 	.get_module_info = mlx5_get_module_info,
 	.get_module_eeprom = mlx5_get_module_eeprom,
 	.hairpin_cap_get = mlx5_hairpin_cap_get,
+	.mtr_ops_get = mlx5_flow_meter_ops_get,
 };
 
 /**
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index fab58c9..ea8bcff 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1001,4 +1001,8 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_tis
 	(struct ibv_context *ctx, struct mlx5_devx_tis_attr *tis_attr);
 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);
+
 #endif /* RTE_PMD_MLX5_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
new file mode 100644
index 0000000..6c7a005
--- /dev/null
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright 2018 Mellanox Technologies, Ltd
+ */
+#include <math.h>
+
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
+
+#include "mlx5.h"
+
+static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
+	.capabilities_get = NULL,
+	.meter_profile_add = NULL,
+	.meter_profile_delete = NULL,
+	.create = NULL,
+	.destroy = NULL,
+	.meter_enable = NULL,
+	.meter_disable = NULL,
+	.meter_profile_update = NULL,
+	.meter_dscp_table_update = NULL,
+	.policer_actions_update = NULL,
+	.stats_update = NULL,
+	.stats_read = NULL,
+};
+
+/**
+ * Get meter operations.
+ *
+ * @param dev
+ *   Pointer to Ethernet device structure.
+ * @param arg
+ *   Pointer to set the mtr operations.
+ *
+ * @return
+ *   Always 0.
+ */
+int
+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;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 02/19] net/mlx5: fill meter capabilities using DevX
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 01/19] net/mlx5: add meter operation callback Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 03/19] net/mlx5: allocate flow meter registers Suanming Mou
                     ` (18 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

This commit add the support of fill and get the meter capabilities
from DevX.

Support items:
1. The srTCM color bind mode.
2. Meter share with multiple flows.
3. Action drop.

The color aware mode and multiple meter chaining in a flow are not
supported.

New internal function in rte_mtr_ops callback:
1. capabilities_get()

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.c            |  6 ++++++
 drivers/net/mlx5/mlx5.h            | 13 +++++++++++
 drivers/net/mlx5/mlx5_devx_cmds.c  | 23 ++++++++++++++++++++
 drivers/net/mlx5/mlx5_flow_meter.c | 44 +++++++++++++++++++++++++++++++++++++-
 4 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 062666c..1adef85 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2290,6 +2290,12 @@ struct mlx5_flow_id_pool *
 			DRV_LOG(DEBUG, "LRO session timeout set to %d usec",
 				config.lro.timeout);
 		}
+#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+		if (config.hca_attr.qos.sup && config.hca_attr.qos.srtcm_sup &&
+		    config.dv_flow_en) {
+			priv->mtr_en = 1;
+		}
+#endif
 	}
 	if (config.mprq.enabled && mprq) {
 		if (config.mprq.stride_num_n > mprq_max_stride_num_n ||
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index ea8bcff..be2f23d 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -169,6 +169,17 @@ struct mlx5_devx_mkey_attr {
 	uint32_t pd;
 };
 
+/* HCA qos attributes. */
+struct mlx5_hca_qos_attr {
+	uint32_t sup:1;	/* Whether QOS is supported. */
+	uint32_t srtcm_sup:1; /* Whether srTCM mode is supported. */
+	uint8_t log_max_flow_meter;
+	/* Power of the maximum supported meters. */
+	uint8_t flow_meter_reg_c_ids;
+	/* Bitmap of the reg_Cs available for flow meter to use. */
+
+};
+
 /* HCA supports this number of time periods for LRO. */
 #define MLX5_LRO_NUM_SUPP_PERIODS 4
 
@@ -195,6 +206,7 @@ struct mlx5_hca_attr {
 	uint32_t log_max_hairpin_wq_data_sz:5;
 	uint32_t log_max_hairpin_num_packets:5;
 	uint32_t vhca_id:16;
+	struct mlx5_hca_qos_attr qos;
 };
 
 /* Flow list . */
@@ -692,6 +704,7 @@ struct mlx5_priv {
 	unsigned int master:1; /* Device is a E-Switch master. */
 	unsigned int dr_shared:1; /* DV/DR data is shared. */
 	unsigned int counter_fallback:1; /* Use counter fallback management. */
+	unsigned int mtr_en:1; /* Whether support meter. */
 	uint16_t domain_id; /* Switch domain identifier. */
 	uint16_t vport_id; /* Associated VF vport index (if any). */
 	uint32_t vport_meta_tag; /* Used for vport index match ove VF LAG. */
diff --git a/drivers/net/mlx5/mlx5_devx_cmds.c b/drivers/net/mlx5/mlx5_devx_cmds.c
index d6e89b6..dcb7609 100644
--- a/drivers/net/mlx5/mlx5_devx_cmds.c
+++ b/drivers/net/mlx5/mlx5_devx_cmds.c
@@ -335,6 +335,29 @@ struct mlx5_devx_obj *
 	attr->log_max_hairpin_num_packets = MLX5_GET
 		(cmd_hca_cap, hcattr, log_min_hairpin_wq_data_sz);
 	attr->vhca_id = MLX5_GET(cmd_hca_cap, hcattr, vhca_id);
+	attr->qos.sup = MLX5_GET(cmd_hca_cap, hcattr, qos);
+	if (attr->qos.sup) {
+		MLX5_SET(query_hca_cap_in, in, op_mod,
+			 MLX5_GET_HCA_CAP_OP_MOD_QOS_CAP |
+			 MLX5_HCA_CAP_OPMOD_GET_CUR);
+		rc = mlx5_glue->devx_general_cmd(ctx, in, sizeof(in),
+						 out, sizeof(out));
+		if (rc)
+			goto error;
+		if (status) {
+			DRV_LOG(DEBUG, "Failed to query devx QOS capabilities,"
+				" status %x, syndrome = %x",
+				status, syndrome);
+			return -1;
+		}
+		hcattr = MLX5_ADDR_OF(query_hca_cap_out, out, capability);
+		attr->qos.srtcm_sup =
+				MLX5_GET(qos_cap, hcattr, flow_meter_srtcm);
+		attr->qos.log_max_flow_meter =
+				MLX5_GET(qos_cap, hcattr, log_max_flow_meter);
+		attr->qos.flow_meter_reg_c_ids =
+			MLX5_GET(qos_cap, hcattr, flow_meter_reg_id);
+	}
 	attr->eth_net_offloads = MLX5_GET(cmd_hca_cap, hcattr,
 					  eth_net_offloads);
 	attr->eth_virt = MLX5_GET(cmd_hca_cap, hcattr, eth_virt);
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 6c7a005..9103b6d 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -8,9 +8,51 @@
 #include <rte_mtr_driver.h>
 
 #include "mlx5.h"
+#include "mlx5_flow.h"
+
+/**
+ * Callback to get MTR capabilities.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] cap
+ *   Pointer to save MTR capabilities.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
+		 struct rte_mtr_capabilities *cap,
+		 struct rte_mtr_error *error __rte_unused)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_hca_qos_attr *qattr = &priv->config.hca_attr.qos;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	memset(cap, 0, sizeof(*cap));
+	cap->n_max = 1 << qattr->log_max_flow_meter;
+	cap->n_shared_max = cap->n_max;
+	cap->identical = 1;
+	cap->shared_identical = 1;
+	cap->shared_n_flows_per_mtr_max = 4 << 20;
+	/* 2M flows can share the same meter. */
+	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
+	cap->meter_srtcm_rfc2697_n_max = qattr->srtcm_sup ? cap->n_max : 0;
+	cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
+	cap->policer_action_drop_supported = 1;
+	cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
+			  RTE_MTR_STATS_N_PKTS_DROPPED;
+	return 0;
+}
 
 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
-	.capabilities_get = NULL,
+	.capabilities_get = mlx5_flow_mtr_cap_get,
 	.meter_profile_add = NULL,
 	.meter_profile_delete = NULL,
 	.create = NULL,
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 03/19] net/mlx5: allocate flow meter registers
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 01/19] net/mlx5: add meter operation callback Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 02/19] net/mlx5: fill meter capabilities using DevX Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 04/19] net/mlx5: support meter profile operations Suanming Mou
                     ` (17 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

Meter need the metadata REG_C to have the color match between the prefix
flow and the meter flow.

As the user define or metadata feature will both use the REG_C in the
suffix flow, the color match register meter uses will not impact the
register use in the later sub flow.

Another case is that tag is add before meter flow. In this case, meter
should not touch the register the tag action is using. To avoid that
case, meter should reserve the REG_C's used by user defined MLX5_APP_TAG.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.c      | 20 ++++++++++++++-
 drivers/net/mlx5/mlx5.h      |  2 ++
 drivers/net/mlx5/mlx5_flow.c | 60 +++++++++++++++++++++++++++++++++-----------
 drivers/net/mlx5/mlx5_flow.h |  2 ++
 4 files changed, 68 insertions(+), 16 deletions(-)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 1adef85..3b30169 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2293,7 +2293,25 @@ struct mlx5_flow_id_pool *
 #if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
 		if (config.hca_attr.qos.sup && config.hca_attr.qos.srtcm_sup &&
 		    config.dv_flow_en) {
-			priv->mtr_en = 1;
+			uint8_t reg_c_mask =
+				config.hca_attr.qos.flow_meter_reg_c_ids;
+			/*
+			 * Meter needs two REG_C's for color match and pre-sfx
+			 * flow match. Here get the REG_C for color match.
+			 * REG_C_0 and REG_C_1 is reserved for metadata feature.
+			 */
+			reg_c_mask &= 0xfc;
+			if (__builtin_popcount(reg_c_mask) < 1) {
+				priv->mtr_en = 0;
+				DRV_LOG(WARNING, "No available register for"
+					" meter.");
+			} else {
+				priv->mtr_color_reg = ffs(reg_c_mask) - 1 +
+						      REG_C_0;
+				priv->mtr_en = 1;
+				DRV_LOG(DEBUG, "The REG_C meter uses is %d",
+					priv->mtr_color_reg);
+			}
 		}
 #endif
 	}
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index be2f23d..f19ea23 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -752,6 +752,8 @@ struct mlx5_priv {
 	struct mlx5_flow_id_pool *qrss_id_pool;
 	struct mlx5_hlist *mreg_cp_tbl;
 	/* Hash table of Rx metadata register copy table. */
+	uint8_t mtr_sfx_reg; /* Meter prefix-suffix flow match REG_C. */
+	uint8_t mtr_color_reg; /* Meter color match REG_C. */
 #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];
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 61afc48..b8abe6a 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -344,6 +344,7 @@ enum modify_reg
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_dev_config *config = &priv->config;
+	enum modify_reg start_reg;
 
 	switch (feature) {
 	case MLX5_HAIRPIN_RX:
@@ -375,24 +376,53 @@ enum modify_reg
 		}
 		break;
 	case MLX5_COPY_MARK:
-		return REG_C_3;
+	case MLX5_MTR_SFX:
+		/*
+		 * Metadata COPY_MARK register using is in meter suffix sub
+		 * flow while with meter. It's safe to share the same register.
+		 */
+		return priv->mtr_color_reg != REG_C_2 ? REG_C_2 : REG_C_3;
+	case MLX5_MTR_COLOR:
+		RTE_ASSERT(priv->mtr_color_reg != REG_NONE);
+		return priv->mtr_color_reg;
 	case MLX5_APP_TAG:
 		/*
-		 * Suppose engaging reg_c_2 .. reg_c_7 registers.
-		 * reg_c_2 is reserved for coloring by meters.
-		 * reg_c_3 is reserved for split flows TAG.
+		 * If meter is enable, it will engage two registers for color
+		 * match and flow match. If meter color match is not using the
+		 * REG_C_2, need to skip the REG_C_x be used by meter color
+		 * match.
+		 * If meter is disable, free to use all available registers.
 		 */
-		if (id > (REG_C_7 - REG_C_4))
-			return rte_flow_error_set
-					(error, EINVAL,
-					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-					 NULL, "invalid tag id");
-		if (config->flow_mreg_c[id + REG_C_4 - REG_C_0] == REG_NONE)
-			return rte_flow_error_set
-					(error, ENOTSUP,
-					 RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
-					 NULL, "unsupported tag id");
-		return config->flow_mreg_c[id + REG_C_4 - REG_C_0];
+		if (priv->mtr_color_reg != REG_NONE)
+			start_reg = priv->mtr_color_reg != REG_C_2 ? REG_C_3 :
+				    REG_C_4;
+		else
+			start_reg = REG_C_2;
+		if (id > (REG_C_7 - start_reg))
+			return rte_flow_error_set(error, EINVAL,
+						  RTE_FLOW_ERROR_TYPE_ITEM,
+						  NULL, "invalid tag id");
+		if (config->flow_mreg_c[id + start_reg - REG_C_0] == REG_NONE)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ITEM,
+						  NULL, "unsupported tag id");
+		/*
+		 * This case means meter is using the REG_C_x great than 2.
+		 * Take care not to conflict with meter color REG_C_x.
+		 * If the available index REG_C_y >= REG_C_x, skip the
+		 * color register.
+		 */
+		if (start_reg == REG_C_3 && config->flow_mreg_c
+		    [id + REG_C_3 - REG_C_0] >= priv->mtr_color_reg) {
+			if (config->flow_mreg_c[id + 1 + REG_C_3 - REG_C_0] !=
+			    REG_NONE)
+				return config->flow_mreg_c
+						[id + 1 + REG_C_3 - REG_C_0];
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ITEM,
+						  NULL, "unsupported tag id");
+		}
+		return config->flow_mreg_c[id + start_reg - REG_C_0];
 	}
 	assert(false);
 	return rte_flow_error_set(error, EINVAL,
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index f84ea9d..ac1675456 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -74,6 +74,8 @@ enum mlx5_feature_name {
 	MLX5_FLOW_MARK,
 	MLX5_APP_TAG,
 	MLX5_COPY_MARK,
+	MLX5_MTR_COLOR,
+	MLX5_MTR_SFX,
 };
 
 /* Pattern outer Layer bits. */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 04/19] net/mlx5: support meter profile operations
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (2 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 03/19] net/mlx5: allocate flow meter registers Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 05/19] net/mlx5: validate meter profile Suanming Mou
                     ` (16 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

This commit add the support of meter profile add and delete operations.

New internal functions in rte_mtr_ops callback:
1. meter_profile_add()
2. meter_profile_delete()

Only RTE_MTR_SRTCM_RFC2697 algorithm is supported and can be added. To
add other algorithm will report an error.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/Makefile          |   1 +
 drivers/net/mlx5/mlx5.c            |   1 +
 drivers/net/mlx5/mlx5.h            |   4 +
 drivers/net/mlx5/mlx5_flow.h       |  29 +++++
 drivers/net/mlx5/mlx5_flow_meter.c | 245 ++++++++++++++++++++++++++++++++++++-
 5 files changed, 278 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/Makefile b/drivers/net/mlx5/Makefile
index 0065e55..d01fa73 100644
--- a/drivers/net/mlx5/Makefile
+++ b/drivers/net/mlx5/Makefile
@@ -64,6 +64,7 @@ LDLIBS += $(shell $(RTE_SDK)/buildtools/options-ibverbs-static.sh)
 else
 LDLIBS += -libverbs -lmlx5
 endif
+LDLIBS += -lm
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
 LDLIBS += -lrte_ethdev -lrte_net -lrte_kvargs
 LDLIBS += -lrte_bus_pci
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 3b30169..3bebad3 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2403,6 +2403,7 @@ struct mlx5_flow_id_pool *
 		mlx5_nl_mac_addr_sync(eth_dev);
 	TAILQ_INIT(&priv->flows);
 	TAILQ_INIT(&priv->ctrl_flows);
+	TAILQ_INIT(&priv->flow_meter_profiles);
 	/* Hint libmlx5 to use PMD allocator for data plane resources */
 	struct mlx5dv_ctx_allocators alctr = {
 		.alloc = &mlx5_alloc_verbs_buf,
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index f19ea23..dbeab2b 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -684,6 +684,9 @@ struct mlx5_proc_priv {
 	/* Table of UAR registers for each process. */
 };
 
+/* MTR profile list. */
+TAILQ_HEAD(mlx5_mtr_profiles, mlx5_flow_meter_profile);
+
 #define MLX5_PROC_PRIV(port_id) \
 	((struct mlx5_proc_priv *)rte_eth_devices[port_id].process_private)
 
@@ -754,6 +757,7 @@ struct mlx5_priv {
 	/* Hash table of Rx metadata register copy table. */
 	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. */
 #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];
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index ac1675456..d755d11 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -23,6 +23,7 @@
 
 #include <rte_atomic.h>
 #include <rte_alarm.h>
+#include <rte_mtr.h>
 
 #include "mlx5.h"
 #include "mlx5_prm.h"
@@ -522,6 +523,34 @@ struct mlx5_flow {
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
+#define MLX5_MAN_WIDTH 8
+
+/* RFC2697 parameter structure. */
+struct mlx5_flow_meter_srtcm_rfc2697_prm {
+	/* green_saturation_value = cbs_mantissa * 2^cbs_exponent */
+	uint32_t cbs_exponent:5;
+	uint32_t cbs_mantissa:8;
+	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent) Bytes/Sec */
+	uint32_t cir_exponent:5;
+	uint32_t cir_mantissa:8;
+	/* yellow _saturation_value = ebs_mantissa * 2^ebs_exponent */
+	uint32_t ebs_exponent:5;
+	uint32_t ebs_mantissa:8;
+};
+
+/* Flow meter profile structure. */
+struct mlx5_flow_meter_profile {
+	TAILQ_ENTRY(mlx5_flow_meter_profile) next;
+	/**< Pointer to the next flow meter structure. */
+	uint32_t meter_profile_id; /**< Profile id. */
+	struct rte_mtr_meter_profile profile; /**< Profile detail. */
+	union {
+		struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm_prm;
+		/**< srtcm_rfc2697 struct. */
+	};
+	uint32_t ref_cnt; /**< Use count. */
+};
+
 /* Flow structure. */
 struct rte_flow {
 	TAILQ_ENTRY(rte_flow) next; /**< Pointer to the next flow structure. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 9103b6d..b11962f 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -4,6 +4,7 @@
  */
 #include <math.h>
 
+#include <rte_malloc.h>
 #include <rte_mtr.h>
 #include <rte_mtr_driver.h>
 
@@ -11,6 +12,150 @@
 #include "mlx5_flow.h"
 
 /**
+ * Find meter profile by id.
+ *
+ * @param priv
+ *   Pointer to mlx5_priv.
+ * @param meter_profile_id
+ *   Meter profile id.
+ *
+ * @return
+ *   Pointer to the profile found on success, NULL otherwise.
+ */
+static struct mlx5_flow_meter_profile *
+mlx5_flow_meter_profile_find(struct mlx5_priv *priv, uint32_t meter_profile_id)
+{
+	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
+	struct mlx5_flow_meter_profile *fmp;
+
+	TAILQ_FOREACH(fmp, fmps, next)
+		if (meter_profile_id == fmp->meter_profile_id)
+			return fmp;
+	return NULL;
+}
+
+/**
+ * Calculate mantissa and exponent for cir.
+ *
+ * @param[in] cir
+ *   Value to be calculated.
+ * @param[out] man
+ *   Pointer to the mantissa.
+ * @param[out] exp
+ *   Pointer to the exp.
+ */
+static void
+mlx5_flow_meter_cir_man_exp_calc(int64_t cir, uint8_t *man, uint8_t *exp)
+{
+	int64_t _cir;
+	int64_t delta = INT64_MAX;
+	uint8_t _man = 0;
+	uint8_t _exp = 0;
+	uint64_t m, e;
+
+	for (m = 0; m <= 0xFF; m++) { /* man width 8 bit */
+		for (e = 0; e <= 0x1F; e++) { /* exp width 5bit */
+			_cir = (1000000000ULL * m) >> e;
+			if (llabs(cir - _cir) <= delta) {
+				delta = llabs(cir - _cir);
+				_man = m;
+				_exp = e;
+			}
+		}
+	}
+	*man = _man;
+	*exp = _exp;
+}
+
+/**
+ * Calculate mantissa and exponent for xbs.
+ *
+ * @param[in] xbs
+ *   Value to be calculated.
+ * @param[out] man
+ *   Pointer to the mantissa.
+ * @param[out] exp
+ *   Pointer to the exp.
+ */
+static void
+mlx5_flow_meter_xbs_man_exp_calc(uint64_t xbs, uint8_t *man, uint8_t *exp)
+{
+	int _exp;
+	double _man;
+
+	/* Special case xbs == 0 ? both exp and matissa are 0. */
+	if (xbs == 0) {
+		*man = 0;
+		*exp = 0;
+		return;
+	}
+	/* xbs = xbs_mantissa * 2^xbs_exponent */
+	_man = frexp(xbs, &_exp);
+	_man = _man * pow(2, MLX5_MAN_WIDTH);
+	_exp = _exp - MLX5_MAN_WIDTH;
+	*man = (uint8_t)ceil(_man);
+	*exp = _exp;
+}
+
+/**
+ * Fill the prm meter parameter.
+ *
+ * @param[in,out] fmp
+ *   Pointer to meter profie to be converted.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_param_fill(struct mlx5_flow_meter_profile *fmp,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm = &fmp->srtcm_prm;
+	uint8_t man, exp;
+
+	if (fmp->profile.alg != RTE_MTR_SRTCM_RFC2697)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_PROFILE,
+				NULL, "Metering algorithm not supported.");
+	 /* cbs = cbs_mantissa * 2^cbs_exponent */
+	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.cbs,
+				    &man, &exp);
+	srtcm->cbs_mantissa = man;
+	srtcm->cbs_exponent = exp;
+	/* Check if cbs mantissa is too large. */
+	if (srtcm->cbs_exponent != exp)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+					  "Metering profile parameter cbs is"
+					  " invalid.");
+	/* ebs = ebs_mantissa * 2^ebs_exponent */
+	mlx5_flow_meter_xbs_man_exp_calc(fmp->profile.srtcm_rfc2697.ebs,
+				    &man, &exp);
+	srtcm->ebs_mantissa = man;
+	srtcm->ebs_exponent = exp;
+	/* Check if ebs mantissa is too large. */
+	if (srtcm->ebs_exponent != exp)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+					  "Metering profile parameter ebs is"
+					  " invalid.");
+	/* cir = 8G * cir_mantissa * 1/(2^cir_exponent)) Bytes/Sec */
+	mlx5_flow_meter_cir_man_exp_calc(fmp->profile.srtcm_rfc2697.cir,
+				    &man, &exp);
+	srtcm->cir_mantissa = man;
+	srtcm->cir_exponent = exp;
+	/* Check if cir mantissa is too large. */
+	if (srtcm->cir_exponent != exp)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS, NULL,
+					  "Metering profile parameter cir is"
+					  " invalid.");
+	return 0;
+}
+
+/**
  * Callback to get MTR capabilities.
  *
  * @param[in] dev
@@ -51,10 +196,106 @@
 	return 0;
 }
 
+/**
+ * Callback to add MTR profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_profile_id
+ *   Meter profile id.
+ * @param[in] profile
+ *   Pointer to meter profile detail.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_profile_add(struct rte_eth_dev *dev,
+		       uint32_t meter_profile_id,
+		       struct rte_mtr_meter_profile *profile,
+		       struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
+	struct mlx5_flow_meter_profile *fmp;
+	int ret;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	/* Meter profile memory allocation. */
+	fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile),
+			 RTE_CACHE_LINE_SIZE);
+	if (fmp == NULL)
+		return -rte_mtr_error_set(error, ENOMEM,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL, "Meter profile memory "
+					  "alloc failed.");
+	/* Fill profile info. */
+	fmp->meter_profile_id = meter_profile_id;
+	fmp->profile = *profile;
+	/* Fill the flow meter parameters for the PRM. */
+	ret = mlx5_flow_meter_param_fill(fmp, error);
+	if (ret)
+		goto error;
+	/* Add to list. */
+	TAILQ_INSERT_TAIL(fmps, fmp, next);
+	return 0;
+error:
+	rte_free(fmp);
+	return ret;
+}
+
+/**
+ * Callback to delete MTR profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_profile_id
+ *   Meter profile id.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
+			  uint32_t meter_profile_id,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_profile *fmp;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	/* Meter profile must exist. */
+	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
+	if (fmp == NULL)
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  &meter_profile_id,
+					  "Meter profile id invalid.");
+	/* Check profile is unused. */
+	if (fmp->ref_cnt)
+		return -rte_mtr_error_set(error, EBUSY,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Meter profile in use.");
+	/* Remove from list. */
+	TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
+	rte_free(fmp);
+	return 0;
+}
+
 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.capabilities_get = mlx5_flow_mtr_cap_get,
-	.meter_profile_add = NULL,
-	.meter_profile_delete = NULL,
+	.meter_profile_add = mlx5_flow_meter_profile_add,
+	.meter_profile_delete = mlx5_flow_meter_profile_delete,
 	.create = NULL,
 	.destroy = NULL,
 	.meter_enable = NULL,
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 05/19] net/mlx5: validate meter profile
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (3 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 04/19] net/mlx5: support meter profile operations Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 06/19] net/mlx5: prepare meter flow tables Suanming Mou
                     ` (15 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

The add meter profile should be validated if it is valid or has been add
to the list. Invalid and exist profile should not be add to the list.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_meter.c | 70 ++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_prm.h        |  5 +++
 2 files changed, 75 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index b11962f..5ad5e14 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -35,6 +35,71 @@
 }
 
 /**
+ * Validate the MTR profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_profile_id
+ *   Meter profile id.
+ * @param[in] profile
+ *   Pointer to meter profile detail.
+ * @param[out] error
+ *   Pointer to the error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+mlx5_flow_meter_profile_validate(struct rte_eth_dev *dev,
+				 uint32_t meter_profile_id,
+				 struct rte_mtr_meter_profile *profile,
+				 struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_profile *fmp;
+
+	/* Profile must not be NULL. */
+	if (profile == NULL)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE,
+					  NULL, "Meter profile is null.");
+	/* Meter profile ID must be valid. */
+	if (meter_profile_id == UINT32_MAX)
+		return -rte_mtr_error_set(error, EINVAL,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Meter profile id not valid.");
+	/* Meter profile must not exist. */
+	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
+	if (fmp)
+		return -rte_mtr_error_set(error, EEXIST,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL,
+					  "Meter profile already exists.");
+	if (profile->alg == RTE_MTR_SRTCM_RFC2697) {
+		if (priv->config.hca_attr.qos.srtcm_sup) {
+			/* Verify support for flow meter parameters. */
+			if (profile->srtcm_rfc2697.cir > 0 &&
+			    profile->srtcm_rfc2697.cir <= MLX5_SRTCM_CIR_MAX &&
+			    profile->srtcm_rfc2697.cbs > 0 &&
+			    profile->srtcm_rfc2697.cbs <= MLX5_SRTCM_CBS_MAX &&
+			    profile->srtcm_rfc2697.ebs <= MLX5_SRTCM_EBS_MAX)
+				return 0;
+			else
+				return -rte_mtr_error_set
+					     (error, ENOTSUP,
+					      RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					      NULL,
+					      profile->srtcm_rfc2697.ebs ?
+					      "Metering value ebs must be 0." :
+					      "Invalid metering parameters.");
+		}
+	}
+	return -rte_mtr_error_set(error, ENOTSUP,
+				  RTE_MTR_ERROR_TYPE_METER_PROFILE,
+				  NULL, "Metering algorithm not supported.");
+}
+
+/**
  * Calculate mantissa and exponent for cir.
  *
  * @param[in] cir
@@ -226,6 +291,11 @@
 		return -rte_mtr_error_set(error, ENOTSUP,
 					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
 					  "Meter is not support");
+	/* Check input params. */
+	ret = mlx5_flow_meter_profile_validate(dev, meter_profile_id,
+					       profile, error);
+	if (ret)
+		return ret;
 	/* Meter profile memory allocation. */
 	fmp = rte_calloc(__func__, 1, sizeof(struct mlx5_flow_meter_profile),
 			 RTE_CACHE_LINE_SIZE);
diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h
index a0c37c8..3ebf191 100644
--- a/drivers/net/mlx5/mlx5_prm.h
+++ b/drivers/net/mlx5/mlx5_prm.h
@@ -1768,6 +1768,11 @@ struct mlx5_mini_cqe8 {
 	uint32_t byte_cnt;
 };
 
+/* Maximum value of srTCM metering parameters. */
+#define MLX5_SRTCM_CBS_MAX (0xFF * (1ULL << 0x1F))
+#define MLX5_SRTCM_CIR_MAX (8 * (1ULL << 30) * 0xFF)
+#define MLX5_SRTCM_EBS_MAX 0
+
 /**
  * Convert a user mark to flow mark.
  *
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 06/19] net/mlx5: prepare meter flow tables
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (4 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 05/19] net/mlx5: validate meter profile Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 07/19] net/mlx5: add policer rules operations Suanming Mou
                     ` (14 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

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(+)

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index dbeab2b..8f2c541 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -578,6 +578,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)
@@ -644,12 +646,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 b8abe6a..6e34c7a 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4911,6 +4911,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 d755d11..d8f1537 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;
 };
 
 
@@ -726,4 +772,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 3f3dad0..c0e5470 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. */
@@ -7574,6 +7599,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().
  */
@@ -7639,6 +7897,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)
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 07/19] net/mlx5: add policer rules operations
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (5 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 06/19] net/mlx5: prepare meter flow tables Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 08/19] net/mlx5: support basic meter operations Suanming Mou
                     ` (13 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

This commit create the color rules on the meter table for the packets.

As the prefix flow with meter action colors the packets, the packets
are transferred to the meter table with meter color match flows. Here
we create the flow rules  with green yellow red actions on the meter
table. Packets match the color will be processed by the related color
flow rule.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c    |  46 ++++++++++
 drivers/net/mlx5/mlx5_flow.h    |  18 ++++
 drivers/net/mlx5/mlx5_flow_dv.c | 187 ++++++++++++++++++++++++++++++++++++++--
 3 files changed, 245 insertions(+), 6 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 6e34c7a..2016ead 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4950,6 +4950,52 @@ struct mlx5_meter_domains_infos *
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
+/**
+ * Create policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter *fm,
+			       const struct rte_flow_attr *attr)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policer_rules(dev, fm, attr);
+}
+
+/**
+ * Destroy policer rules.
+ *
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter *fm,
+				const struct rte_flow_attr *attr)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->destroy_policer_rules(dev, fm, attr);
+}
+
 #define MLX5_POOL_QUERY_FREQ_US 1000000
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index d8f1537..489d7c0 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -559,6 +559,8 @@ struct mlx5_meter_domains_infos {
 struct mlx5_flow_meter {
 	uint32_t meter_id;
 	/**< Meter id. */
+	struct rte_mtr_params params;
+	/**< Meter rule parameters. */
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
 	uint32_t ref_cnt;
@@ -636,6 +638,14 @@ typedef int (*mlx5_flow_query_t)(struct rte_eth_dev *dev,
 					    (struct rte_eth_dev *dev);
 typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 					struct mlx5_meter_domains_infos *tbls);
+typedef int (*mlx5_flow_create_policer_rules_t)
+					(struct rte_eth_dev *dev,
+					 struct mlx5_flow_meter *fm,
+					 const struct rte_flow_attr *attr);
+typedef int (*mlx5_flow_destroy_policer_rules_t)
+					(struct rte_eth_dev *dev,
+					 const struct mlx5_flow_meter *fm,
+					 const struct rte_flow_attr *attr);
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
 	mlx5_flow_prepare_t prepare;
@@ -646,6 +656,8 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_query_t query;
 	mlx5_flow_create_mtr_tbls_t create_mtr_tbls;
 	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
+	mlx5_flow_create_policer_rules_t create_policer_rules;
+	mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
 };
 
 
@@ -776,4 +788,10 @@ 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);
+int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
+				   struct mlx5_flow_meter *fm,
+				   const struct rte_flow_attr *attr);
+int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
+				    struct mlx5_flow_meter *fm,
+				    const struct rte_flow_attr *attr);
 #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 c0e5470..aa00b3e 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7660,6 +7660,9 @@ struct field_modify_info modify_tcp[] = {
 	return 0;
 }
 
+/* Number of meter flow actions, count and jump or count and drop. */
+#define METER_ACTIONS 2
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -7697,12 +7700,6 @@ struct field_modify_info modify_tcp[] = {
 		.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;
@@ -7832,6 +7829,182 @@ struct field_modify_info modify_tcp[] = {
 	return NULL;
 }
 
+/**
+ * Destroy domain policer rule.
+ *
+ * @param[in] dt
+ *   Pointer to domain table.
+ */
+static void
+flow_dv_destroy_domain_policer_rule(struct mlx5_meter_domain_info *dt)
+{
+	int i;
+
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		if (dt->policer_rules[i]) {
+			claim_zero(mlx5_glue->dv_destroy_flow
+				  (dt->policer_rules[i]));
+			dt->policer_rules[i] = NULL;
+		}
+	}
+	if (dt->jump_actn) {
+		claim_zero(mlx5_glue->destroy_flow_action(dt->jump_actn));
+		dt->jump_actn = NULL;
+	}
+}
+
+/**
+ * Destroy policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   Always 0.
+ */
+static int
+flow_dv_destroy_policer_rules(struct rte_eth_dev *dev __rte_unused,
+			      const struct mlx5_flow_meter *fm,
+			      const struct rte_flow_attr *attr)
+{
+	struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
+
+	if (!mtb)
+		return 0;
+	if (attr->egress)
+		flow_dv_destroy_domain_policer_rule(&mtb->egress);
+	if (attr->ingress)
+		flow_dv_destroy_domain_policer_rule(&mtb->ingress);
+	if (attr->transfer)
+		flow_dv_destroy_domain_policer_rule(&mtb->transfer);
+	return 0;
+}
+
+/**
+ * Create specify domain meter policer rule.
+ *
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] mtb
+ *   Pointer to DV meter table set.
+ * @param[in] sfx_tb
+ *   Pointer to suffix table.
+ * @param[in] mtr_reg_c
+ *   Color match REG_C.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_forward_rule(struct mlx5_flow_meter *fm,
+				    struct mlx5_meter_domain_info *dtb,
+				    struct mlx5_flow_tbl_resource *sfx_tb,
+				    uint8_t mtr_reg_c)
+{
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf),
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf),
+	};
+	struct mlx5_meter_domains_infos *mtb = fm->mfts;
+	void *actions[METER_ACTIONS];
+	int i;
+
+	/* Create jump action. */
+	if (!sfx_tb)
+		return -1;
+	if (!dtb->jump_actn)
+		dtb->jump_actn =
+			mlx5_glue->dr_create_flow_action_dest_flow_tbl
+							(sfx_tb->obj);
+	if (!dtb->jump_actn) {
+		DRV_LOG(ERR, "Failed to create policer jump action.");
+		goto error;
+	}
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		int j = 0;
+
+		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,
+				       rte_col_2_mlx5_col(i), UINT32_MAX);
+		if (fm->params.action[i] == MTR_POLICER_ACTION_DROP)
+			actions[j++] = mtb->drop_actn;
+		else
+			actions[j++] = dtb->jump_actn;
+		dtb->policer_rules[i] =
+			mlx5_glue->dv_create_flow(dtb->color_matcher,
+						 (void *)&value,
+						  j, actions);
+		if (!dtb->policer_rules[i]) {
+			DRV_LOG(ERR, "Failed to create policer rule.");
+			goto error;
+		}
+	}
+	return 0;
+error:
+	rte_errno = errno;
+	return -1;
+}
+
+/**
+ * Create policer rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policer_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter *fm,
+			     const struct rte_flow_attr *attr)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_domains_infos *mtb = fm->mfts;
+	int ret;
+
+	if (attr->egress) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->egress,
+						priv->sh->tx_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create egress policer.");
+			goto error;
+		}
+	}
+	if (attr->ingress) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->ingress,
+						priv->sh->rx_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create ingress policer.");
+			goto error;
+		}
+	}
+	if (attr->transfer) {
+		ret = flow_dv_create_policer_forward_rule(fm, &mtb->transfer,
+						priv->sh->fdb_mtr_sfx_tbl,
+						priv->mtr_color_reg);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create transfer policer.");
+			goto error;
+		}
+	}
+	return 0;
+error:
+	flow_dv_destroy_policer_rules(dev, fm, attr);
+	return -1;
+}
+
 /*
  * Mutex-protected thunk to lock-free  __flow_dv_translate().
  */
@@ -7899,6 +8072,8 @@ struct field_modify_info modify_tcp[] = {
 	.query = flow_dv_query,
 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
+	.create_policer_rules = flow_dv_create_policer_rules,
+	.destroy_policer_rules = flow_dv_destroy_policer_rules,
 };
 
 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 08/19] net/mlx5: support basic meter operations
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (6 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 07/19] net/mlx5: add policer rules operations Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 09/19] net/mlx5: add meter action creation to the glue Suanming Mou
                     ` (12 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

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>
---
 drivers/net/mlx5/mlx5.c            |   1 +
 drivers/net/mlx5/mlx5.h            |   5 +
 drivers/net/mlx5/mlx5_flow.h       |   8 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 242 ++++++++++++++++++++++++++++++++++++-
 4 files changed, 254 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 3bebad3..b1921c3 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -2403,6 +2403,7 @@ struct mlx5_flow_id_pool *
 		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 = {
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 8f2c541..d8a3d40 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -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_tis
 /* 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_ */
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 489d7c0..aaeb5b3 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -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. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 5ad5e14..76a3180 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -362,12 +362,227 @@
 	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 @@
 	*(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;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 09/19] net/mlx5: add meter action creation to the glue
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (7 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 08/19] net/mlx5: support basic meter operations Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 10/19] net/mlx5: support meter modification operations Suanming Mou
                     ` (11 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

This commit add the meter action creation to the glue code.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_glue.c | 30 ++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_glue.h |  9 +++++++++
 2 files changed, 39 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_glue.c b/drivers/net/mlx5/mlx5_glue.c
index 58c9a82..15197cf 100644
--- a/drivers/net/mlx5/mlx5_glue.c
+++ b/drivers/net/mlx5/mlx5_glue.c
@@ -765,6 +765,34 @@
 	return NULL;
 }
 
+static void *
+mlx5_glue_dv_create_flow_action_meter(struct mlx5dv_dr_flow_meter_attr *attr)
+{
+#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+	return mlx5dv_dr_action_create_flow_meter(attr);
+#else
+	(void)attr;
+	errno = ENOTSUP;
+	return NULL;
+#endif
+}
+
+static int
+mlx5_glue_dv_modify_flow_action_meter(void *action,
+				      struct mlx5dv_dr_flow_meter_attr *attr,
+				      uint64_t modify_bits)
+{
+#if defined(HAVE_MLX5DV_DR) && defined(HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER)
+	return mlx5dv_dr_action_modify_flow_meter(action, attr, modify_bits);
+#else
+	(void)action;
+	(void)attr;
+	(void)modify_bits;
+	errno = ENOTSUP;
+	return errno;
+#endif
+}
+
 static int
 mlx5_glue_dv_destroy_flow(void *flow_id)
 {
@@ -1084,6 +1112,8 @@
 	.dv_create_flow_action_packet_reformat =
 		mlx5_glue_dv_create_flow_action_packet_reformat,
 	.dv_create_flow_action_tag =  mlx5_glue_dv_create_flow_action_tag,
+	.dv_create_flow_action_meter = mlx5_glue_dv_create_flow_action_meter,
+	.dv_modify_flow_action_meter = mlx5_glue_dv_modify_flow_action_meter,
 	.dv_destroy_flow = mlx5_glue_dv_destroy_flow,
 	.dv_destroy_flow_matcher = mlx5_glue_dv_destroy_flow_matcher,
 	.dv_open_device = mlx5_glue_dv_open_device,
diff --git a/drivers/net/mlx5/mlx5_glue.h b/drivers/net/mlx5/mlx5_glue.h
index 7fa8349..7ad6379 100644
--- a/drivers/net/mlx5/mlx5_glue.h
+++ b/drivers/net/mlx5/mlx5_glue.h
@@ -52,6 +52,7 @@
 struct mlx5dv_flow_matcher_attr;
 struct mlx5dv_flow_action_attr;
 struct mlx5dv_flow_match_parameters;
+struct mlx5dv_dr_flow_meter_attr;
 struct ibv_flow_action;
 enum mlx5dv_flow_action_packet_reformat_type { packet_reformat_type = 0, };
 enum mlx5dv_flow_table_type { flow_table_type = 0, };
@@ -80,6 +81,10 @@
 struct mlx5dv_devx_port;
 #endif
 
+#ifndef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
+struct mlx5dv_dr_flow_meter_attr;
+#endif
+
 /* LIB_GLUE_VERSION must be updated every time this structure is modified. */
 struct mlx5_glue {
 	const char *version;
@@ -209,6 +214,10 @@ struct mlx5_glue {
 		 struct mlx5dv_dr_domain *domain,
 		 uint32_t flags, size_t data_sz, void *data);
 	void *(*dv_create_flow_action_tag)(uint32_t tag);
+	void *(*dv_create_flow_action_meter)
+		(struct mlx5dv_dr_flow_meter_attr *attr);
+	int (*dv_modify_flow_action_meter)(void *action,
+		struct mlx5dv_dr_flow_meter_attr *attr, uint64_t modify_bits);
 	int (*dv_destroy_flow)(void *flow);
 	int (*dv_destroy_flow_matcher)(void *matcher);
 	struct ibv_context *(*dv_open_device)(struct ibv_device *device);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 10/19] net/mlx5: support meter modification operations
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (8 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 09/19] net/mlx5: add meter action creation to the glue Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 11/19] net/mlx5: support meter profile update Suanming Mou
                     ` (10 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

This commit add meter enable and disable supoort.

New internal functions in rte_mtr_ops callback:
1. meter_enable()
2. meter_disable()

The meter_enable() enables the meter action and the meter_disable()
disables the meter action.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.h       |  10 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 233 ++++++++++++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_prm.h        |  32 +++++
 3 files changed, 273 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index aaeb5b3..672552b 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -523,6 +523,10 @@ struct mlx5_flow {
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
+/* Flow meter state. */
+#define MLX5_FLOW_METER_DISABLE 0
+#define MLX5_FLOW_METER_ENABLE 1
+
 #define MLX5_MAN_WIDTH 8
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
@@ -553,6 +557,12 @@ struct mlx5_meter_domains_infos {
 	/**< FDB meter table. */
 	void *drop_actn;
 	/**< Drop action as not matched. */
+	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
+	/**< Flow meter parameter. */
+	size_t fmp_size;
+	/**< Flow meter parameter size. */
+	void *meter_action;
+	/**< Flow meter action. */
 };
 
 /* Meter parameter structure. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 76a3180..6966ffc 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -443,6 +443,103 @@
 }
 
 /**
+ * Modify the flow meter action.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5 private data structure.
+ * @param[in] fm
+ *   Pointer to flow meter to be modified.
+ * @param[in] srtcm
+ *   Pointer to meter srtcm description parameter.
+ * @param[in] modify_bits
+ *   The bit in srtcm to be updated.
+ * @param[in] active_state
+ *   The state to be updated.
+ * @return
+ *   0 on success, o negative value otherwise.
+ */
+static int
+mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
+		struct mlx5_flow_meter *fm,
+		const struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm,
+		uint64_t modify_bits, uint32_t active_state)
+{
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
+	uint32_t in[MLX5_ST_SZ_DW(flow_meter_parameters)] = { 0 };
+	uint32_t *attr;
+	struct mlx5dv_dr_flow_meter_attr mod_attr = { 0 };
+	int ret;
+
+	/* Fill command parameters. */
+	mod_attr.reg_c_index = priv->mtr_color_reg - REG_C_0;
+	mod_attr.flow_meter_parameter = in;
+	mod_attr.flow_meter_parameter_sz = fm->mfts->fmp_size;
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
+		mod_attr.active = !!active_state;
+	else
+		mod_attr.active = 0;
+	attr = in;
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_exponent, srtcm->cbs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_mantissa, srtcm->cbs_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_exponent, srtcm->cir_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_mantissa, srtcm->cir_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_exponent, srtcm->ebs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_mantissa, srtcm->ebs_mantissa);
+	}
+	/* Apply modifications to meter only if it was created. */
+	if (fm->mfts->meter_action) {
+		ret = mlx5_glue->dv_modify_flow_action_meter
+					(fm->mfts->meter_action, &mod_attr,
+					rte_cpu_to_be_64(modify_bits));
+		if (ret)
+			return ret;
+	}
+	/* Update succeedded modify meter parameters. */
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE)
+		fm->active_state = !!active_state;
+	attr = fm->mfts->fmp;
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_exponent, srtcm->cbs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cbs_mantissa, srtcm->cbs_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_exponent, srtcm->cir_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, cir_mantissa, srtcm->cir_mantissa);
+	}
+	if (modify_bits & MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS) {
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_exponent, srtcm->ebs_exponent);
+		MLX5_SET(flow_meter_parameters,
+			 attr, ebs_mantissa, srtcm->ebs_mantissa);
+	}
+
+	return 0;
+#else
+	(void)priv;
+	(void)fm;
+	(void)srtcm;
+	(void)modify_bits;
+	(void)active_state;
+	return -ENOTSUP;
+#endif
+}
+
+/**
  * Create meter rules.
  *
  * @param[in] dev
@@ -577,14 +674,146 @@
 	return 0;
 }
 
+/**
+ * Modify meter state.
+ *
+ * @param[in] priv
+ *   Pointer to mlx5 private data structure.
+ * @param[in] fm
+ *   Pointer to flow meter.
+ * @param[in] new_state
+ *   New state to update.
+ * @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_modify_state(struct mlx5_priv *priv,
+			     struct mlx5_flow_meter *fm,
+			     uint32_t new_state,
+			     struct rte_mtr_error *error)
+{
+	static const struct mlx5_flow_meter_srtcm_rfc2697_prm srtcm = {
+		.cbs_exponent = 20,
+		.cbs_mantissa = 191,
+		.cir_exponent = 0,
+		.cir_mantissa = 200,
+		.ebs_exponent = 0,
+		.ebs_mantissa = 0,
+	};
+	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
+			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
+	int ret;
+
+	if (new_state == MLX5_FLOW_METER_DISABLE)
+		ret = mlx5_flow_meter_action_modify(priv, fm, &srtcm,
+						    modify_bits, 0);
+	else
+		ret = mlx5_flow_meter_action_modify(priv, fm,
+						   &fm->profile->srtcm_prm,
+						    modify_bits, 0);
+	if (ret)
+		return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL,
+					  new_state ?
+					  "Failed to enable meter." :
+					  "Failed to disable meter.");
+	return 0;
+}
+
+/**
+ * Callback to enable flow meter.
+ *
+ * @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_enable(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_meter *fm;
+	int ret;
+
+	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 not found.");
+	if (fm->active_state == MLX5_FLOW_METER_ENABLE)
+		return 0;
+	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_ENABLE,
+					   error);
+	if (!ret)
+		fm->active_state = MLX5_FLOW_METER_ENABLE;
+	return ret;
+}
+
+/**
+ * Callback to disable flow meter.
+ *
+ * @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_disable(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_meter *fm;
+	int ret;
+
+	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 not found.");
+	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
+		return 0;
+	ret = mlx5_flow_meter_modify_state(priv, fm, MLX5_FLOW_METER_DISABLE,
+					   error);
+	if (!ret)
+		fm->active_state = MLX5_FLOW_METER_DISABLE;
+	return ret;
+}
+
 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 = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
-	.meter_enable = NULL,
-	.meter_disable = NULL,
+	.meter_enable = mlx5_flow_meter_enable,
+	.meter_disable = mlx5_flow_meter_disable,
 	.meter_profile_update = NULL,
 	.meter_dscp_table_update = NULL,
 	.policer_actions_update = NULL,
diff --git a/drivers/net/mlx5/mlx5_prm.h b/drivers/net/mlx5/mlx5_prm.h
index ebedc90..651006b 100644
--- a/drivers/net/mlx5/mlx5_prm.h
+++ b/drivers/net/mlx5/mlx5_prm.h
@@ -1745,6 +1745,38 @@ struct mlx5_ifc_create_sq_in_bits {
 	struct mlx5_ifc_sqc_bits ctx;
 };
 
+enum {
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_ACTIVE = (1ULL << 0),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS = (1ULL << 1),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR = (1ULL << 2),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EBS = (1ULL << 3),
+	MLX5_FLOW_METER_OBJ_MODIFY_FIELD_EIR = (1ULL << 4),
+};
+
+struct mlx5_ifc_flow_meter_parameters_bits {
+	u8         valid[0x1];			// 00h
+	u8         bucket_overflow[0x1];
+	u8         start_color[0x2];
+	u8         both_buckets_on_green[0x1];
+	u8         meter_mode[0x2];
+	u8         reserved_at_1[0x19];
+	u8         reserved_at_2[0x20]; //04h
+	u8         reserved_at_3[0x3];
+	u8         cbs_exponent[0x5];		// 08h
+	u8         cbs_mantissa[0x8];
+	u8         reserved_at_4[0x3];
+	u8         cir_exponent[0x5];
+	u8         cir_mantissa[0x8];
+	u8         reserved_at_5[0x20];		// 0Ch
+	u8         reserved_at_6[0x3];
+	u8         ebs_exponent[0x5];		// 10h
+	u8         ebs_mantissa[0x8];
+	u8         reserved_at_7[0x3];
+	u8         eir_exponent[0x5];
+	u8         eir_mantissa[0x8];
+	u8         reserved_at_8[0x60];		// 14h-1Ch
+};
+
 /* CQE format mask. */
 #define MLX5E_CQE_FORMAT_MASK 0xc
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 11/19] net/mlx5: support meter profile update
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (9 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 10/19] net/mlx5: support meter modification operations Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 12/19] net/mlx5: expose flow counters management Suanming Mou
                     ` (9 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

This commit add the meter profile update support.

New internal function in rte_mtr_ops callback:
1. meter_profile_update()

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_meter.c | 70 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 6966ffc..7f64924 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -806,6 +806,74 @@
 	return ret;
 }
 
+/**
+ * Callback to update meter profile.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[in] meter_profile_id
+ *   To be updated meter profile 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_profile_update(struct rte_eth_dev *dev,
+			       uint32_t meter_id,
+			       uint32_t meter_profile_id,
+			       struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_flow_meter_profile *old_fmp;
+	struct mlx5_flow_meter *fm;
+	uint64_t modify_bits = MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CBS |
+			       MLX5_FLOW_METER_OBJ_MODIFY_FIELD_CIR;
+	int ret;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  "Meter is not support");
+	/* Meter profile must exist. */
+	fmp = mlx5_flow_meter_profile_find(priv, meter_profile_id);
+	if (fmp == NULL)
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+					  NULL, "Meter profile not found.");
+	/* 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 not found.");
+	/* MTR object already set to meter profile id. */
+	old_fmp = fm->profile;
+	if (fmp == old_fmp)
+		return 0;
+	/* Update the profile. */
+	fm->profile = fmp;
+	/* Update meter params in HW (if not disabled). */
+	if (fm->active_state == MLX5_FLOW_METER_DISABLE)
+		return 0;
+	ret = mlx5_flow_meter_action_modify(priv, fm, &fm->profile->srtcm_prm,
+					      modify_bits, fm->active_state);
+	if (ret) {
+		fm->profile = old_fmp;
+		return -rte_mtr_error_set(error, -ret,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL, "Failed to update meter"
+					  " parmeters in hardware.");
+	}
+	old_fmp->ref_cnt--;
+	fmp->ref_cnt++;
+	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,
@@ -814,7 +882,7 @@
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
-	.meter_profile_update = NULL,
+	.meter_profile_update = mlx5_flow_meter_profile_update,
 	.meter_dscp_table_update = NULL,
 	.policer_actions_update = NULL,
 	.stats_update = NULL,
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 12/19] net/mlx5: expose flow counters management
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (10 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 11/19] net/mlx5: support meter profile update Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 13/19] net/mlx5: add count action to meter Suanming Mou
                     ` (8 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

Expose the flow counter management mechanism for other components to
use.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.h         |  4 ++
 drivers/net/mlx5/mlx5_flow.c    | 83 +++++++++++++++++++++++++++++++++++++++++
 drivers/net/mlx5/mlx5_flow.h    | 11 ++++++
 drivers/net/mlx5/mlx5_flow_dv.c | 68 +++++++++++++++++++++++++++++++++
 4 files changed, 166 insertions(+)

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index d8a3d40..f9e1396 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -959,6 +959,10 @@ void mlx5_flow_async_pool_query_handle(struct mlx5_ibv_shared *sh,
 				       uint64_t async_id, int status);
 void mlx5_set_query_alarm(struct mlx5_ibv_shared *sh);
 void mlx5_flow_query_alarm(void *arg);
+struct mlx5_flow_counter *mlx5_counter_alloc(struct rte_eth_dev *dev);
+void mlx5_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt);
+int mlx5_counter_query(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt,
+		       bool clear, uint64_t *pkts, uint64_t *bytes);
 
 /* mlx5_mp.c */
 void mlx5_mp_req_start_rxtx(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 2016ead..750e58e 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4996,6 +4996,89 @@ struct mlx5_meter_domains_infos *
 	return fops->destroy_policer_rules(dev, fm, attr);
 }
 
+/**
+ * Allocate a counter.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device structure.
+ *
+ * @return
+ *   Pointer to allocated counter  on success, NULL otherwise.
+ */
+struct mlx5_flow_counter *
+mlx5_counter_alloc(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+	struct rte_flow_attr attr = { .transfer = 0 };
+
+	if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) {
+		fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+		return fops->counter_alloc(dev);
+	}
+	DRV_LOG(ERR,
+		"port %u counter allocate is not supported.",
+		 dev->data->port_id);
+	return NULL;
+}
+
+/**
+ * Free a counter.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device structure.
+ * @param[in] cnt
+ *   Pointer to counter to be free.
+ */
+void
+mlx5_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt)
+{
+	const struct mlx5_flow_driver_ops *fops;
+	struct rte_flow_attr attr = { .transfer = 0 };
+
+	if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) {
+		fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+		fops->counter_free(dev, cnt);
+		return;
+	}
+	DRV_LOG(ERR,
+		"port %u counter free is not supported.",
+		 dev->data->port_id);
+}
+
+/**
+ * Query counter statistics.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device structure.
+ * @param[in] cnt
+ *   Pointer to counter to query.
+ * @param[in] clear
+ *   Set to clear counter statistics.
+ * @param[out] pkts
+ *   The counter hits packets number to save.
+ * @param[out] bytes
+ *   The counter hits bytes number to save.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise.
+ */
+int
+mlx5_counter_query(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt,
+		   bool clear, uint64_t *pkts, uint64_t *bytes)
+{
+	const struct mlx5_flow_driver_ops *fops;
+	struct rte_flow_attr attr = { .transfer = 0 };
+
+	if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) {
+		fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+		return fops->counter_query(dev, cnt, clear, pkts, bytes);
+	}
+	DRV_LOG(ERR,
+		"port %u counter query is not supported.",
+		 dev->data->port_id);
+	return -ENOTSUP;
+}
+
 #define MLX5_POOL_QUERY_FREQ_US 1000000
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 672552b..0326330 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -664,6 +664,14 @@ typedef int (*mlx5_flow_destroy_policer_rules_t)
 					(struct rte_eth_dev *dev,
 					 const struct mlx5_flow_meter *fm,
 					 const struct rte_flow_attr *attr);
+typedef struct mlx5_flow_counter * (*mlx5_flow_counter_alloc_t)
+				   (struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_counter_free_t)(struct rte_eth_dev *dev,
+					 struct mlx5_flow_counter *cnt);
+typedef int (*mlx5_flow_counter_query_t)(struct rte_eth_dev *dev,
+					 struct mlx5_flow_counter *cnt,
+					 bool clear, uint64_t *pkts,
+					 uint64_t *bytes);
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
 	mlx5_flow_prepare_t prepare;
@@ -676,6 +684,9 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
 	mlx5_flow_create_policer_rules_t create_policer_rules;
 	mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
+	mlx5_flow_counter_alloc_t counter_alloc;
+	mlx5_flow_counter_free_t counter_free;
+	mlx5_flow_counter_query_t counter_query;
 };
 
 
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index aa00b3e..b273b6c 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -8005,6 +8005,46 @@ struct field_modify_info modify_tcp[] = {
 	return -1;
 }
 
+/**
+ * Query a devx counter.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] cnt
+ *   Pointer to the flow counter.
+ * @param[in] clear
+ *   Set to clear the counter statistics.
+ * @param[out] pkts
+ *   The statistics value of packets.
+ * @param[out] bytes
+ *   The statistics value of bytes.
+ *
+ * @return
+ *   0 on success, otherwise return -1.
+ */
+static int
+flow_dv_counter_query(struct rte_eth_dev *dev,
+		      struct mlx5_flow_counter *cnt, bool clear,
+		      uint64_t *pkts, uint64_t *bytes)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	uint64_t inn_pkts, inn_bytes;
+	int ret;
+
+	if (!priv->config.devx)
+		return -1;
+	ret = _flow_dv_query_count(dev, cnt, &inn_pkts, &inn_bytes);
+	if (ret)
+		return -1;
+	*pkts = inn_pkts - cnt->hits;
+	*bytes = inn_bytes - cnt->bytes;
+	if (clear) {
+		cnt->hits = inn_pkts;
+		cnt->bytes = inn_bytes;
+	}
+	return 0;
+}
+
 /*
  * Mutex-protected thunk to lock-free  __flow_dv_translate().
  */
@@ -8062,6 +8102,31 @@ struct field_modify_info modify_tcp[] = {
 	flow_dv_shared_unlock(dev);
 }
 
+/*
+ * Mutex-protected thunk to lock-free flow_dv_counter_alloc().
+ */
+static struct mlx5_flow_counter *
+flow_dv_counter_allocate(struct rte_eth_dev *dev)
+{
+	struct mlx5_flow_counter *cnt;
+
+	flow_dv_shared_lock(dev);
+	cnt = flow_dv_counter_alloc(dev, 0, 0, 1);
+	flow_dv_shared_unlock(dev);
+	return cnt;
+}
+
+/*
+ * Mutex-protected thunk to lock-free flow_dv_counter_release().
+ */
+static void
+flow_dv_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt)
+{
+	flow_dv_shared_lock(dev);
+	flow_dv_counter_release(dev, cnt);
+	flow_dv_shared_unlock(dev);
+}
+
 const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.validate = flow_dv_validate,
 	.prepare = flow_dv_prepare,
@@ -8074,6 +8139,9 @@ struct field_modify_info modify_tcp[] = {
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
 	.create_policer_rules = flow_dv_create_policer_rules,
 	.destroy_policer_rules = flow_dv_destroy_policer_rules,
+	.counter_alloc = flow_dv_counter_allocate,
+	.counter_free = flow_dv_counter_free,
+	.counter_query = flow_dv_counter_query,
 };
 
 #endif /* HAVE_IBV_FLOW_DV_SUPPORT */
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 13/19] net/mlx5: add count action to meter
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (11 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 12/19] net/mlx5: expose flow counters management Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 14/19] net/mlx5: add meter statistics read and update Suanming Mou
                     ` (7 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

Add count action to meter for metering packet statistics. All the
packets be colored and dropped will be recorded.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c       |  7 +++++--
 drivers/net/mlx5/mlx5_flow.h       | 18 ++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_dv.c    | 16 +++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c | 18 +++++++++++++++++-
 4 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 750e58e..ee964b0 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4916,17 +4916,20 @@ struct rte_flow *
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to the flow meter.
  *
  * @return
  *   Pointer to table set on success, NULL otherwise.
  */
 struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+			  const struct mlx5_flow_meter *fm)
 {
 	const struct mlx5_flow_driver_ops *fops;
 
 	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->create_mtr_tbls(dev);
+	return fops->create_mtr_tbls(dev, fm);
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 0326330..cdcca7a 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -531,6 +531,14 @@ struct mlx5_flow {
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
 
+/* Meter policer statistics */
+struct mlx5_flow_policer_stats {
+	struct mlx5_flow_counter *cnt[RTE_COLORS + 1];
+	/**< Color counter, extra for drop. */
+	uint64_t stats_mask;
+	/**< Statistics mask for the colors. */
+};
+
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
 	struct mlx5_flow_tbl_resource *tbl;
@@ -557,6 +565,8 @@ struct mlx5_meter_domains_infos {
 	/**< FDB meter table. */
 	void *drop_actn;
 	/**< Drop action as not matched. */
+	void *count_actns[RTE_MTR_DROPPED + 1];
+	/**< Counters for match and unmatched statistics. */
 	uint32_t fmp[MLX5_ST_SZ_DW(flow_meter_parameters)];
 	/**< Flow meter parameter. */
 	size_t fmp_size;
@@ -577,6 +587,8 @@ struct mlx5_flow_meter {
 	/**< Meter profile parameters. */
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
+	struct mlx5_flow_policer_stats policer_stats;
+	/**< Meter policer statistics. */
 	uint32_t ref_cnt;
 	/**< Use count. */
 	uint32_t active_state:1;
@@ -653,7 +665,8 @@ typedef int (*mlx5_flow_query_t)(struct rte_eth_dev *dev,
 				 void *data,
 				 struct rte_flow_error *error);
 typedef struct mlx5_meter_domains_infos *(*mlx5_flow_create_mtr_tbls_t)
-					    (struct rte_eth_dev *dev);
+					    (struct rte_eth_dev *dev,
+					     const struct mlx5_flow_meter *fm);
 typedef int (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 					struct mlx5_meter_domains_infos *tbls);
 typedef int (*mlx5_flow_create_policer_rules_t)
@@ -814,7 +827,8 @@ int mlx5_flow_validate_item_geneve(const struct rte_flow_item *item,
 				   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);
+					(struct rte_eth_dev *dev,
+					 const struct mlx5_flow_meter *fm);
 int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_meter_domains_infos *tbl);
 int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index b273b6c..c03950e 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7756,6 +7756,8 @@ struct field_modify_info modify_tcp[] = {
 		DRV_LOG(ERR, "Failed to create meter policer color matcher.");
 		goto error_exit;
 	}
+	if (mtb->count_actns[RTE_MTR_DROPPED])
+		actions[i++] = mtb->count_actns[RTE_MTR_DROPPED];
 	actions[i++] = mtb->drop_actn;
 	/* Default rule: lowest priority, match any, actions: drop. */
 	dtb->policer_rules[RTE_MTR_DROPPED] =
@@ -7776,16 +7778,20 @@ struct field_modify_info modify_tcp[] = {
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
+ * @param[in] fm
+ *   Pointer to the flow meter.
  *
  * @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)
+flow_dv_create_mtr_tbl(struct rte_eth_dev *dev,
+		       const struct mlx5_flow_meter *fm)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_meter_domains_infos *mtb;
 	int ret;
+	int i;
 
 	if (!priv->mtr_en) {
 		rte_errno = ENOTSUP;
@@ -7796,6 +7802,12 @@ struct field_modify_info modify_tcp[] = {
 		DRV_LOG(ERR, "Failed to allocate memory for meter.");
 		return NULL;
 	}
+	/* Create meter count actions */
+	for (i = 0; i <= RTE_MTR_DROPPED; i++) {
+		if (!fm->policer_stats.cnt[i])
+			continue;
+		mtb->count_actns[i] = fm->policer_stats.cnt[i]->action;
+	}
 	/* Create drop action. */
 	mtb->drop_actn = mlx5_glue->dr_create_flow_action_drop();
 	if (!mtb->drop_actn) {
@@ -7931,6 +7943,8 @@ struct field_modify_info modify_tcp[] = {
 
 		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_reg_c,
 				       rte_col_2_mlx5_col(i), UINT32_MAX);
+		if (mtb->count_actns[i])
+			actions[j++] = mtb->count_actns[i];
 		if (fm->params.action[i] == MTR_POLICER_ACTION_DROP)
 			actions[j++] = mtb->drop_actn;
 		else
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 7f64924..7645d92 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -571,6 +571,7 @@
 				.transfer = priv->config.dv_esw_en ? 1 : 0,
 			};
 	int ret;
+	unsigned int i;
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
@@ -597,7 +598,13 @@
 	fm->meter_id = meter_id;
 	fm->profile = fmp;
 	fm->params = *params;
-	fm->mfts = mlx5_flow_create_mtr_tbls(dev);
+	/* Alloc policer counters. */
+	for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++) {
+		fm->policer_stats.cnt[i] = mlx5_counter_alloc(dev);
+		if (!fm->policer_stats.cnt[i])
+			goto error;
+	}
+	fm->mfts = mlx5_flow_create_mtr_tbls(dev, fm);
 	if (!fm->mfts)
 		goto error;
 	ret = mlx5_flow_create_policer_rules(dev, fm, &attr);
@@ -612,6 +619,10 @@
 error:
 	mlx5_flow_destroy_policer_rules(dev, fm, &attr);
 	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
+	/* Free policer counters. */
+	for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
+		if (fm->policer_stats.cnt[i])
+			mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
 	rte_free(fm);
 	return -rte_mtr_error_set(error, -ret,
 				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
@@ -644,6 +655,7 @@
 				.egress = 1,
 				.transfer = priv->config.dv_esw_en ? 1 : 0,
 			};
+	unsigned int i;
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
@@ -667,6 +679,10 @@
 	fmp->ref_cnt--;
 	/* Remove from the flow meter list. */
 	TAILQ_REMOVE(fms, fm, next);
+	/* Free policer counters. */
+	for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
+		if (fm->policer_stats.cnt[i])
+			mlx5_counter_free(dev, fm->policer_stats.cnt[i]);
 	/* Free meter flow table */
 	mlx5_flow_destroy_policer_rules(dev, fm, &attr);
 	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 14/19] net/mlx5: add meter statistics read and update
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (12 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 13/19] net/mlx5: add count action to meter Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 15/19] net/mlx5: add meter attach and detach Suanming Mou
                     ` (6 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

This commit add the meter statistics read and update to check the meter
statistics.

New internal functions in rte_mtr_ops callback:
1. stats_update()
2. stats_read()

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_meter.c | 140 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 138 insertions(+), 2 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 7645d92..c39e703 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -614,6 +614,7 @@
 	TAILQ_INSERT_TAIL(fms, fm, next);
 	fm->active_state = 1; /* Config meter starts as active. */
 	fm->shared = !!shared;
+	fm->policer_stats.stats_mask = params->stats_mask;
 	fm->profile->ref_cnt++;
 	return 0;
 error:
@@ -890,6 +891,141 @@
 	return 0;
 }
 
+/**
+ * Callback to update meter stats mask.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[in] stats_mask
+ *   To be updated stats_mask.
+ * @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_stats_update(struct rte_eth_dev *dev,
+			     uint32_t meter_id,
+			     uint64_t stats_mask,
+			     struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter *fm;
+
+	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.");
+	fm->policer_stats.stats_mask = stats_mask;
+	return 0;
+}
+
+/**
+ * Callback to read meter statistics.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] meter_id
+ *   Meter id.
+ * @param[out] stats
+ *   Pointer to store the statistics.
+ * @param[out] stats_mask
+ *   Pointer to store the stats_mask.
+ * @param[in] clear
+ *   Statistic to be cleared after read 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_stats_read(struct rte_eth_dev *dev,
+			   uint32_t meter_id,
+			   struct rte_mtr_stats *stats,
+			   uint64_t *stats_mask,
+			   int clear,
+			   struct rte_mtr_error *error)
+{
+	static uint64_t meter2mask[RTE_MTR_DROPPED + 1] = {
+		RTE_MTR_STATS_N_PKTS_GREEN | RTE_MTR_STATS_N_BYTES_GREEN,
+		RTE_MTR_STATS_N_PKTS_YELLOW | RTE_MTR_STATS_N_BYTES_YELLOW,
+		RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED,
+		RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED
+	};
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter *fm;
+	struct mlx5_flow_policer_stats *ps;
+	uint64_t pkts_dropped = 0;
+	uint64_t bytes_dropped = 0;
+	uint64_t pkts;
+	uint64_t bytes;
+	int i;
+	int ret = 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.");
+	ps = &fm->policer_stats;
+	*stats_mask = ps->stats_mask;
+	for (i = 0; i < RTE_MTR_DROPPED; i++) {
+		if (*stats_mask & meter2mask[i]) {
+			ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
+						 &bytes);
+			if (ret)
+				goto error;
+			if (fm->params.action[i] == MTR_POLICER_ACTION_DROP) {
+				pkts_dropped += pkts;
+				bytes_dropped += bytes;
+			}
+			/* If need to read the packets, set it. */
+			if ((1 << i) & (*stats_mask & meter2mask[i]))
+				stats->n_pkts[i] = pkts;
+			/* If need to read the bytes, set it. */
+			if ((1 << (RTE_MTR_DROPPED + 1 + i)) &
+			   (*stats_mask & meter2mask[i]))
+				stats->n_bytes[i] = bytes;
+		}
+	}
+	/* Dropped packets/bytes are treated differently. */
+	if (*stats_mask & meter2mask[i]) {
+		ret = mlx5_counter_query(dev, ps->cnt[i], clear, &pkts,
+					 &bytes);
+		if (ret)
+			goto error;
+		pkts += pkts_dropped;
+		bytes += bytes_dropped;
+		/* If need to read the packets, set it. */
+		if ((*stats_mask & meter2mask[i]) &
+		   RTE_MTR_STATS_N_PKTS_DROPPED)
+			stats->n_pkts_dropped = pkts;
+		/* If need to read the bytes, set it. */
+		if ((*stats_mask & meter2mask[i]) &
+		   RTE_MTR_STATS_N_BYTES_DROPPED)
+			stats->n_bytes_dropped = bytes;
+	}
+	return 0;
+error:
+	return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
+				 "Failed to read policer counters.");
+}
+
 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,
@@ -901,8 +1037,8 @@
 	.meter_profile_update = mlx5_flow_meter_profile_update,
 	.meter_dscp_table_update = NULL,
 	.policer_actions_update = NULL,
-	.stats_update = NULL,
-	.stats_read = NULL,
+	.stats_update = mlx5_flow_meter_stats_update,
+	.stats_read = mlx5_flow_meter_stats_read,
 };
 
 /**
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 15/19] net/mlx5: add meter attach and detach
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (13 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 14/19] net/mlx5: add meter statistics read and update Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 16/19] net/mlx5: support meter flow action Suanming Mou
                     ` (5 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

Add the meter attach and detach for the flow create.

When create the flow with meter, first try to find any created meter
action matches the flow meter id. If the meter action is already
created, just attach to it and increase the ref_cnt. If not, create
one.

For the dettach, decrease the ref_cnt, destroy the meter action while
the ref_cnt decreased to zero.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.h            |   6 ++
 drivers/net/mlx5/mlx5_flow.h       |   4 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 141 +++++++++++++++++++++++++++++++++++++
 3 files changed, 151 insertions(+)

diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index f9e1396..e8148ce 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -1040,5 +1040,11 @@ struct mlx5_devx_obj *mlx5_devx_cmd_create_tis
 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);
+struct mlx5_flow_meter *mlx5_flow_meter_attach
+					(struct mlx5_priv *priv,
+					 uint32_t meter_id,
+					 const struct rte_flow_attr *attr,
+					 struct rte_flow_error *error);
+void mlx5_flow_meter_detach(struct mlx5_flow_meter *fm);
 
 #endif /* RTE_PMD_MLX5_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index cdcca7a..ffb6886 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -201,6 +201,7 @@ enum mlx5_feature_name {
 #define MLX5_FLOW_ACTION_SET_TAG (1ull << 32)
 #define MLX5_FLOW_ACTION_MARK_EXT (1ull << 33)
 #define MLX5_FLOW_ACTION_SET_META (1ull << 34)
+#define MLX5_FLOW_ACTION_METER (1ull << 35)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \
@@ -585,6 +586,8 @@ struct mlx5_flow_meter {
 	/**< Meter rule parameters. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
+	struct rte_flow_attr attr;
+	/**< Flow attributes. */
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
 	struct mlx5_flow_policer_stats policer_stats;
@@ -631,6 +634,7 @@ struct rte_flow {
 	struct mlx5_flow_counter *counter; /**< Holds flow counter. */
 	struct mlx5_flow_mreg_copy_resource *mreg_copy;
 	/**< pointer to metadata register copy table resource. */
+	struct mlx5_flow_meter *meter; /**< Holds flow meter. */
 	LIST_HEAD(dev_flows, mlx5_flow) dev_flows;
 	/**< Device flows that are part of the flow. */
 	struct mlx5_fdir *fdir; /**< Pointer to associated FDIR if any. */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index c39e703..7b9d394 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -12,6 +12,62 @@
 #include "mlx5_flow.h"
 
 /**
+ * Create the meter action.
+ *
+ * @param priv
+ *   Pointer to mlx5_priv.
+ * @param[in] fm
+ *   Pointer to flow meter to be converted.
+ *
+ * @return
+ *   Pointer to the meter action on success, NULL otherwise.
+ */
+static void *
+mlx5_flow_meter_action_create(struct mlx5_priv *priv,
+			      struct mlx5_flow_meter *fm)
+{
+#ifdef HAVE_MLX5_DR_CREATE_ACTION_FLOW_METER
+	struct mlx5dv_dr_flow_meter_attr mtr_init;
+	void *attr = fm->mfts->fmp;
+	struct mlx5_flow_meter_srtcm_rfc2697_prm *srtcm =
+						     &fm->profile->srtcm_prm;
+
+	fm->mfts->fmp_size = MLX5_ST_SZ_BYTES(flow_meter_parameters);
+	memset(attr, 0, fm->mfts->fmp_size);
+	MLX5_SET(flow_meter_parameters, attr, valid, 1);
+	MLX5_SET(flow_meter_parameters, attr, bucket_overflow, 1);
+	MLX5_SET(flow_meter_parameters, attr,
+		 start_color, MLX5_FLOW_COLOR_GREEN);
+	MLX5_SET(flow_meter_parameters, attr, both_buckets_on_green, 0);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cbs_exponent, srtcm->cbs_exponent);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cbs_mantissa, srtcm->cbs_mantissa);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cir_exponent, srtcm->cir_exponent);
+	MLX5_SET(flow_meter_parameters,
+		 attr, cir_mantissa, srtcm->cir_mantissa);
+	MLX5_SET(flow_meter_parameters,
+		 attr, ebs_exponent, srtcm->ebs_exponent);
+	MLX5_SET(flow_meter_parameters,
+		 attr, ebs_mantissa, srtcm->ebs_mantissa);
+	mtr_init.next_table =
+		fm->attr.transfer ? fm->mfts->transfer.tbl->obj :
+		    fm->attr.egress ? fm->mfts->egress.tbl->obj :
+				       fm->mfts->ingress.tbl->obj;
+	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
+	mtr_init.flow_meter_parameter = fm->mfts->fmp;
+	mtr_init.flow_meter_parameter_sz = fm->mfts->fmp_size;
+	mtr_init.active = fm->active_state;
+	return mlx5_glue->dv_create_flow_action_meter(&mtr_init);
+#else
+	(void)priv;
+	(void)fm;
+	return NULL;
+#endif
+}
+
+/**
  * Find meter profile by id.
  *
  * @param priv
@@ -1081,3 +1137,88 @@ struct mlx5_flow_meter *
 			return fm;
 	return NULL;
 }
+
+/**
+ * Attach meter to flow.
+ * Unidirectional Meter creation can only be done
+ * when flow direction is known, i.e. when calling meter_attach.
+ *
+ * @param [in] priv
+ *  Pointer to mlx5 private data.
+ * @param [in] meter_id
+ *  Flow meter id.
+ * @param [in] attr
+ *  Pointer to flow attributes.
+ * @param [out] error
+ *  Pointer to error structure.
+ *
+ * @return the flow meter pointer, NULL otherwise.
+ */
+struct mlx5_flow_meter *
+mlx5_flow_meter_attach(struct mlx5_priv *priv, uint32_t meter_id,
+		       const struct rte_flow_attr *attr,
+		       struct rte_flow_error *error)
+{
+	struct mlx5_flow_meter *fm;
+
+	fm = mlx5_flow_meter_find(priv, meter_id);
+	if (fm == NULL) {
+		rte_flow_error_set(error, ENOENT,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Meter object id not valid");
+		goto error;
+	}
+	if (!fm->shared && fm->ref_cnt) {
+		DRV_LOG(ERR, "Cannot share a non-shared meter.");
+		rte_flow_error_set(error, EINVAL,
+				  RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				  "Meter can't be shared");
+		goto error;
+	}
+	if (!fm->ref_cnt++) {
+		RTE_ASSERT(!fm->mfts->meter_action);
+		fm->attr = *attr;
+		/* This also creates the meter object. */
+		fm->mfts->meter_action = mlx5_flow_meter_action_create(priv,
+								       fm);
+		if (!fm->mfts->meter_action)
+			goto error_detach;
+	} else {
+		RTE_ASSERT(fm->mfts->meter_action);
+		if (attr->transfer != fm->attr.transfer ||
+		    attr->ingress != fm->attr.ingress ||
+		    attr->egress != fm->attr.egress) {
+			DRV_LOG(ERR, "meter I/O attributes do not "
+				"match flow I/O attributes.");
+			goto error_detach;
+		}
+	}
+	return fm;
+error_detach:
+	mlx5_flow_meter_detach(fm);
+	rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			  fm->mfts->meter_action ? "Meter attr not match" :
+			  "Meter action create failed");
+error:
+	return NULL;
+}
+
+/**
+ * Detach meter from flow.
+ *
+ * @param [in] fm
+ *  Pointer to flow meter.
+ */
+void
+mlx5_flow_meter_detach(struct mlx5_flow_meter *fm)
+{
+	const struct rte_flow_attr attr = { 0 };
+
+	RTE_ASSERT(fm->ref_cnt);
+	if (--fm->ref_cnt)
+		return;
+	if (fm->mfts->meter_action)
+		mlx5_glue->destroy_flow_action(fm->mfts->meter_action);
+	fm->mfts->meter_action = NULL;
+	fm->attr = attr;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 16/19] net/mlx5: support meter flow action
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (14 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 15/19] net/mlx5: add meter attach and detach Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 17/19] net/mlx5: split meter flow Suanming Mou
                     ` (4 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

Add meter flow action support in flow validate and translate.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow_dv.c | 95 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index c03950e..3e5717e 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -3266,6 +3266,10 @@ struct field_modify_info modify_tcp[] = {
 					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
 					  "can't have 2 fate actions in"
 					  " same flow");
+	if (action_flags & MLX5_FLOW_ACTION_METER)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "jump with meter not support");
 	if (!action->conf)
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
@@ -3379,6 +3383,63 @@ struct field_modify_info modify_tcp[] = {
 	return mlx5_flow_ext_mreg_supported(dev) ? MLX5_MODIFY_NUM :
 						   MLX5_MODIFY_NUM_NO_MREG;
 }
+
+/**
+ * Validate the meter action.
+ *
+ * @param[in] dev
+ *   Pointer to rte_eth_dev structure.
+ * @param[in] action_flags
+ *   Bit-fields that holds the actions detected until now.
+ * @param[in] action
+ *   Pointer to the meter action.
+ * @param[in] attr
+ *   Attributes of flow that includes this action.
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_ernno is set.
+ */
+static int
+mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
+				uint64_t action_flags,
+				const struct rte_flow_action *action,
+				const struct rte_flow_attr *attr,
+				struct rte_flow_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	const struct rte_flow_action_meter *am = action->conf;
+	struct mlx5_flow_meter *fm = mlx5_flow_meter_find(priv, am->mtr_id);
+
+	if (action_flags & MLX5_FLOW_ACTION_METER)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "meter chaining not support");
+	if (action_flags & MLX5_FLOW_ACTION_JUMP)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "meter with jump not support");
+	if (!priv->mtr_en)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
+					  "meter action not supported");
+	if (!fm)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Meter not found");
+	if (fm->ref_cnt && (!(fm->attr.transfer == attr->transfer ||
+	      (!fm->attr.ingress && !attr->ingress && attr->egress) ||
+	      (!fm->attr.egress && !attr->egress && attr->ingress))))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Flow attributes are either invalid "
+					  "or have a conflict with current "
+					  "meter attributes");
+	return 0;
+}
+
 /**
  * Find existing modify-header resource or create and register a new one.
  *
@@ -4752,6 +4813,16 @@ struct field_modify_info modify_tcp[] = {
 		case MLX5_RTE_FLOW_ACTION_TYPE_MARK:
 		case MLX5_RTE_FLOW_ACTION_TYPE_COPY_MREG:
 			break;
+		case RTE_FLOW_ACTION_TYPE_METER:
+			ret = mlx5_flow_validate_action_meter(dev,
+							      action_flags,
+							      actions, attr,
+							      error);
+			if (ret < 0)
+				return ret;
+			action_flags |= MLX5_FLOW_ACTION_METER;
+			++actions_n;
+			break;
 		default:
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
@@ -6527,6 +6598,7 @@ struct field_modify_info modify_tcp[] = {
 		const struct rte_flow_action_count *count = action->conf;
 		const uint8_t *rss_key;
 		const struct rte_flow_action_jump *jump_data;
+		const struct rte_flow_action_meter *mtr;
 		struct mlx5_flow_dv_jump_tbl_resource jump_tbl_resource;
 		struct mlx5_flow_tbl_resource *tbl;
 		uint32_t port_id = 0;
@@ -6893,6 +6965,25 @@ struct field_modify_info modify_tcp[] = {
 				return -rte_errno;
 			action_flags |= MLX5_FLOW_ACTION_SET_TAG;
 			break;
+		case RTE_FLOW_ACTION_TYPE_METER:
+			mtr = actions->conf;
+			if (!flow->meter) {
+				flow->meter = mlx5_flow_meter_attach(priv,
+							mtr->mtr_id, attr,
+							error);
+				if (!flow->meter)
+					return rte_flow_error_set(error,
+						rte_errno,
+						RTE_FLOW_ERROR_TYPE_ACTION,
+						NULL,
+						"meter not found "
+						"or invalid parameters");
+			}
+			/* Set the meter action. */
+			dev_flow->dv.actions[actions_n++] =
+				flow->meter->mfts->meter_action;
+			action_flags |= MLX5_FLOW_ACTION_METER;
+			break;
 		case RTE_FLOW_ACTION_TYPE_END:
 			actions_end = true;
 			if (mhdr_res.actions_num) {
@@ -7494,6 +7585,10 @@ struct field_modify_info modify_tcp[] = {
 		flow_dv_counter_release(dev, flow->counter);
 		flow->counter = NULL;
 	}
+	if (flow->meter) {
+		mlx5_flow_meter_detach(flow->meter);
+		flow->meter = NULL;
+	}
 	while (!LIST_EMPTY(&flow->dev_flows)) {
 		dev_flow = LIST_FIRST(&flow->dev_flows);
 		LIST_REMOVE(dev_flow, next);
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 17/19] net/mlx5: split meter flow
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (15 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 16/19] net/mlx5: support meter flow action Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 18/19] net/mlx5: share tag between meter and metadata Suanming Mou
                     ` (3 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

The flow with meter action will be divided to three sub flows, the
prefix flow, the meter flow and the suffix flow.

For these three sub flows, as the prefix flow and meter flow have the
meter color match. In order the make the packet from prefix flow to
match with the suffix flow, an extra metadata register is allocated.
The prefix flow will add a unique id to the register and the suffix
flow matches on that unique id.

As RSS will also divided the flow to several sub flows, flow with meter
will be divided as the sub flow of the RSS sub flows if have as below:

Original flow ->
	RSS sub flow 1 ->
		Meter sub flow 1 (Contain three sub flows.)
	RSS sub flow 2 ->
		Meter sub flow 2 (Contain three sub flows.)
	......
	RSS sub flow n ->
		Meter sub flow n (Contain three sub flows.)

The metadata feature flow will be split as the sub flow of the meter
suffix flow.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c | 299 ++++++++++++++++++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow.h |   1 +
 2 files changed, 299 insertions(+), 1 deletion(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ee964b0..da3e47a 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -2328,6 +2328,27 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 			flow_qrss_free_id(dev, dev_flow->qrss_id);
 }
 
+/**
+ * Release meter prefix suffix flow match id.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param flow
+ *   Flow to release id's from.
+ */
+static void
+flow_meter_split_id_release(struct rte_eth_dev *dev,
+			    struct rte_flow *flow)
+{
+	struct mlx5_flow *dev_flow;
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	LIST_FOREACH(dev_flow, &flow->dev_flows, next)
+		if (dev_flow->qrss_id)
+			mlx5_flow_id_release(priv->sh->flow_id_pool,
+					     dev_flow->mtr_flow_id);
+}
+
 static int
 flow_null_validate(struct rte_eth_dev *dev __rte_unused,
 		   const struct rte_flow_attr *attr __rte_unused,
@@ -2618,6 +2639,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	enum mlx5_flow_drv_type type = flow->drv_type;
 
 	flow_mreg_split_qrss_release(dev, flow);
+	flow_meter_split_id_release(dev, flow);
 	assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
 	fops = flow_get_drv_ops(type);
 	fops->destroy(dev, flow);
@@ -2645,6 +2667,26 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * Get port id item from the item list.
+ *
+ * @param[in] item
+ *   Pointer to the list of items.
+ *
+ * @return
+ *   Pointer to the port id item if exist, else return NULL.
+ */
+static const struct rte_flow_item *
+find_port_id_item(const struct rte_flow_item *item)
+{
+	assert(item);
+	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
+		if (item->type == RTE_FLOW_ITEM_TYPE_PORT_ID)
+			return item;
+	}
+	return NULL;
+}
+
+/**
  * Get RSS action from the action list.
  *
  * @param[in] actions
@@ -2723,6 +2765,38 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * Check meter action from the action list.
+ *
+ * @param[in] actions
+ *   Pointer to the list of actions.
+ * @param[out] mtr
+ *   Pointer to the meter exist flag.
+ *
+ * @return
+ *   Total number of actions.
+ */
+static int
+flow_check_meter_action(const struct rte_flow_action actions[], uint32_t *mtr)
+{
+	int actions_n = 0;
+
+	assert(mtr);
+	*mtr = 0;
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_METER:
+			*mtr = 1;
+			break;
+		default:
+			break;
+		}
+		actions_n++;
+	}
+	/* Count RTE_FLOW_ACTION_TYPE_END. */
+	return actions_n + 1;
+}
+
+/**
  * Check if the flow should be splited due to hairpin.
  * The reason for the split is that in current HW we can't
  * support encap on Rx, so if a flow have encap we move it
@@ -3366,6 +3440,111 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * Split the meter flow.
+ *
+ * As meter flow will split to three sub flow, other than meter
+ * action, the other actions make sense to only meter accepts
+ * the packet. If it need to be dropped, no other additional
+ * actions should be take.
+ *
+ * One kind of special action which decapsulates the L3 tunnel
+ * header will be in the prefix sub flow, as not to take the
+ * L3 tunnel header into account.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] actions
+ *   Associated actions (list terminated by the END action).
+ * @param[out] actions_sfx
+ *   Suffix flow actions.
+ * @param[out] actions_pre
+ *   Prefix flow actions.
+ * @param[out] pattern_sfx
+ *   The pattern items for the suffix flow.
+ * @param[out] tag_sfx
+ *   Pointer to suffix flow tag.
+ *
+ * @return
+ *   0 on success.
+ */
+static int
+flow_meter_split_prep(struct rte_eth_dev *dev,
+		 const struct rte_flow_action actions[],
+		 struct rte_flow_action actions_sfx[],
+		 struct rte_flow_action actions_pre[])
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_action *tag_action;
+	struct mlx5_rte_flow_action_set_tag *set_tag;
+	struct rte_flow_error error;
+	const struct rte_flow_action_raw_encap *raw_encap;
+	const struct rte_flow_action_raw_decap *raw_decap;
+	uint32_t tag_id;
+
+	/* Add the extra tag action first. */
+	tag_action = actions_pre;
+	tag_action->type = MLX5_RTE_FLOW_ACTION_TYPE_TAG;
+	actions_pre++;
+	/* Prepare the actions for prefix and suffix flow. */
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		switch (actions->type) {
+		case RTE_FLOW_ACTION_TYPE_METER:
+		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+		case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+			memcpy(actions_pre, actions,
+			       sizeof(struct rte_flow_action));
+			actions_pre++;
+			break;
+		case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+			raw_encap = actions->conf;
+			if (raw_encap->size >
+			    (sizeof(struct rte_flow_item_eth) +
+			     sizeof(struct rte_flow_item_ipv4))) {
+				memcpy(actions_sfx, actions,
+				       sizeof(struct rte_flow_action));
+				actions_sfx++;
+			} else {
+				rte_memcpy(actions_pre, actions,
+					   sizeof(struct rte_flow_action));
+				actions_pre++;
+			}
+			break;
+		case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+			raw_decap = actions->conf;
+			/* Size 0 decap means 50 bytes as vxlan decap. */
+			if (raw_decap->size && (raw_decap->size <
+			    (sizeof(struct rte_flow_item_eth) +
+			     sizeof(struct rte_flow_item_ipv4)))) {
+				memcpy(actions_sfx, actions,
+				       sizeof(struct rte_flow_action));
+				actions_sfx++;
+			} else {
+				rte_memcpy(actions_pre, actions,
+					   sizeof(struct rte_flow_action));
+				actions_pre++;
+			}
+			break;
+		default:
+			memcpy(actions_sfx, actions,
+				sizeof(struct rte_flow_action));
+			actions_sfx++;
+			break;
+		}
+	}
+	/* Add end action to the actions. */
+	actions_sfx->type = RTE_FLOW_ACTION_TYPE_END;
+	actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+	actions_pre++;
+	/* Set the tag. */
+	set_tag = (void *)actions_pre;
+	set_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);
+	mlx5_flow_id_get(priv->sh->flow_id_pool, &tag_id);
+	set_tag->data = rte_cpu_to_be_32(tag_id);
+	tag_action->conf = set_tag;
+	return tag_id;
+}
+
+/**
  * Split action list having QUEUE/RSS for metadata register copy.
  *
  * Once Q/RSS action is detected in user's action list, the flow action
@@ -3711,6 +3890,124 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 }
 
 /**
+ * The splitting for meter feature.
+ *
+ * - The meter flow will be split to two flows as prefix and
+ *   suffix flow. The packets make sense only it pass the prefix
+ *   meter action.
+ *
+ * - Reg_C_5 is used for the packet to match betweend prefix and
+ *   suffix flow.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
+ * @param[in] attr
+ *   Flow rule attributes.
+ * @param[in] items
+ *   Pattern specification (list terminated by the END pattern item).
+ * @param[in] actions
+ *   Associated actions (list terminated by the END action).
+ * @param[in] external
+ *   This flow rule is created by request external to PMD.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   0 on success, negative value otherwise
+ */
+static int
+flow_create_split_meter(struct rte_eth_dev *dev,
+			   struct rte_flow *flow,
+			   const struct rte_flow_attr *attr,
+			   const struct rte_flow_item items[],
+			   const struct rte_flow_action actions[],
+			   bool external, struct rte_flow_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_action *sfx_actions = NULL;
+	struct rte_flow_action *pre_actions = NULL;
+	struct rte_flow_item *sfx_items = NULL;
+	const  struct rte_flow_item *sfx_port_id_item;
+	struct mlx5_flow *dev_flow = NULL;
+	struct rte_flow_attr sfx_attr = *attr;
+	uint32_t mtr = 0;
+	uint32_t mtr_tag_id = 0;
+	size_t act_size;
+	size_t item_size;
+	int actions_n = 0;
+	int ret;
+
+	if (priv->mtr_en)
+		actions_n = flow_check_meter_action(actions, &mtr);
+	if (mtr) {
+		struct mlx5_rte_flow_item_tag *tag_spec;
+		/* The five prefix actions: meter, decap, encap, tag, end. */
+		act_size = sizeof(struct rte_flow_action) * (actions_n + 5) +
+			   sizeof(struct rte_flow_action_set_tag);
+		/* tag, end. */
+#define METER_SUFFIX_ITEM 3
+		item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
+			    sizeof(struct mlx5_rte_flow_item_tag);
+		sfx_actions = rte_zmalloc(__func__, (act_size + item_size), 0);
+		if (!sfx_actions)
+			return rte_flow_error_set(error, ENOMEM,
+						  RTE_FLOW_ERROR_TYPE_ACTION,
+						  NULL, "no memory to split "
+						  "meter flow");
+		pre_actions = sfx_actions + actions_n;
+		mtr_tag_id = flow_meter_split_prep(dev, actions, sfx_actions,
+						     pre_actions);
+		if (!mtr_tag_id) {
+			ret = -rte_errno;
+			goto exit;
+		}
+		/* Add the prefix subflow. */
+		ret = flow_create_split_inner(dev, flow, &dev_flow, attr, items,
+						  pre_actions, external, error);
+		if (ret) {
+			ret = -rte_errno;
+			goto exit;
+		}
+		dev_flow->mtr_flow_id = mtr_tag_id;
+		/* Prepare the suffix flow match pattern. */
+		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
+			     act_size);
+		tag_spec = (struct mlx5_rte_flow_item_tag *)(sfx_items +
+			    METER_SUFFIX_ITEM);
+		tag_spec->data = rte_cpu_to_be_32(dev_flow->mtr_flow_id);
+		tag_spec->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0,
+						    error);
+		sfx_items->type = MLX5_RTE_FLOW_ITEM_TYPE_TAG;
+		sfx_items->spec = tag_spec;
+		sfx_items->last = NULL;
+		sfx_items->mask = NULL;
+		sfx_items++;
+		sfx_port_id_item = find_port_id_item(items);
+		if (sfx_port_id_item) {
+			memcpy(sfx_items, sfx_port_id_item,
+			       sizeof(*sfx_items));
+			sfx_items++;
+		}
+		sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
+		sfx_items -= METER_SUFFIX_ITEM;
+		/* Setting the sfx group atrr. */
+		sfx_attr.group = sfx_attr.transfer ?
+				(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_SUFFIX;
+	}
+	/* Add the prefix subflow. */
+	ret = flow_create_split_metadata(dev, flow, &sfx_attr,
+					 sfx_items ? sfx_items : items,
+					 sfx_actions ? sfx_actions : actions,
+					 external, error);
+exit:
+	if (sfx_actions)
+		rte_free(sfx_actions);
+	return ret;
+}
+
+/**
  * Split the flow to subflow set. The splitters might be linked
  * in the chain, like this:
  * flow_create_split_outer() calls:
@@ -3755,7 +4052,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 {
 	int ret;
 
-	ret = flow_create_split_metadata(dev, flow, attr, items,
+	ret = flow_create_split_meter(dev, flow, attr, items,
 					 actions, external, error);
 	assert(ret <= 0);
 	return ret;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index ffb6886..42b4c76 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -521,6 +521,7 @@ struct mlx5_flow {
 		struct mlx5_flow_verbs verbs;
 	};
 	uint32_t qrss_id; /**< Uniqie Q/RSS suffix subflow tag. */
+	uint32_t mtr_flow_id; /**< Unique meter match flow id. */
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 18/19] net/mlx5: share tag between meter and metadata
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (16 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 17/19] net/mlx5: split meter flow Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 19/19] net/mlx5: clean meter resources Suanming Mou
                     ` (2 subsequent siblings)
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

In the meter flow split, metadata flow will be as the sub flow of meter
suffix flow. In meter suffix flow, there is already a unique id tag
exist as for the meter prefix and suffix flow match.

Make metadata feature and meter both share the unique id tag for match.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5_flow.c | 150 +++++++++++++++++++++++--------------------
 drivers/net/mlx5/mlx5_flow.h |   6 +-
 2 files changed, 85 insertions(+), 71 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index da3e47a..092f7b4 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -2328,27 +2328,6 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 			flow_qrss_free_id(dev, dev_flow->qrss_id);
 }
 
-/**
- * Release meter prefix suffix flow match id.
- *
- * @param dev
- *   Pointer to Ethernet device.
- * @param flow
- *   Flow to release id's from.
- */
-static void
-flow_meter_split_id_release(struct rte_eth_dev *dev,
-			    struct rte_flow *flow)
-{
-	struct mlx5_flow *dev_flow;
-	struct mlx5_priv *priv = dev->data->dev_private;
-
-	LIST_FOREACH(dev_flow, &flow->dev_flows, next)
-		if (dev_flow->qrss_id)
-			mlx5_flow_id_release(priv->sh->flow_id_pool,
-					     dev_flow->mtr_flow_id);
-}
-
 static int
 flow_null_validate(struct rte_eth_dev *dev __rte_unused,
 		   const struct rte_flow_attr *attr __rte_unused,
@@ -2639,7 +2618,6 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	enum mlx5_flow_drv_type type = flow->drv_type;
 
 	flow_mreg_split_qrss_release(dev, flow);
-	flow_meter_split_id_release(dev, flow);
 	assert(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
 	fops = flow_get_drv_ops(type);
 	fops->destroy(dev, flow);
@@ -3473,7 +3451,6 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 		 struct rte_flow_action actions_sfx[],
 		 struct rte_flow_action actions_pre[])
 {
-	struct mlx5_priv *priv = dev->data->dev_private;
 	struct rte_flow_action *tag_action;
 	struct mlx5_rte_flow_action_set_tag *set_tag;
 	struct rte_flow_error error;
@@ -3538,7 +3515,10 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	/* Set the tag. */
 	set_tag = (void *)actions_pre;
 	set_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error);
-	mlx5_flow_id_get(priv->sh->flow_id_pool, &tag_id);
+	/*
+	 * Get the id from the qrss_pool to make qrss share the id with meter.
+	 */
+	tag_id = flow_qrss_get_id(dev);
 	set_tag->data = rte_cpu_to_be_32(tag_id);
 	tag_action->conf = set_tag;
 	return tag_id;
@@ -3595,7 +3575,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	struct mlx5_rte_flow_action_set_tag *set_tag;
 	struct rte_flow_action_jump *jump;
 	const int qrss_idx = qrss - actions;
-	uint32_t flow_id;
+	uint32_t flow_id = 0;
 	int ret = 0;
 
 	/*
@@ -3605,43 +3585,50 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	 * As a result, there will be one more action.
 	 */
 	++actions_n;
+	memcpy(split_actions, actions, sizeof(*split_actions) * actions_n);
+	set_tag = (void *)(split_actions + actions_n);
 	/*
-	 * Allocate the new subflow ID. This one is unique within
-	 * device and not shared with representors. Otherwise,
-	 * we would have to resolve multi-thread access synch
-	 * issue. Each flow on the shared device is appended
-	 * with source vport identifier, so the resulting
-	 * flows will be unique in the shared (by master and
-	 * representors) domain even if they have coinciding
-	 * IDs.
+	 * If tag action is not set to void(it means we are not the meter
+	 * suffix flow), add the tag action. Since meter suffix flow already
+	 * has the tag added.
 	 */
-	flow_id = flow_qrss_get_id(dev);
-	if (!flow_id)
-		return rte_flow_error_set(error, ENOMEM,
-					  RTE_FLOW_ERROR_TYPE_ACTION,
-					  NULL, "can't allocate id "
-					  "for split Q/RSS subflow");
-	/* Internal SET_TAG action to set flow ID. */
-	set_tag = (void *)(split_actions + actions_n);
-	*set_tag = (struct mlx5_rte_flow_action_set_tag){
-		.data = flow_id,
-	};
-	ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error);
-	if (ret < 0)
-		return ret;
-	set_tag->id = ret;
+	if (split_actions[qrss_idx].type != RTE_FLOW_ACTION_TYPE_VOID) {
+		/*
+		 * Allocate the new subflow ID. This one is unique within
+		 * device and not shared with representors. Otherwise,
+		 * we would have to resolve multi-thread access synch
+		 * issue. Each flow on the shared device is appended
+		 * with source vport identifier, so the resulting
+		 * flows will be unique in the shared (by master and
+		 * representors) domain even if they have coinciding
+		 * IDs.
+		 */
+		flow_id = flow_qrss_get_id(dev);
+		if (!flow_id)
+			return rte_flow_error_set(error, ENOMEM,
+						  RTE_FLOW_ERROR_TYPE_ACTION,
+						  NULL, "can't allocate id "
+						  "for split Q/RSS subflow");
+		/* Internal SET_TAG action to set flow ID. */
+		*set_tag = (struct mlx5_rte_flow_action_set_tag){
+			.data = flow_id,
+		};
+		ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error);
+		if (ret < 0)
+			return ret;
+		set_tag->id = ret;
+		/* Construct new actions array. */
+		/* Replace QUEUE/RSS action. */
+		split_actions[qrss_idx] = (struct rte_flow_action){
+			.type = MLX5_RTE_FLOW_ACTION_TYPE_TAG,
+			.conf = set_tag,
+		};
+	}
 	/* JUMP action to jump to mreg copy table (CP_TBL). */
 	jump = (void *)(set_tag + 1);
 	*jump = (struct rte_flow_action_jump){
 		.group = MLX5_FLOW_MREG_CP_TABLE_GROUP,
 	};
-	/* Construct new actions array. */
-	memcpy(split_actions, actions, sizeof(*split_actions) * actions_n);
-	/* Replace QUEUE/RSS action. */
-	split_actions[qrss_idx] = (struct rte_flow_action){
-		.type = MLX5_RTE_FLOW_ACTION_TYPE_TAG,
-		.conf = set_tag,
-	};
 	split_actions[actions_n - 2] = (struct rte_flow_action){
 		.type = RTE_FLOW_ACTION_TYPE_JUMP,
 		.conf = jump,
@@ -3742,6 +3729,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	struct rte_flow_action *ext_actions = NULL;
 	struct mlx5_flow *dev_flow = NULL;
 	uint32_t qrss_id = 0;
+	int mtr_sfx = 0;
 	size_t act_size;
 	int actions_n;
 	int ret;
@@ -3772,6 +3760,10 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 		}
 	}
 	if (qrss) {
+		/* Check if it is in meter suffix table. */
+		mtr_sfx = attr->group == (attr->transfer ?
+			  (MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
+			  MLX5_FLOW_TABLE_LEVEL_SUFFIX);
 		/*
 		 * Q/RSS action on NIC Rx should be split in order to pass by
 		 * the mreg copy table (RX_CP_TBL) and then it jumps to the
@@ -3787,6 +3779,16 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 						  NULL, "no memory to split "
 						  "metadata flow");
 		/*
+		 * If we are the suffix flow of meter, tag already exist.
+		 * Set the tag action to void.
+		 */
+		if (mtr_sfx)
+			ext_actions[qrss - actions].type =
+						RTE_FLOW_ACTION_TYPE_VOID;
+		else
+			ext_actions[qrss - actions].type =
+						MLX5_RTE_FLOW_ACTION_TYPE_TAG;
+		/*
 		 * Create the new actions list with removed Q/RSS action
 		 * and appended set tag and jump to register copy table
 		 * (RX_CP_TBL). We should preallocate unique tag ID here
@@ -3794,7 +3796,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 		 */
 		qrss_id = flow_mreg_split_qrss_prep(dev, ext_actions, actions,
 						    qrss, actions_n, error);
-		if (!qrss_id) {
+		if (!mtr_sfx && !qrss_id) {
 			ret = -rte_errno;
 			goto exit;
 		}
@@ -3824,7 +3826,7 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 	if (ret < 0)
 		goto exit;
 	assert(dev_flow);
-	if (qrss_id) {
+	if (qrss) {
 		const struct rte_flow_attr q_attr = {
 			.group = MLX5_FLOW_MREG_ACT_TABLE_GROUP,
 			.ingress = 1,
@@ -3855,22 +3857,32 @@ uint32_t mlx5_flow_adjust_priority(struct rte_eth_dev *dev, int32_t priority,
 			},
 		};
 		uint64_t hash_fields = dev_flow->hash_fields;
+		dev_flow = NULL;
 		/*
-		 * Put unique id in prefix flow due to it is destroyed after
-		 * prefix flow and id will be freed after there is no actual
-		 * flows with this id and identifier reallocation becomes
-		 * possible (for example, for other flows in other threads).
+		 * Configure the tag action only if we are not the meter sub
+		 * flow. Since tag is already marked in the meter suffix sub
+		 * flow.
 		 */
-		dev_flow->qrss_id = qrss_id;
-		qrss_id = 0;
-		dev_flow = NULL;
-		ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error);
-		if (ret < 0)
-			goto exit;
-		q_tag_spec.id = ret;
+		if (qrss_id) {
+			/*
+			 * Put unique id in prefix flow due to it is destroyed
+			 * after prefix flow and id will be freed after there
+			 * is no actual flows with this id and identifier
+			 * reallocation becomes possible (for example, for
+			 * other flows in other threads).
+			 */
+			dev_flow->qrss_id = qrss_id;
+			qrss_id = 0;
+			ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0,
+						   error);
+			if (ret < 0)
+				goto exit;
+			q_tag_spec.id = ret;
+		}
 		/* Add suffix subflow to execute Q/RSS. */
 		ret = flow_create_split_inner(dev, flow, &dev_flow,
-					      &q_attr, q_items, q_actions,
+					      &q_attr, mtr_sfx ? items :
+					      q_items, q_actions,
 					      external, error);
 		if (ret < 0)
 			goto exit;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 42b4c76..bbce63d 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -520,8 +520,10 @@ struct mlx5_flow {
 #endif
 		struct mlx5_flow_verbs verbs;
 	};
-	uint32_t qrss_id; /**< Uniqie Q/RSS suffix subflow tag. */
-	uint32_t mtr_flow_id; /**< Unique meter match flow id. */
+	union {
+		uint32_t qrss_id; /**< Uniqie Q/RSS suffix subflow tag. */
+		uint32_t mtr_flow_id; /**< Unique meter match flow id. */
+	};
 	bool external; /**< true if the flow is created external to PMD. */
 };
 
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* [dpdk-dev] [PATCH v2 19/19] net/mlx5: clean meter resources
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (17 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 18/19] net/mlx5: share tag between meter and metadata Suanming Mou
@ 2019-11-08  3:49   ` Suanming Mou
  2019-11-08  6:20   ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Matan Azrad
  2019-11-08 14:22   ` Raslan Darawsheh
  20 siblings, 0 replies; 42+ messages in thread
From: Suanming Mou @ 2019-11-08  3:49 UTC (permalink / raw)
  To: viacheslavo, matan; +Cc: orika, rasland, dev

When the port is closed or program exits ungraceful, the meter rulers
should be flushed after the flow destroyed.

Signed-off-by: Suanming Mou <suanmingm@mellanox.com>
---
 drivers/net/mlx5/mlx5.c            |  1 +
 drivers/net/mlx5/mlx5_flow.h       |  2 ++
 drivers/net/mlx5/mlx5_flow_meter.c | 61 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)

diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index b1921c3..9a2c711 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -1016,6 +1016,7 @@ struct mlx5_flow_id_pool *
 	mlx5_dev_interrupt_handler_devx_uninstall(dev);
 	mlx5_traffic_disable(dev);
 	mlx5_flow_flush(dev, NULL);
+	mlx5_flow_meter_flush(dev, NULL);
 	/* Prevent crashes when queues are still in use. */
 	dev->rx_pkt_burst = removed_rx_burst;
 	dev->tx_pkt_burst = removed_tx_burst;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index bbce63d..875947c 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -844,4 +844,6 @@ int mlx5_flow_create_policer_rules(struct rte_eth_dev *dev,
 int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
 				    struct mlx5_flow_meter *fm,
 				    const struct rte_flow_attr *attr);
+int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
+			  struct rte_mtr_error *error);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 7b9d394..c4d28b2 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -4,6 +4,7 @@
  */
 #include <math.h>
 
+#include <rte_tailq.h>
 #include <rte_malloc.h>
 #include <rte_mtr.h>
 #include <rte_mtr_driver.h>
@@ -1222,3 +1223,63 @@ struct mlx5_flow_meter *
 	fm->mfts->meter_action = NULL;
 	fm->attr = attr;
 }
+
+/**
+ * Flush meter configuration.
+ *
+ * @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.
+ */
+int
+mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
+	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,
+			};
+	void *tmp;
+	uint32_t i;
+
+	TAILQ_FOREACH_SAFE(fm, fms, next, tmp) {
+		/* Meter object must not have any owner. */
+		RTE_ASSERT(!fm->ref_cnt);
+		/* Get meter profile. */
+		fmp = fm->profile;
+		if (fmp == NULL)
+			return -rte_mtr_error_set(error, EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+				NULL, "MTR object meter profile invalid.");
+		/* Update dependencies. */
+		fmp->ref_cnt--;
+		/* Remove from list. */
+		TAILQ_REMOVE(fms, fm, next);
+		/* Free policer counters. */
+		for (i = 0; i < RTE_DIM(fm->policer_stats.cnt); i++)
+			if (fm->policer_stats.cnt[i])
+				mlx5_counter_free(dev,
+						  fm->policer_stats.cnt[i]);
+		/* Free meter flow table. */
+		mlx5_flow_destroy_policer_rules(dev, fm, &attr);
+		mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
+		rte_free(fm);
+	}
+	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
+		/* Check unused. */
+		RTE_ASSERT(!fmp->ref_cnt);
+		/* Remove from list. */
+		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
+		rte_free(fmp);
+	}
+	return 0;
+}
-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (18 preceding siblings ...)
  2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 19/19] net/mlx5: clean meter resources Suanming Mou
@ 2019-11-08  6:20   ` Matan Azrad
  2019-11-08 14:22   ` Raslan Darawsheh
  20 siblings, 0 replies; 42+ messages in thread
From: Matan Azrad @ 2019-11-08  6:20 UTC (permalink / raw)
  To: Suanming Mou, Slava Ovsiienko; +Cc: Ori Kam, Raslan Darawsheh, dev



From: Suanming Mou
> The patches introduce the meter action support for mlx5.
> The design of the implementation was introduced in RFC as below:
> https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Finbox.
> dpdk.org%2Fdev%2Fb994cd03-02f6-cd50-120f-
> dcf0941e4485%40mellanox.com&amp;data=02%7C01%7Cmatan%40mellanox
> .com%7C95ee54ab6dcb43f951bb08d763feab78%7Ca652971c7d2e4d9ba6a4d1
> 49256f461b%7C0%7C0%7C637087817814455376&amp;sdata=BTjZsNhFxfWvF
> Aw%2F4UHVpBi2GIWGf0LCmRhzFibAUXU%3D&amp;reserved=0
> 
> The implementation is followed RFC to split flow with meter to three sub
> flows.
> Prefix flow -> Meter flow -> Suffix flow
> 
> The srTCM color blind mode is supported only, color aware mode and
> multiple meter chaining are not supported.
> 
> The patch set add the operations to get the capabilities of the meter action,
> create/destroy the action, validate the action, attach/detach the action,
> update the action, query the action statistics and flush the actions resources.
> 
> Besides these, as the flow with meter action is split to three sub flows for
> coloring(in prefix flow), color checking(in meter flow), left actions applying (in
> suffix flow), two registers are used for the color match and prefix-suffix flow
> match. That's what the "allocate flow meter registers" patch does.
> 
> As with the three sub flows, two more flow tables are created for the meter
> flow and suffix flow in patch "prepare meter flow tables". As wrote in the
> RFC, meter flow and suffix flow are separated since meter maybe shared
> with multiple flows.
> 
> For the meter action statistics's query, the DevX flow counter is exposed to
> meter action in patch "expose flow counters management".
> 
> In the "split meter flow" patch, flow with meter is split to three sub flow. The
> *_DECAP and meter action will be in the prefix flow.
> And an extra tag action with unique flow id to match with the suffix flow is
> also added to the prefix flow. The suffix flow will apply all the left actions
> while the flow id in tag item matches.
> 
> Since the metadata copy mark action is in the meter suffix flow, the REG_C
> for cpoy mark and prefix-suffix flow match is shared.
> Once the meter suffix flow add the tag, metadata suffix sub flow won't add
> the tag anymore but share the tag is enough. It's done in the "share tag
> between meter and metadata" patch.
> 
> ---
> v2: rebased on top of the latest code with metadata feature
> 
For all the series:
Acked-by: Matan Azrad <matan@mellanox.com>

> Suanming Mou (19):
>   net/mlx5: add meter operation callback
>   net/mlx5: fill meter capabilities using DevX
>   net/mlx5: allocate flow meter registers
>   net/mlx5: support meter profile operations
>   net/mlx5: validate meter profile
>   net/mlx5: prepare meter flow tables
>   net/mlx5: add policer rules operations
>   net/mlx5: support basic meter operations
>   net/mlx5: add meter action creation to the glue
>   net/mlx5: support meter modification operations
>   net/mlx5: support meter profile update
>   net/mlx5: expose flow counters management
>   net/mlx5: add count action to meter
>   net/mlx5: add meter statistics read and update
>   net/mlx5: add meter attach and detach
>   net/mlx5: support meter flow action
>   net/mlx5: split meter flow
>   net/mlx5: share tag between meter and metadata
>   net/mlx5: clean meter resources
> 
>  drivers/net/mlx5/Makefile          |    7 +
>  drivers/net/mlx5/meson.build       |    3 +
>  drivers/net/mlx5/mlx5.c            |   29 +
>  drivers/net/mlx5/mlx5.h            |   46 ++
>  drivers/net/mlx5/mlx5_devx_cmds.c  |   23 +
>  drivers/net/mlx5/mlx5_flow.c       |  632 ++++++++++++++++--
>  drivers/net/mlx5/mlx5_flow.h       |  153 ++++-
>  drivers/net/mlx5/mlx5_flow_dv.c    |  612 +++++++++++++++++
>  drivers/net/mlx5/mlx5_flow_meter.c | 1285
> ++++++++++++++++++++++++++++++++++++
>  drivers/net/mlx5/mlx5_glue.c       |   30 +
>  drivers/net/mlx5/mlx5_glue.h       |    9 +
>  drivers/net/mlx5/mlx5_prm.h        |   45 ++
>  12 files changed, 2812 insertions(+), 62 deletions(-)  create mode 100644
> drivers/net/mlx5/mlx5_flow_meter.c
> 
> --
> 1.8.3.1


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter
  2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
                     ` (19 preceding siblings ...)
  2019-11-08  6:20   ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Matan Azrad
@ 2019-11-08 14:22   ` Raslan Darawsheh
  20 siblings, 0 replies; 42+ messages in thread
From: Raslan Darawsheh @ 2019-11-08 14:22 UTC (permalink / raw)
  To: Suanming Mou, Slava Ovsiienko, Matan Azrad; +Cc: Ori Kam, dev

Hi,

> -----Original Message-----
> From: Suanming Mou <suanmingm@mellanox.com>
> Sent: Friday, November 8, 2019 5:49 AM
> To: Slava Ovsiienko <viacheslavo@mellanox.com>; Matan Azrad
> <matan@mellanox.com>
> Cc: Ori Kam <orika@mellanox.com>; Raslan Darawsheh
> <rasland@mellanox.com>; dev@dpdk.org
> Subject: [PATCH v2 00/19] net/mlx5: support meter
> 
> The patches introduce the meter action support for mlx5.
> The design of the implementation was introduced in RFC as below:
> https://eur03.safelinks.protection.outlook.com/?url=http%3A%2F%2Finbox.
> dpdk.org%2Fdev%2Fb994cd03-02f6-cd50-120f-
> dcf0941e4485%40mellanox.com&amp;data=02%7C01%7Crasland%40mellano
> x.com%7C95ee54ab6dcb43f951bb08d763feab78%7Ca652971c7d2e4d9ba6a4d
> 149256f461b%7C0%7C0%7C637087817814515342&amp;sdata=XUrJiS50aeFhg
> y8Wsm1JtGJcA1hQpINLVzTgUJxDDfk%3D&amp;reserved=0
> 
> The implementation is followed RFC to split flow with meter to three sub
> flows.
> Prefix flow -> Meter flow -> Suffix flow
> 
> The srTCM color blind mode is supported only, color aware mode and
> multiple meter chaining are not supported.
> 
> The patch set add the operations to get the capabilities of the meter action,
> create/destroy the action, validate the action, attach/detach the action,
> update the action, query the action statistics and flush the actions resources.
> 
> Besides these, as the flow with meter action is split to three sub flows for
> coloring(in prefix flow), color checking(in meter flow), left actions applying (in
> suffix flow), two registers are used for the color match and prefix-suffix flow
> match. That's what the "allocate flow meter registers" patch does.
> 
> As with the three sub flows, two more flow tables are created for the meter
> flow and suffix flow in patch "prepare meter flow tables". As wrote in the
> RFC, meter flow and suffix flow are separated since meter maybe shared
> with multiple flows.
> 
> For the meter action statistics's query, the DevX flow counter is exposed to
> meter action in patch "expose flow counters management".
> 
> In the "split meter flow" patch, flow with meter is split to three sub flow. The
> *_DECAP and meter action will be in the prefix flow.
> And an extra tag action with unique flow id to match with the suffix flow is
> also added to the prefix flow. The suffix flow will apply all the left actions
> while the flow id in tag item matches.
> 
> Since the metadata copy mark action is in the meter suffix flow, the REG_C
> for cpoy mark and prefix-suffix flow match is shared.
> Once the meter suffix flow add the tag, metadata suffix sub flow won't add
> the tag anymore but share the tag is enough. It's done in the "share tag
> between meter and metadata" patch.
> 
> ---
> v2: rebased on top of the latest code with metadata feature
> 
> Suanming Mou (19):
>   net/mlx5: add meter operation callback
>   net/mlx5: fill meter capabilities using DevX
>   net/mlx5: allocate flow meter registers
>   net/mlx5: support meter profile operations
>   net/mlx5: validate meter profile
>   net/mlx5: prepare meter flow tables
>   net/mlx5: add policer rules operations
>   net/mlx5: support basic meter operations
>   net/mlx5: add meter action creation to the glue
>   net/mlx5: support meter modification operations
>   net/mlx5: support meter profile update
>   net/mlx5: expose flow counters management
>   net/mlx5: add count action to meter
>   net/mlx5: add meter statistics read and update
>   net/mlx5: add meter attach and detach
>   net/mlx5: support meter flow action
>   net/mlx5: split meter flow
>   net/mlx5: share tag between meter and metadata
>   net/mlx5: clean meter resources
> 
>  drivers/net/mlx5/Makefile          |    7 +
>  drivers/net/mlx5/meson.build       |    3 +
>  drivers/net/mlx5/mlx5.c            |   29 +
>  drivers/net/mlx5/mlx5.h            |   46 ++
>  drivers/net/mlx5/mlx5_devx_cmds.c  |   23 +
>  drivers/net/mlx5/mlx5_flow.c       |  632 ++++++++++++++++--
>  drivers/net/mlx5/mlx5_flow.h       |  153 ++++-
>  drivers/net/mlx5/mlx5_flow_dv.c    |  612 +++++++++++++++++
>  drivers/net/mlx5/mlx5_flow_meter.c | 1285
> ++++++++++++++++++++++++++++++++++++
>  drivers/net/mlx5/mlx5_glue.c       |   30 +
>  drivers/net/mlx5/mlx5_glue.h       |    9 +
>  drivers/net/mlx5/mlx5_prm.h        |   45 ++
>  12 files changed, 2812 insertions(+), 62 deletions(-)  create mode 100644
> drivers/net/mlx5/mlx5_flow_meter.c
> 
> --
> 1.8.3.1


Series applied to next-net-mlx,

Kindest regards,
Raslan Darawsheh

^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, back to index

Thread overview: 42+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-06 15:11 [dpdk-dev] [PATCH 00/19] net/mlx5: support meter Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 01/19] net/mlx5: add meter operation callback Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 02/19] net/mlx5: fill meter capabilities using DevX Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 03/19] net/mlx5: allocate flow meter registers Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 04/19] net/mlx5: support meter profile operations Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 05/19] net/mlx5: validate meter profile Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 06/19] net/mlx5: prepare meter flow tables Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 07/19] net/mlx5: add policer rules operations Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 08/19] net/mlx5: support basic meter operations Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 09/19] net/mlx5: add meter action creation to the glue Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 10/19] net/mlx5: support meter modification operations Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 11/19] net/mlx5: support meter profile update Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 12/19] net/mlx5: expose flow counters management Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 13/19] net/mlx5: add count action to meter Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 14/19] net/mlx5: add meter statistics read and update Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 15/19] net/mlx5: add meter attach and detach Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 16/19] net/mlx5: support meter flow action Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 17/19] net/mlx5: split meter flow Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 18/19] net/mlx5: share tag between meter and metadata Suanming Mou
2019-11-06 15:11 ` [dpdk-dev] [PATCH 19/19] net/mlx5: clean meter resources Suanming Mou
2019-11-08  3:49 ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 01/19] net/mlx5: add meter operation callback Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 02/19] net/mlx5: fill meter capabilities using DevX Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 03/19] net/mlx5: allocate flow meter registers Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 04/19] net/mlx5: support meter profile operations Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 05/19] net/mlx5: validate meter profile Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 06/19] net/mlx5: prepare meter flow tables Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 07/19] net/mlx5: add policer rules operations Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 08/19] net/mlx5: support basic meter operations Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 09/19] net/mlx5: add meter action creation to the glue Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 10/19] net/mlx5: support meter modification operations Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 11/19] net/mlx5: support meter profile update Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 12/19] net/mlx5: expose flow counters management Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 13/19] net/mlx5: add count action to meter Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 14/19] net/mlx5: add meter statistics read and update Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 15/19] net/mlx5: add meter attach and detach Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 16/19] net/mlx5: support meter flow action Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 17/19] net/mlx5: split meter flow Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 18/19] net/mlx5: share tag between meter and metadata Suanming Mou
2019-11-08  3:49   ` [dpdk-dev] [PATCH v2 19/19] net/mlx5: clean meter resources Suanming Mou
2019-11-08  6:20   ` [dpdk-dev] [PATCH v2 00/19] net/mlx5: support meter Matan Azrad
2019-11-08 14:22   ` Raslan Darawsheh

DPDK-dev Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/dpdk-dev/0 dpdk-dev/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 dpdk-dev dpdk-dev/ https://lore.kernel.org/dpdk-dev \
		dev@dpdk.org
	public-inbox-index dpdk-dev

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.dpdk.dev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git