DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations
@ 2021-04-01  8:16 Li Zhang
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 1/4] " Li Zhang
                   ` (10 more replies)
  0 siblings, 11 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-01  8:16 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Depends-on: series=15998  ("Add ASO meter support in MLX5 PMD ")
https://patchwork.dpdk.org/project/dpdk/list/?series=15998

Depends-on: series=16037  ("Support meter policy API ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16037

Li Zhang (3):
  net/mlx5: support meter policy operations
  net/mlx5: support meter creation with policy
  net/mlx5: prepare sub-policy for a flow with meter

Shun Hao (1):
  net/mlx5: connect meter policy to created flows

 doc/guides/nics/mlx5.rst           |   12 +
 drivers/net/mlx5/linux/mlx5_os.c   |   13 +-
 drivers/net/mlx5/mlx5.c            |   76 +-
 drivers/net/mlx5/mlx5.h            |  197 ++-
 drivers/net/mlx5/mlx5_flow.c       |  614 +++++++++-
 drivers/net/mlx5/mlx5_flow.h       |  120 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1842 ++++++++++++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_meter.c |  738 ++++++++++-
 9 files changed, 3288 insertions(+), 334 deletions(-)

-- 
2.27.0


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

* [dpdk-dev] [PATCH 1/4] net/mlx5: support meter policy operations
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-01  8:16 ` Li Zhang
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 2/4] net/mlx5: support meter creation with policy Li Zhang
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-01  8:16 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Signed-off-by: Li Zhang <lizh@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |    2 +-
 drivers/net/mlx5/mlx5.c            |   76 +-
 drivers/net/mlx5/mlx5.h            |  145 ++-
 drivers/net/mlx5/mlx5_flow.c       |  169 +++-
 drivers/net/mlx5/mlx5_flow.h       |   69 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1374 +++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c |  449 ++++++++-
 8 files changed, 2176 insertions(+), 118 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 772feff598..859b9098dc 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1246,7 +1246,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			log_obj_size <=
 			config->hca_attr.qos.log_meter_aso_max_alloc) {
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv);
+				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
 				if (err) {
 					err = -err;
 					goto error;
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 3cc184a2af..e3efad500c 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -350,6 +350,20 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {
 		.free = mlx5_free,
 		.type = "mlx5_shared_action_rss",
 	},
+	[MLX5_IPOOL_MTR_POLICY] = {
+		/**
+		 * The ipool index should grow continually from small to big,
+		 * for policy idx, so not set grow_trunk to avoid policy index
+		 * not jump continually.
+		 */
+		.size = sizeof(struct mlx5_flow_meter_sub_policy),
+		.trunk_size = 64,
+		.need_lock = 1,
+		.release_mem_en = 1,
+		.malloc = mlx5_malloc,
+		.free = mlx5_free,
+		.type = "mlx5_meter_policy_ipool",
+	},
 };
 
 
@@ -549,27 +563,24 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh)
  *   Pointer to mlx5_dev_ctx_shared object to free
  */
 int
-mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv)
+mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!priv->mtr_idx_tbl) {
-		priv->mtr_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
-		if (!priv->mtr_idx_tbl) {
-			DRV_LOG(ERR, "fail to create meter lookup table.");
-			rte_errno = ENOMEM;
-			return -ENOMEM;
-		}
-	}
-	if (!priv->sh->mtrmng) {
-		priv->sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
-			sizeof(*priv->sh->mtrmng),
+	if (!sh->mtrmng) {
+		sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(*sh->mtrmng),
 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
-		if (!priv->sh->mtrmng) {
-			DRV_LOG(ERR, "mlx5_aso_mtr_pools_mng allocation was failed.");
+		if (!sh->mtrmng) {
+			DRV_LOG(ERR,
+			"mlx5_aso_mtr_pools_mng allocation was failed.");
 			rte_errno = ENOMEM;
 			return -ENOMEM;
 		}
-		rte_spinlock_init(&priv->sh->mtrmng->mtrsl);
-		LIST_INIT(&priv->sh->mtrmng->meters);
+		if (sh->meter_aso_en) {
+			rte_spinlock_init(&sh->mtrmng->pools_mng.mtrsl);
+			LIST_INIT(&sh->mtrmng->pools_mng.meters);
+			sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		}
 	}
 	return 0;
 }
@@ -586,26 +597,29 @@ mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
 {
 	struct mlx5_aso_mtr_pool *mtr_pool;
 	struct mlx5_aso_mtr *aso_mtr;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng;
+	struct mlx5_flow_mtr_mng *mtrmng = sh->mtrmng;
 	uint32_t idx;
 	int i;
 
-	mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
-	idx = mtrmng->n_valid;
-	while (idx--) {
-		mtr_pool = mtrmng->pools[idx];
-		for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
-			aso_mtr = &mtr_pool->mtrs[i];
-			if (aso_mtr->fm.meter_action)
-				claim_zero(mlx5_glue->destroy_flow_action
-						(aso_mtr->fm.meter_action));
-		}
-		claim_zero(mlx5_devx_cmd_destroy
+	if (sh->meter_aso_en) {
+		mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
+		idx = mtrmng->pools_mng.n_valid;
+		while (idx--) {
+			mtr_pool = mtrmng->pools_mng.pools[idx];
+			for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
+				aso_mtr = &mtr_pool->mtrs[i];
+				if (aso_mtr->fm.meter_action)
+					claim_zero
+					(mlx5_glue->destroy_flow_action
+					(aso_mtr->fm.meter_action));
+			}
+			claim_zero(mlx5_devx_cmd_destroy
 						(mtr_pool->devx_obj));
-		mtrmng->n_valid--;
-		mlx5_free(mtr_pool);
+			mtrmng->pools_mng.n_valid--;
+			mlx5_free(mtr_pool);
+		}
+		mlx5_free(sh->mtrmng->pools_mng.pools);
 	}
-	mlx5_free(sh->mtrmng->pools);
 	mlx5_free(sh->mtrmng);
 	sh->mtrmng = NULL;
 }
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index b182fb6c19..a2d47cff16 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -56,6 +56,7 @@ enum mlx5_ipool_index {
 	MLX5_IPOOL_RTE_FLOW, /* Pool for rte_flow. */
 	MLX5_IPOOL_RSS_EXPANTION_FLOW_ID, /* Pool for Queue/RSS flow ID. */
 	MLX5_IPOOL_RSS_SHARED_ACTIONS, /* Pool for RSS shared actions. */
+	MLX5_IPOOL_MTR_POLICY, /* Pool for meter policy resource. */
 	MLX5_IPOOL_MAX,
 };
 
@@ -589,9 +590,115 @@ struct mlx5_dev_shared_port {
 	/* Aging information for per port. */
 };
 
+/*
+ * Max number of actions per DV flow.
+ * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
+ * in rdma-core file providers/mlx5/verbs.c.
+ */
+#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
+
 /*ASO flow meter structures*/
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
+/* Yellow is not supported. */
+#define MLX5_MTR_RTE_COLORS (RTE_COLOR_GREEN + 1)
+/* table_id 22 bits in mlx5_flow_tbl_key so limit policy number. */
+#define MLX5_MAX_SUB_POLICY_TBL_NUM 0x3FFFFF
+
+enum mlx5_meter_domain {
+	MLX5_MTR_DOMAIN_INGRESS,
+	MLX5_MTR_DOMAIN_EGRESS,
+	MLX5_MTR_DOMAIN_TRANSFER,
+	MLX5_MTR_DOMAIN_MAX,
+};
+#define MLX5_MTR_DOMAIN_INGRESS_BIT  (1 << MLX5_MTR_DOMAIN_INGRESS)
+#define MLX5_MTR_DOMAIN_EGRESS_BIT   (1 << MLX5_MTR_DOMAIN_EGRESS)
+#define MLX5_MTR_DOMAIN_TRANSFER_BIT (1 << MLX5_MTR_DOMAIN_TRANSFER)
+#define MLX5_MTR_ALL_DOMAIN_BIT      (0x7)
+
+/* Meter sub-policy structure.
+ * Each RSS TIR in meter policy need its own sub-policy resource.
+ */
+struct mlx5_flow_meter_sub_policy {
+	uint32_t main_policy_id:1;
+	/* Main policy id is same as this sub_policy id. */
+	uint32_t idx:31;
+	/* Index to sub_policy ipool entity. */
+	void *main_policy;
+	/* Point to struct mlx5_flow_meter_policy. */
+	struct mlx5_flow_tbl_resource *tbl_rsc;
+	/* The sub-policy table resource. */
+	uint32_t rix_hrxq[MLX5_MTR_RTE_COLORS];
+	/* Index to TIR resource. */
+	struct mlx5_flow_tbl_resource *jump_tbl[MLX5_MTR_RTE_COLORS];
+	/* Meter jump/drop table. */
+	struct mlx5_flow_dv_matcher *color_matcher[RTE_COLORS];
+	/* Matcher for Color. */
+	void *color_rule[RTE_COLORS];
+	/* Meter green/yellow/drop rule. */
+};
+
+struct mlx5_meter_policy_acts {
+	uint8_t actions_n;
+	/* Number of actions. */
+	void *dv_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS];
+	/* Action list. */
+};
+
+struct mlx5_meter_policy_action_container {
+	uint32_t rix_mark;
+	/* Index to the mark action. */
+	struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
+	/* Pointer to modify header resource in cache. */
+	uint8_t fate_action;
+	/* Fate action type. */
+	union {
+		struct rte_flow_action *rss;
+		/* Rss action configuration. */
+		uint32_t rix_port_id_action;
+		/* Index to port ID action resource. */
+		void *dr_jump_action[MLX5_MTR_DOMAIN_MAX];
+		/* Jump/drop action per color. */
+	};
+};
+
+/* Flow meter policy parameter structure. */
+struct mlx5_flow_meter_policy {
+	uint32_t is_rss:1;
+	/* Is RSS policy table. */
+	uint32_t ingress:1;
+	/* Rule applies to ingress domain. */
+	uint32_t egress:1;
+	/* Rule applies to egress domain. */
+	uint32_t transfer:1;
+	/* Rule applies to transfer domain. */
+	rte_spinlock_t sl;
+	uint32_t ref_cnt;
+	/* Use count. */
+	struct mlx5_meter_policy_action_container act_cnt[MLX5_MTR_RTE_COLORS];
+	/* Policy actions container. */
+	void *dr_drop_action[MLX5_MTR_DOMAIN_MAX];
+	/* drop action for red color. */
+	uint16_t sub_policy_num;
+	/* Count sub policy tables, 3 bits per domain. */
+	struct mlx5_flow_meter_sub_policy **sub_policys[MLX5_MTR_DOMAIN_MAX];
+	/* Sub policy table array must be the end of struct. */
+};
+
+/* The maximum sub policy is relate to struct mlx5_rss_hash_fields[]. */
+#define MLX5_MTR_RSS_MAX_SUB_POLICY 7
+#define MLX5_MTR_SUB_POLICY_NUM_SHIFT  3
+#define MLX5_MTR_SUB_POLICY_NUM_MARK  0x7
+
+/* Flow meter default policy parameter structure.
+ * Policy id 0 is reserved by default policy table.
+ */
+struct mlx5_flow_meter_def_policy {
+	struct mlx5_flow_meter_sub_policy sub_policy;
+	/* Policy rules jump to other tables. */
+	void *dr_jump_action[RTE_COLORS];
+	/* Jump action per color. */
+};
 
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
@@ -755,6 +862,29 @@ struct mlx5_aso_mtr_pools_mng {
 	struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */
 };
 
+/* Meter management structure for global flow meter resource. */
+struct mlx5_flow_mtr_mng {
+	struct mlx5_aso_mtr_pools_mng pools_mng;
+	/* Pools management structure for ASO flow meter pools. */
+	struct mlx5_flow_meter_def_policy *def_policy[MLX5_MTR_DOMAIN_MAX];
+	/* Default policy table. */
+	uint32_t def_policy_ref_cnt;
+	/** def_policy create/delete count. */
+	uint32_t def_policy_mtr_ref_cnt;
+	/** def_policy meter use count. */
+	struct mlx5_l3t_tbl *policy_idx_tbl;
+	/* Policy index lookup table. */
+	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop table. */
+	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Matcher meter in drop table. */
+	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* default matcher in drop table. */
+	void *def_rule[MLX5_MTR_DOMAIN_MAX];
+	/* default rule in drop table. */
+};
+#define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
+
 /* Table key of the hash organization. */
 union mlx5_flow_tbl_key {
 	struct {
@@ -782,8 +912,9 @@ struct mlx5_flow_tbl_resource {
 #define MLX5_FLOW_MREG_CP_TABLE_GROUP (MLX5_MAX_TABLES - 2)
 /* Tables for metering splits should be added here. */
 #define MLX5_FLOW_TABLE_LEVEL_SUFFIX (MLX5_MAX_TABLES - 3)
-#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 4)
-#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_METER
+#define MLX5_FLOW_TABLE_LEVEL_METER_DROP (MLX5_MAX_TABLES - 4)
+#define MLX5_FLOW_TABLE_LEVEL_POLICY (MLX5_MAX_TABLES - 5)
+#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_POLICY
 #define MLX5_MAX_TABLES_FDB UINT16_MAX
 #define MLX5_FLOW_TABLE_FACTOR 10
 
@@ -929,8 +1060,8 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_geneve_tlv_option_resource *geneve_tlv_option_resource;
 	/* Management structure for geneve tlv option */
 	rte_spinlock_t geneve_tlv_opt_sl; /* Lock for geneve tlv resource */
-	struct mlx5_aso_mtr_pools_mng *mtrmng;
-	/* Meter pools management structure. */
+	struct mlx5_flow_mtr_mng *mtrmng;
+	/* Meter management structure. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
 
@@ -1232,7 +1363,7 @@ int mlx5_hairpin_cap_get(struct rte_eth_dev *dev,
 bool mlx5_flex_parser_ecpri_exist(struct rte_eth_dev *dev);
 int mlx5_flex_parser_ecpri_alloc(struct rte_eth_dev *dev);
 int mlx5_flow_aso_age_mng_init(struct mlx5_dev_ctx_shared *sh);
-int mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv);
+int mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh);
 
 /* mlx5_ethdev.c */
 
@@ -1448,6 +1579,10 @@ int mlx5_flow_meter_attach(struct mlx5_priv *priv,
 			   struct rte_flow_error *error);
 void mlx5_flow_meter_detach(struct mlx5_priv *priv,
 			    struct mlx5_flow_meter_info *fm);
+struct mlx5_flow_meter_policy *mlx5_flow_meter_policy_find
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		uint32_t *policy_idx);
 
 /* mlx5_os.c */
 struct rte_pci_driver;
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 2d0daf631a..1ca4ea741c 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1044,7 +1044,7 @@ flow_rxq_tunnel_ptype_update(struct mlx5_rxq_ctrl *rxq_ctrl)
  * @param[in] dev_handle
  *   Pointer to device flow handle structure.
  */
-static void
+void
 flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
 		       struct mlx5_flow_handle *dev_handle)
 {
@@ -4490,8 +4490,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		actions_pre++;
 		jump_data = (struct rte_flow_action_jump *)actions_pre;
 		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_METER;
+				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_POLICY;
 		hw_mtr_action->conf = jump_data;
 		actions_pre = (struct rte_flow_action *)(jump_data + 1);
 	} else {
@@ -6615,6 +6615,169 @@ mlx5_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
 	return 0;
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] is_rss
+ *   Is RSS or not.
+ * @param[out] domain_bitmap
+ *   Domain bitmap.
+ * @param[out] is_def_policy
+ *   Is default policy or not.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->validate_mtr_acts(dev, actions, attr,
+			is_rss, domain_bitmap, is_def_policy, error);
+}
+
+/**
+ * Destroy the meter table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_acts(dev, mtr_policy);
+}
+
+/**
+ * Create policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_mtr_acts(dev, mtr_policy, actions, error);
+}
+
+/**
+ * Create policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_def_policy(dev);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_def_policy(dev);
+}
+
 /**
  * Create the needed meter and suffix tables.
  *
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 8e4530f32c..5d13053f21 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -691,13 +691,6 @@ struct mlx5_flow_handle {
 #define MLX5_FLOW_HANDLE_VERBS_SIZE (sizeof(struct mlx5_flow_handle))
 #endif
 
-/*
- * Max number of actions per DV flow.
- * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
- * in rdma-core file providers/mlx5/verbs.c.
- */
-#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
-
 /** Device flow structure only for DV flow creation. */
 struct mlx5_flow_dv_workspace {
 	uint32_t group; /**< The group index. */
@@ -1124,6 +1117,32 @@ typedef int (*mlx5_flow_sync_domain_t)
 			(struct rte_eth_dev *dev,
 			 uint32_t domains,
 			 uint32_t flags);
+typedef int (*mlx5_flow_validate_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+			 const struct rte_flow_action *actions[RTE_COLORS],
+			 struct rte_flow_attr *attr,
+			 bool *is_rss,
+			 uint8_t *domain_bitmap,
+			 bool *is_def_policy,
+			 struct rte_mtr_error *error);
+typedef int (*mlx5_flow_create_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+typedef void (*mlx5_flow_destroy_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef void (*mlx5_flow_destroy_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_def_policy_t)
+			(struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_destroy_def_policy_t)
+			(struct rte_eth_dev *dev);
 
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
@@ -1137,6 +1156,13 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_mtr_tbls_t destroy_mtr_tbls;
 	mlx5_flow_mtr_alloc_t create_meter;
 	mlx5_flow_mtr_free_t free_meter;
+	mlx5_flow_validate_mtr_acts_t validate_mtr_acts;
+	mlx5_flow_create_mtr_acts_t create_mtr_acts;
+	mlx5_flow_destroy_mtr_acts_t destroy_mtr_acts;
+	mlx5_flow_create_policy_rules_t create_policy_rules;
+	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
+	mlx5_flow_create_def_policy_t create_def_policy;
+	mlx5_flow_destroy_def_policy_t destroy_def_policy;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1213,12 +1239,13 @@ static inline struct mlx5_aso_mtr *
 mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)
 {
 	struct mlx5_aso_mtr_pool *pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 
 	/* Decrease to original index. */
 	idx--;
-	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < mtrmng->n);
-	pool = mtrmng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
+	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n);
+	pool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
 	return &pool->mtrs[idx % MLX5_ASO_MTRS_PER_POOL];
 }
 
@@ -1366,6 +1393,7 @@ int mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_meter_domains_infos *tbl);
 int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
 			  struct rte_mtr_error *error);
+void flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
@@ -1466,4 +1494,25 @@ int mlx5_flow_os_set_specific_workspace(struct mlx5_flow_workspace *data);
 void mlx5_flow_os_release_workspace(void);
 uint32_t mlx5_flow_mtr_alloc(struct rte_eth_dev *dev);
 void mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx);
+int mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+int mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+void mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_def_policy(struct rte_eth_dev *dev);
+void mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev);
+void flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
+		       struct mlx5_flow_handle *dev_handle);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c
index 4d13743ecc..93fe08779e 100644
--- a/drivers/net/mlx5/mlx5_flow_aso.c
+++ b/drivers/net/mlx5/mlx5_flow_aso.c
@@ -312,11 +312,11 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh,
 		mlx5_aso_age_init_sq(&sh->aso_age_mng->aso_sq);
 		break;
 	case ASO_OPC_MOD_POLICER:
-		if (mlx5_aso_sq_create(sh->ctx,&sh->mtrmng->sq, 0,
+		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->pools_mng.sq, 0,
 				  sh->tx_uar, sh->pdn, MLX5_ASO_QUEUE_LOG_DESC,
 				  sh->sq_ts_format))
 			return -1;
-		mlx5_aso_mtr_init_sq(&sh->mtrmng->sq);
+		mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq);
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -343,7 +343,7 @@ mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh,
 		sq = &sh->aso_age_mng->aso_sq;
 		break;
 	case ASO_OPC_MOD_POLICER:
-		sq = &sh->mtrmng->sq;
+		sq = &sh->mtrmng->pools_mng.sq;
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -799,7 +799,7 @@ int
 mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	do {
@@ -831,7 +831,7 @@ int
 mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) ==
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index ec6097b395..3992ad6980 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -21,6 +21,8 @@
 #include <rte_gtp.h>
 #include <rte_eal_paging.h>
 #include <rte_mpls.h>
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -184,6 +186,31 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
 	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. */
@@ -4692,10 +4719,6 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev,
 					  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,
@@ -5914,9 +5937,10 @@ static int
 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
-	void *old_pools = mtrmng->pools;
-	uint32_t resize = mtrmng->n + MLX5_MTRS_CONTAINER_RESIZE;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
+	void *old_pools = pools_mng->pools;
+	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
 
@@ -5924,16 +5948,16 @@ flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 		rte_errno = ENOMEM;
 		return -ENOMEM;
 	}
-	if (!mtrmng->n)
+	if (!pools_mng->n)
 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
 			mlx5_free(pools);
 			return -ENOMEM;
 		}
 	if (old_pools)
-		memcpy(pools, old_pools, mtrmng->n *
+		memcpy(pools, old_pools, pools_mng->n *
 				       sizeof(struct mlx5_aso_mtr_pool *));
-	mtrmng->n = resize;
-	mtrmng->pools = pools;
+	pools_mng->n = resize;
+	pools_mng->pools = pools;
 	if (old_pools)
 		mlx5_free(old_pools);
 	return 0;
@@ -5956,7 +5980,8 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 			     struct mlx5_aso_mtr **mtr_free)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool = NULL;
 	struct mlx5_devx_obj *dcs = NULL;
 	uint32_t i;
@@ -5976,17 +6001,17 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 		return NULL;
 	}
 	pool->devx_obj = dcs;
-	pool->index = mtrmng->n_valid;
-	if (pool->index == mtrmng->n && flow_dv_mtr_container_resize(dev)) {
+	pool->index = pools_mng->n_valid;
+	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
 		mlx5_free(pool);
 		claim_zero(mlx5_devx_cmd_destroy(dcs));
 		return NULL;
 	}
-	mtrmng->pools[pool->index] = pool;
-	mtrmng->n_valid++;
+	pools_mng->pools[pool->index] = pool;
+	pools_mng->n_valid++;
 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
 		pool->mtrs[i].offset = i;
-		LIST_INSERT_HEAD(&mtrmng->meters,
+		LIST_INSERT_HEAD(&pools_mng->meters,
 						&pool->mtrs[i], next);
 	}
 	pool->mtrs[0].offset = 0;
@@ -6006,14 +6031,15 @@ static void
 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
 
 	MLX5_ASSERT(aso_mtr);
-	rte_spinlock_lock(&mtrmng->mtrsl);
+	rte_spinlock_lock(&pools_mng->mtrsl);
 	aso_mtr->state = ASO_METER_FREE;
-	LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 }
 
 /**
@@ -6030,7 +6056,8 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_aso_mtr *mtr_free = NULL;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool;
 	struct rte_flow_error error;
 	uint8_t reg_id;
@@ -6042,16 +6069,16 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 	}
 	/* Allocate the flow meter memory. */
 	/* Get free meters from management. */
-	rte_spinlock_lock(&mtrmng->mtrsl);
-	mtr_free = LIST_FIRST(&mtrmng->meters);
+	rte_spinlock_lock(&pools_mng->mtrsl);
+	mtr_free = LIST_FIRST(&pools_mng->meters);
 	if (mtr_free)
 		LIST_REMOVE(mtr_free, next);
 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
 		return 0;
 	}
 	mtr_free->state = ASO_METER_WAIT;
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 	pool = container_of(mtr_free,
 			struct mlx5_aso_mtr_pool,
 			mtrs[mtr_free->offset]);
@@ -13253,6 +13280,555 @@ flow_dv_action_query(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Destroy the meter sub policy table rules.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *   Pointer to meter sub policy table.
+ */
+static void
+__flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_sub_policy *sub_policy)
+{
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (sub_policy->color_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(sub_policy->color_rule[i]));
+			sub_policy->color_rule[i] = NULL;
+		}
+		if (sub_policy->color_matcher[i]) {
+			tbl = container_of(sub_policy->color_matcher[i]->tbl,
+				typeof(*tbl), tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &sub_policy->color_matcher[i]->entry);
+			sub_policy->color_matcher[i] = NULL;
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (sub_policy->rix_hrxq[i]) {
+			mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+			sub_policy->rix_hrxq[i] = 0;
+		}
+		if (sub_policy->jump_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->jump_tbl[i]);
+			sub_policy->jump_tbl[i] = NULL;
+		}
+	}
+	if (sub_policy->tbl_rsc) {
+		flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->tbl_rsc);
+		sub_policy->tbl_rsc = NULL;
+	}
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	uint32_t i, j;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		for (j = 0; j < sub_policy_num; j++) {
+			sub_policy = mtr_policy->sub_policys[i][j];
+			if (sub_policy)
+				__flow_dv_destroy_sub_policy_rules
+						(dev, sub_policy);
+		}
+	}
+}
+
+/**
+ * Destroy policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	struct rte_flow_action *rss_action;
+	struct mlx5_flow_handle dev_handle;
+	uint32_t i, j;
+
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			flow_dv_tag_release(dev,
+				mtr_policy->act_cnt[i].rix_mark);
+			mtr_policy->act_cnt[i].rix_mark = 0;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			dev_handle.dvh.modify_hdr =
+				mtr_policy->act_cnt[i].modify_hdr;
+			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
+		}
+		switch (mtr_policy->act_cnt[i].fate_action) {
+		case MLX5_FLOW_FATE_SHARED_RSS:
+			rss_action = mtr_policy->act_cnt[i].rss;
+			mlx5_free(rss_action);
+			break;
+		case MLX5_FLOW_FATE_PORT_ID:
+			if (mtr_policy->act_cnt[i].rix_port_id_action) {
+				flow_dv_port_id_action_resource_release(dev,
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				mtr_policy->act_cnt[i].rix_port_id_action = 0;
+			}
+			break;
+		case MLX5_FLOW_FATE_DROP:
+		case MLX5_FLOW_FATE_JUMP:
+			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+				mtr_policy->act_cnt[i].dr_jump_action[j] =
+						NULL;
+			break;
+		default:
+			/*Queue action do nothing*/
+			break;
+		}
+	}
+	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+		mtr_policy->dr_drop_action[j] = NULL;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+__flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+			 enum mlx5_meter_domain domain,
+		      struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_error flow_err;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	struct mlx5_flow_handle dh;
+	struct mlx5_flow dev_flow;
+	struct mlx5_flow_dv_port_id_action_resource port_id_action;
+	int i, ret;
+	uint8_t egress, transfer;
+	struct mlx5_meter_policy_action_container *act_cnt = NULL;
+	union {
+		struct mlx5_flow_dv_modify_hdr_resource res;
+		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
+			    sizeof(struct mlx5_modification_cmd) *
+			    (MLX5_MAX_MODIFY_NUM + 1)];
+	} mhdr_dummy;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
+	memset(&port_id_action, 0,
+		sizeof(struct mlx5_flow_dv_port_id_action_resource));
+	dev_flow.handle = &dh;
+	dev_flow.dv.port_id_action = &port_id_action;
+	dev_flow.external = true;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i < MLX5_MTR_RTE_COLORS)
+			act_cnt = &mtr_policy->act_cnt[i];
+		for (act = actions[i];
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_MARK:
+			{
+				uint32_t tag_be = mlx5_flow_mark_set
+					(((const struct rte_flow_action_mark *)
+					(act->conf))->id);
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "mark action for this color");
+				dev_flow.handle->mark = 1;
+				if (flow_dv_tag_resource_register(dev, tag_be,
+						  &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot setup policy mark action");
+				MLX5_ASSERT(dev_flow.dv.tag_resource);
+				act_cnt->rix_mark =
+					dev_flow.handle->dvh.rix_tag;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+			mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+			{
+				struct mlx5_flow_dv_modify_hdr_resource
+					*mhdr_res = &mhdr_dummy.res;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "set tag action for this color");
+				memset(mhdr_res, 0, sizeof(*mhdr_res));
+				mhdr_res->ft_type = transfer ?
+					MLX5DV_FLOW_TABLE_TYPE_FDB :
+					egress ?
+					MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+					MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+				if (flow_dv_convert_action_set_tag
+				(dev, mhdr_res,
+				(const struct rte_flow_action_set_tag *)
+				act->conf,  &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot convert policy "
+					"set tag action");
+				if (!mhdr_res->actions_num)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot find policy "
+					"set tag action");
+				/* create modify action if needed. */
+				dev_flow.dv.group = 1;
+				if (flow_dv_modify_hdr_resource_register
+					(dev, mhdr_res, &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot register policy "
+					"set tag action");
+				act_cnt->modify_hdr =
+				dev_flow.handle->dvh.modify_hdr;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+				mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_DROP:
+			{
+				struct mlx5_flow_mtr_mng *mtrmng =
+						priv->sh->mtrmng;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+
+				/*
+				 * Create the drop table with
+				 * METER DROP level.
+				 */
+				if (!mtrmng->drop_tbl[domain]) {
+					mtrmng->drop_tbl[domain] =
+					flow_dv_tbl_resource_get(dev,
+					MLX5_FLOW_TABLE_LEVEL_METER_DROP,
+					egress, transfer, false, NULL, 0,
+					0, 0, &flow_err);
+					if (!mtrmng->drop_tbl[domain])
+						return -rte_mtr_error_set
+					(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Failed to create meter drop table");
+				}
+				tbl_data = container_of
+				(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				if (i < MLX5_MTR_RTE_COLORS) {
+					act_cnt->dr_jump_action[domain] =
+						tbl_data->jump.action;
+					act_cnt->fate_action =
+						MLX5_FLOW_FATE_DROP;
+				}
+				if (i == RTE_COLOR_RED)
+					mtr_policy->dr_drop_action[domain] =
+						tbl_data->jump.action;
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+			{
+				struct mlx5_hrxq *hrxq;
+				uint32_t hrxq_idx;
+				struct mlx5_flow_rss_desc rss_desc;
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"fate queue for this color");
+				memset(&rss_desc, 0,
+					sizeof(struct mlx5_flow_rss_desc));
+				rss_desc.queue_num = 1;
+				rss_desc.const_q = act->conf;
+				hrxq = flow_dv_hrxq_prepare(dev, &dev_flow,
+						    &rss_desc, &hrxq_idx);
+				if (!hrxq)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot create policy fate queue");
+				sub_policy->rix_hrxq[i] = hrxq_idx;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				dev_flow.handle->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				if (action_flags & MLX5_FLOW_ACTION_MARK ||
+				    action_flags & MLX5_FLOW_ACTION_SET_TAG) {
+					dev_flow.handle->rix_hrxq = hrxq_idx;
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_RSS:
+			{
+				int rss_size;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "rss action for this color");
+				/*
+				 * Save RSS conf into policy struct
+				 * for translate stage.
+				 */
+				rss_size = rte_flow_conv
+						(RTE_FLOW_CONV_OP_ACTION,
+						NULL, 0, act, &flow_err);
+				if (rss_size <= 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Get the wrong "
+					  "rss action struct size");
+				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
+						rss_size, 0, SOCKET_ID_ANY);
+				if (!act_cnt->rss)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "Fail to malloc rss action memory");
+				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
+					act_cnt->rss, rss_size,
+					act, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Fail to save "
+					  "rss action into policy struct");
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_SHARED_RSS;
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+			{
+				struct mlx5_flow_dv_port_id_action_resource
+					port_id_resource;
+				uint32_t port_id = 0;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"port action for this color");
+				memset(&port_id_resource, 0,
+					sizeof(port_id_resource));
+				if (flow_dv_translate_action_port_id(dev, act,
+						&port_id, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot translate "
+					"policy port action");
+				port_id_resource.port_id = port_id;
+				if (flow_dv_port_id_action_resource_register
+					(dev, &port_id_resource,
+					&dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy port action");
+				act_cnt->rix_port_id_action =
+					dev_flow.handle->rix_port_id_action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_PORT_ID;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+			{
+				uint32_t jump_group = 0;
+				uint32_t table;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+				struct flow_grp_info grp_info = {
+					.external = !!dev_flow.external,
+					.transfer = !!transfer,
+					.fdb_def_rule = !!priv->fdb_def_rule,
+					.std_tbl_fix = 0,
+					.skip_scale = dev_flow.skip_scale &
+					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
+				};
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "jump action for this color");
+				jump_group =
+				((const struct rte_flow_action_jump *)
+							act->conf)->group;
+				if (mlx5_flow_group_to_table(dev, NULL,
+						       jump_group,
+						       &table,
+						       &grp_info, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy jump action");
+				sub_policy->jump_tbl[i] =
+				flow_dv_tbl_resource_get(dev,
+					table, egress,
+					transfer,
+					!!dev_flow.external,
+					NULL, jump_group, 0,
+					0, &flow_err);
+				if
+				(!sub_policy->jump_tbl[i])
+					return  -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create jump action.");
+				tbl_data = container_of
+				(sub_policy->jump_tbl[i],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				act_cnt->dr_jump_action[domain] =
+					tbl_data->jump.action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_JUMP;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			}
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "action type not supported");
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	int ret, i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		if (sub_policy_num) {
+			ret = __flow_dv_create_domain_policy_acts(dev,
+				mtr_policy, actions, i, error);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
 /**
  * Query a dv flow  rule for its statistics via devx.
  *
@@ -13433,9 +14009,472 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
 	return 0;
 }
 
+void
+flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (mtrmng->def_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+					(mtrmng->def_rule[i]));
+			mtrmng->def_rule[i] = NULL;
+		}
+		if (mtrmng->def_matcher[i]) {
+			tbl = container_of(mtrmng->def_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->def_matcher[i]->entry);
+			mtrmng->def_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_matcher[i]) {
+			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->drop_matcher[i]->entry);
+			mtrmng->drop_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+				mtrmng->drop_tbl[i]);
+			mtrmng->drop_tbl[i] = NULL;
+		}
+	}
+}
+
 /* Number of meter flow actions, count and jump or count and drop. */
 #define METER_ACTIONS 2
 
+static void
+__flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
+			      enum mlx5_meter_domain domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_def_policy *def_policy =
+			priv->sh->mtrmng->def_policy[domain];
+
+	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
+	mlx5_free(def_policy);
+	priv->sh->mtrmng->def_policy[domain] = NULL;
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+static void
+flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
+		if (priv->sh->mtrmng->def_policy[i])
+			__flow_dv_destroy_domain_def_policy(dev, i);
+}
+
+static int
+__flow_dv_create_policy_flow(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			enum rte_color color, void *matcher_object,
+			int actions_n, void *actions,
+			bool is_defult_policy, void **rule,
+			const struct rte_flow_attr *attr)
+{
+	int ret;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!is_defult_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to create meter policy flow with port.");
+			return -1;
+		}
+	}
+	flow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c_idx,
+				       rte_col_2_mlx5_col(color),
+				       UINT32_MAX);
+	ret = mlx5_flow_os_create_flow(matcher_object,
+			(void *)&value, actions_n, actions, rule);
+	if (ret) {
+		DRV_LOG(ERR, "Failed to create meter policy flow.");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			uint16_t priority,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			const struct rte_flow_attr *attr,
+			bool is_defult_policy,
+			struct rte_flow_error *error)
+{
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+				MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+		.tbl = tbl_rsc,
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = error,
+		.data = &matcher,
+	};
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!is_defult_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to register meter drop matcher with port.");
+			return -1;
+		}
+	}
+	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
+	if (priority < RTE_COLOR_RED)
+		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+					color_reg_c_idx, 0,
+					LS32_MASK(MLX5_MTR_COLOR_BITS));
+	matcher.priority = priority;
+	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
+					matcher.mask.size);
+	entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+	if (!entry) {
+		DRV_LOG(ERR, "Failed to register meter drop matcher.");
+		return -1;
+	}
+	sub_policy->color_matcher[priority] =
+		container_of(entry, struct mlx5_flow_dv_matcher, entry);
+	return 0;
+}
+
+/**
+ * Create the policy rules per domain.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *    Pointer to sub policy table..
+ * @param[in] egress
+ *   Direction of the table.
+ * @param[in] transfer
+ *   E-Switch or NIC flow.
+ * @param[in] acts
+ *   Pointer to policy action list per color.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+__flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_sub_policy *sub_policy,
+		uint8_t egress, uint8_t transfer, bool is_defult_policy,
+		struct mlx5_meter_policy_acts acts[RTE_COLORS])
+{
+	struct rte_flow_error flow_err;
+	uint32_t color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,
+						    0, &flow_err);
+	struct rte_flow_attr attr = {
+		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
+		.priority = 0,
+		.ingress = 0,
+		.egress = !!egress,
+		.transfer = !!transfer,
+		.reserved = 0,
+	};
+	int i;
+
+	/* Create policy table with POLICY level. */
+	if (!sub_policy->tbl_rsc)
+		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_POLICY,
+				egress, transfer, false, NULL, 0, 0,
+				sub_policy->idx, &flow_err);
+	if (!sub_policy->tbl_rsc) {
+		DRV_LOG(ERR,
+			"Failed to create meter sub policy table.");
+		return -1;
+	}
+	/* Prepare matchers. */
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i == RTE_COLOR_YELLOW || !acts[i].actions_n)
+			continue;
+		attr.priority = i;
+		if (!sub_policy->color_matcher[i]) {
+			/* Create matchers for Color. */
+			if (__flow_dv_create_policy_matcher(dev,
+				color_reg_c_idx, i, sub_policy,
+				&attr, is_defult_policy, &flow_err))
+				return -1;
+		}
+		/* Create flow, matching color. */
+		if (acts[i].actions_n)
+			if (__flow_dv_create_policy_flow(dev,
+				color_reg_c_idx, i,
+				sub_policy->color_matcher[i]->matcher_object,
+				acts[i].actions_n,
+				acts[i].dv_actions,
+				is_defult_policy,
+				&sub_policy->color_rule[i],
+				&attr))
+				return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	struct mlx5_flow_dv_tag_resource *tag;
+	struct mlx5_flow_dv_port_id_action_resource *port_action;
+	struct mlx5_hrxq *hrxq;
+	uint8_t egress, transfer;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		acts[i].actions_n = 0;
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (i == RTE_COLOR_RED) {
+			/* Only support drop on red. */
+			acts[i].dv_actions[0] =
+			mtr_policy->dr_drop_action[domain];
+			acts[i].actions_n = 1;
+			continue;
+		}
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
+					mtr_policy->act_cnt[i].rix_mark);
+			if (!tag) {
+				DRV_LOG(ERR, "Failed to find "
+				"mark action for policy.");
+				return -1;
+			}
+			acts[i].dv_actions[acts[i].actions_n] =
+						tag->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			acts[i].dv_actions[acts[i].actions_n] =
+			mtr_policy->act_cnt[i].modify_hdr->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].fate_action) {
+			switch (mtr_policy->act_cnt[i].fate_action) {
+			case MLX5_FLOW_FATE_PORT_ID:
+				port_action = mlx5_ipool_get
+					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				if (!port_action) {
+					DRV_LOG(ERR, "Failed to find "
+						"port action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				port_action->action;
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_DROP:
+			case MLX5_FLOW_FATE_JUMP:
+				acts[i].dv_actions[acts[i].actions_n] =
+				mtr_policy->act_cnt[i].dr_jump_action[domain];
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_SHARED_RSS:
+			case MLX5_FLOW_FATE_QUEUE:
+				hrxq = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+				sub_policy->rix_hrxq[i]);
+				acts[i].dv_actions[acts[i].actions_n] =
+				hrxq->action;
+				acts[i].actions_n++;
+				break;
+			default:
+				/*Queue action do nothing*/
+				break;
+			}
+		}
+	}
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
+				egress, transfer, false, acts)) {
+		DRV_LOG(ERR,
+		"Failed to create policy rules per domain.");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Create the policy rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in,out] mtr_policy
+ *   Pointer to meter policy table.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	int i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		if (!sub_policy_num)
+			continue;
+		/* Prepare actions list and create policy rules*/
+		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+			mtr_policy->sub_policys[i][0], i)) {
+			DRV_LOG(ERR,
+			"Failed to create policy action list per domain.");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_meter_def_policy *def_policy;
+	struct mlx5_flow_tbl_resource *jump_tbl;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	struct rte_flow_error error;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	int ret;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	def_policy = mtrmng->def_policy[domain];
+	if (!def_policy) {
+		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(struct mlx5_flow_meter_def_policy),
+			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+		if (!def_policy) {
+			DRV_LOG(ERR, "Failed to alloc "
+					"default policy table.");
+			goto def_policy_error;
+		}
+		mtrmng->def_policy[domain] = def_policy;
+		/* Create the meter suffix table with SUFFIX level. */
+		jump_tbl = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_SUFFIX,
+				egress, transfer, false, NULL, 0,
+				0, 0, &error);
+		if (!jump_tbl) {
+			DRV_LOG(ERR,
+				"Failed to create meter suffix table.");
+			goto def_policy_error;
+		}
+		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
+		tbl_data = container_of(jump_tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].dv_actions[0] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].actions_n = 1;
+		/* Create jump action to the drop table. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
+				(dev, MLX5_FLOW_TABLE_LEVEL_METER_DROP,
+				egress, transfer, false, NULL, 0,
+				0, 0, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create "
+				"meter drop table for default policy.");
+				goto def_policy_error;
+			}
+		}
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_RED] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
+		acts[RTE_COLOR_RED].actions_n = 1;
+		/* Create default policy rules. */
+		ret = __flow_dv_create_domain_policy_rules(dev,
+					&def_policy->sub_policy,
+					egress, transfer, true, acts);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create "
+				"default policy rules.");
+				goto def_policy_error;
+		}
+	}
+	return 0;
+def_policy_error:
+	__flow_dv_destroy_domain_def_policy(dev, domain);
+	return -1;
+}
+
+/**
+ * Create the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	/* Non-termination policy table*/
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
+			continue;
+		if (__flow_dv_create_domain_def_policy(dev, i)) {
+			DRV_LOG(ERR,
+			"Failed to create default policy");
+			return -1;
+		}
+	}
+	return 0;
+}
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -13465,14 +14504,6 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
 		dtb = &mtb->egress;
 	else
 		dtb = &mtb->ingress;
-	/* Create the meter table with METER level. */
-	dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
-	if (!dtb->tbl) {
-		DRV_LOG(ERR, "Failed to create meter policer table.");
-		return -1;
-	}
 	/* Create the meter suffix table with SUFFIX level. */
 	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
 					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
@@ -13795,6 +14826,274 @@ flow_dv_action_validate(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_dev_config *dev_conf = &priv->config;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	int actions_n;
+	int i, ret;
+	struct rte_flow_error flow_err;
+	uint8_t domain_color[RTE_COLORS] = {0};
+	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
+
+	if (!priv->config.dv_esw_en)
+		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	*domain_bitmap = def_domain;
+	/*
+	 * Check default policy actions:
+	 * Green/Yellow: no action, Red: drop action
+	 */
+	if ((!actions[RTE_COLOR_GREEN] ||
+		actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END) &&
+	    (!actions[RTE_COLOR_YELLOW] ||
+		actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END) &&
+	    (actions[RTE_COLOR_RED] &&
+	     actions[RTE_COLOR_RED]->type == RTE_FLOW_ACTION_TYPE_DROP)) {
+		*is_def_policy = true;
+		return 0;
+	}
+	for (i = 0; i < RTE_COLORS; i++) {
+		act = actions[i];
+		if (i == RTE_COLOR_RED &&
+			(!act || act->type != RTE_FLOW_ACTION_TYPE_DROP))
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Red color only supports drop action.");
+		for (action_flags = 0, actions_n = 0;
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			if (i == RTE_COLOR_YELLOW)
+				return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"Yellow color does not support any action.");
+			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "too many actions");
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+				if (!priv->config.dv_esw_en)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "PORT action validate check"
+					" fail for ESW disable");
+				ret = flow_dv_validate_action_port_id(dev,
+						action_flags,
+						act, attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message);
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			case RTE_FLOW_ACTION_TYPE_MARK:
+				ret = flow_dv_validate_action_mark(dev, act,
+							   action_flags,
+							   attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message);
+				if (dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "Extend MARK action is "
+					"not supported. Please try use "
+					"policy id 0 for meter.");
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+				ret = flow_dv_validate_action_set_tag(dev,
+							act, action_flags,
+							attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message);
+				/* Count all modify-header actions
+				 * as one action.
+				 */
+				if (!(action_flags &
+					MLX5_FLOW_MODIFY_HDR_ACTIONS))
+					++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			case RTE_FLOW_ACTION_TYPE_DROP:
+				ret = mlx5_flow_validate_action_drop
+					(action_flags,
+					attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message);
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+				/* Check whether extensive
+				 * metadata feature is engaged.
+				 */
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Queue action with meta "
+					  "is not supported. Please try use "
+					  "policy id 0 for meter.");
+				ret = mlx5_flow_validate_action_queue(act,
+							action_flags, dev,
+							attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message);
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_RSS:
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "RSS action with meta "
+					  "is not supported. Please try use "
+					  "policy id 0 for meter.");
+				ret = mlx5_validate_action_rss(dev, act,
+						&flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message);
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				++actions_n;
+				*is_rss = true;
+				break;
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+				ret = flow_dv_validate_action_jump(dev,
+					NULL, act, action_flags,
+					attr, true, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message);
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Doesn't support optional action");
+			}
+		}
+		/* Yellow is not supported, just skip. */
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
+		else if ((action_flags &
+			(MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
+			(action_flags & MLX5_FLOW_ACTION_MARK))
+			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
+		else
+			domain_color[i] = def_domain;
+		/*
+		 * Validate the drop action mutual exclusion
+		 * with other actions. Drop action is mutually-exclusive
+		 * with any other action, except for Count action.
+		 */
+		if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
+			(action_flags & ~MLX5_FLOW_ACTION_DROP)) {
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Drop action is mutually-exclusive "
+				"with any other action");
+		}
+		/* Eswitch has few restrictions on using items and actions */
+		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
+			if (!mlx5_flow_ext_mreg_supported(dev) &&
+				action_flags & MLX5_FLOW_ACTION_MARK)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action MARK");
+			if (action_flags & MLX5_FLOW_ACTION_QUEUE)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action QUEUE");
+			if (action_flags & MLX5_FLOW_ACTION_RSS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action RSS");
+			if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+		} else {
+			if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) &&
+				(domain_color[i] &
+				MLX5_MTR_DOMAIN_INGRESS_BIT)) {
+				if ((domain_color[i] &
+					MLX5_MTR_DOMAIN_EGRESS_BIT))
+					domain_color[i] =
+					MLX5_MTR_DOMAIN_EGRESS_BIT;
+				else
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+			}
+		}
+		if (domain_color[i] != def_domain)
+			*domain_bitmap = domain_color[i];
+	}
+	return 0;
+}
+
 static int
 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
 {
@@ -13832,6 +15131,13 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
+	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
+	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
+	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
+	.create_policy_rules = flow_dv_create_policy_rules,
+	.destroy_policy_rules = flow_dv_destroy_policy_rules,
+	.create_def_policy = flow_dv_create_def_policy,
+	.destroy_def_policy = flow_dv_destroy_def_policy,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index af0a1c18cb..25c78cfd3c 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -38,6 +38,12 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
 	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
 	uint32_t val;
+	enum mlx5_meter_domain domain =
+		fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+			fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
+				MLX5_MTR_DOMAIN_INGRESS;
+	struct mlx5_flow_meter_def_policy *def_policy =
+		priv->sh->mtrmng->def_policy[domain];
 
 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
@@ -57,10 +63,7 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
-	mtr_init.next_table =
-		fm->transfer ? fm->mfts->transfer.tbl->obj :
-			fm->egress ? fm->mfts->egress.tbl->obj :
-				fm->mfts->ingress.tbl->obj;
+	mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
 	mtr_init.flow_meter_parameter = fmp;
 	mtr_init.flow_meter_parameter_sz =
@@ -317,7 +320,7 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
 					  "Meter is not supported");
 	memset(cap, 0, sizeof(*cap));
 	if (priv->sh->meter_aso_en)
-	    /* 2 meters per one ASO cache line. */
+		/* 2 meters per one ASO cache line. */
 		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
 	else
 		cap->n_max = 1 << qattr->log_max_flow_meter;
@@ -435,6 +438,356 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * Find policy by id.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param policy_id
+ *   Policy id.
+ *
+ * @return
+ *   Pointer to the policy found on success, NULL otherwise.
+ */
+struct mlx5_flow_meter_policy *
+mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
+			    uint32_t policy_id,
+			    uint32_t *policy_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	union mlx5_l3t_data data;
+
+	if (!policy_id || policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM ||
+		!priv->sh->mtrmng->policy_idx_tbl)
+		return NULL;
+	if (mlx5_l3t_get_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data) ||
+				!data.dword) {
+		return NULL;
+	}
+	if (policy_idx)
+		*policy_idx = data.dword;
+	sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				data.dword);
+	/* Remove reference taken by the mlx5_l3t_get_entry. */
+	mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl, policy_id);
+	if (sub_policy) {
+		if (sub_policy->main_policy_id)
+			return sub_policy->main_policy;
+	}
+	return NULL;
+}
+
+/**
+ * Callback to check MTR policy action validate
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_validate(struct rte_eth_dev *dev,
+	const struct rte_flow_action *actions[RTE_COLORS],
+	struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint8_t domain_bitmap;
+	int ret;
+
+	if (!priv->mtr_en || !priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "meter policy unsupported.");
+	ret = mlx5_flow_validate_mtr_acts(dev, actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+/**
+ * Callback to add MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] policy_id
+ *   Pointer to policy id
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_create(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	uint32_t sub_policy_idx = 0;
+	uint32_t policy_idx = 0;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint32_t i;
+	int ret;
+	uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
+	uint16_t sub_policy_num;
+	uint8_t domain_bitmap;
+	union mlx5_l3t_data data;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "meter policy unsupported.");
+	if (!priv->sh->meter_aso_en &&
+		policy_id != RTE_MTR_DEFAULT_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "please use default policy id.");
+	ret = mlx5_flow_validate_mtr_acts(dev, actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	if (is_def_policy) {
+		if (policy_id != RTE_MTR_DEFAULT_POLICY_ID)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "please use default policy id.");
+		if (mlx5_flow_create_def_policy(dev))
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "fail to create default policy.");
+		__atomic_add_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
+				1, __ATOMIC_RELAXED);
+		return 0;
+	}
+	if (policy_id == RTE_MTR_DEFAULT_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+			NULL, "invalid actions for default policy.");
+	if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy id is invalid. ");
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id,
+				&policy_idx);
+	if (mtr_policy)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy object already exists. ");
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		if (is_rss) {
+			policy_size +=
+			sizeof(struct mlx5_flow_meter_sub_policy  *) *
+			MLX5_MTR_RSS_MAX_SUB_POLICY;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
+	}
+	mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
+			 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+				"Memory alloc failed for meter policy.");
+	policy_size = sizeof(struct mlx5_flow_meter_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
+		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy)
+			goto policy_add_err;
+		if (sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto policy_add_err;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+		if (policy_idx) {
+			policy_idx = sub_policy_idx;
+			sub_policy->main_policy_id = 1;
+		}
+		mtr_policy->sub_policys[i] =
+		(struct mlx5_flow_meter_sub_policy **)
+			((uint8_t *)mtr_policy + policy_size);
+		mtr_policy->sub_policys[i][0] = sub_policy;
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		sub_policy_num++;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MARK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
+		mtr_policy->sub_policy_num |=
+			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MARK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
+		if (is_rss) {
+			mtr_policy->is_rss = 1;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
+	}
+	ret = mlx5_flow_create_mtr_acts(dev, mtr_policy, actions, error);
+	if (ret)
+		goto policy_add_err;
+	if (!is_rss) {
+		/* Create policy rules in HW. */
+		ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
+		if (ret)
+			goto policy_add_err;
+	}
+	if (!priv->sh->mtrmng->policy_idx_tbl)
+		priv->sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+	if (!priv->sh->mtrmng->policy_idx_tbl)
+		goto policy_add_err;
+	data.dword = policy_idx;
+	if (mlx5_l3t_set_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data))
+		goto policy_add_err;
+	rte_spinlock_init(&mtr_policy->sl);
+	return 0;
+policy_add_err:
+	if (mtr_policy) {
+		mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
+		if (!is_rss)
+			mlx5_flow_destroy_policy_rules(dev, mtr_policy);
+		for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+			sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+			if (sub_policy_num) {
+				sub_policy = mtr_policy->sub_policys[i][0];
+				if (sub_policy)
+					mlx5_ipool_free
+					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+			}
+		}
+		mlx5_free(mtr_policy);
+	}
+	return -rte_mtr_error_set(error, ENOTSUP,
+				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+				  NULL, "Failed to create devx policy.");
+}
+
+static int
+__mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint32_t i, j;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	if (mtr_policy->ref_cnt) {
+		rte_spinlock_unlock(&mtr_policy->sl);
+		return -rte_mtr_error_set(error, EBUSY,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				 NULL,
+				"Meter policy object is being used.");
+	}
+	mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
+	mlx5_flow_destroy_policy_rules(dev, mtr_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		if (sub_policy_num) {
+			for (j = 0; j < sub_policy_num; j++) {
+				sub_policy = mtr_policy->sub_policys[i][j];
+				if (sub_policy)
+					mlx5_ipool_free
+					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+			}
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl && policy_id)
+		if (mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+					policy_id)) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Fail to delete policy in index table.");
+		}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return 0;
+}
+
+/**
+ * Callback to delete MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Meter policy 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_policy_delete(struct rte_eth_dev *dev,
+			  uint32_t policy_id,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	int ret;
+
+	if (policy_id == RTE_MTR_DEFAULT_POLICY_ID) {
+		if (!priv->sh->mtrmng->def_policy_ref_cnt)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy id is invalid.");
+		if (priv->sh->mtrmng->def_policy_mtr_ref_cnt > 0)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter object is being used.");
+		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
+					1, __ATOMIC_RELAXED);
+		return 0;
+	}
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy id is invalid. ");
+	ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
+						error);
+	if (ret)
+		return ret;
+	mlx5_free(mtr_policy);
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -942,6 +1295,9 @@ 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,
+	.meter_policy_validate = mlx5_flow_meter_policy_validate,
+	.meter_policy_create = mlx5_flow_meter_policy_create,
+	.meter_policy_delete = mlx5_flow_meter_policy_delete,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -989,22 +1345,32 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_aso_mtr *aso_mtr;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	union mlx5_l3t_data data;
 
 	if (priv->sh->meter_aso_en) {
-		rte_spinlock_lock(&mtrmng->mtrsl);
-		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
-			!data.dword) {
-			rte_spinlock_unlock(&mtrmng->mtrsl);
-			return NULL;
+		rte_spinlock_lock(&pools_mng->mtrsl);
+		if (priv->mtr_idx_tbl) {
+			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
+				meter_id, &data) ||
+				!data.dword) {
+				rte_spinlock_unlock(&pools_mng->mtrsl);
+				return NULL;
+			}
+			if (mtr_idx)
+				*mtr_idx = data.dword;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+			/* Remove reference taken by the mlx5_l3t_get_entry. */
+			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
+		} else {
+			if (mtr_idx)
+				*mtr_idx = meter_id;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
 		}
-		if (mtr_idx)
-			*mtr_idx = data.dword;
-		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-		/* Remove reference taken by the mlx5_l3t_get_entry. */
-		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
+		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
+			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
@@ -1169,39 +1535,61 @@ 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_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
 	struct mlx5_aso_mtr_pool *mtr_pool;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
 	void *tmp;
-	uint32_t i, offset, mtr_idx;
+	uint32_t i, offset, mtr_idx, policy_idx;
+	void *entry;
 
 	if (priv->sh->meter_aso_en) {
-		i = mtrmng->n_valid;
+		i = pools_mng->n_valid;
 		while (i--) {
-			mtr_pool = mtrmng->pools[i];
+			mtr_pool = pools_mng->pools[i];
 			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
 				offset++) {
 				fm = &mtr_pool->mtrs[offset].fm;
 				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				if (mlx5_flow_meter_params_flush(dev,
-						fm, mtr_idx))
-					return -rte_mtr_error_set
-					(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				(void)mlx5_flow_meter_params_flush(dev,
+						fm, mtr_idx);
 			}
 		}
+		if (priv->sh->mtrmng->policy_idx_tbl) {
+			MLX5_L3T_FOREACH(priv->sh->mtrmng->policy_idx_tbl,
+					i, entry) {
+				policy_idx = *(uint32_t *)entry;
+				if (policy_idx) {
+					sub_policy =
+					mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					policy_idx);
+					if (__mlx5_flow_meter_policy_delete
+						(dev, 0,
+						sub_policy->main_policy,
+						error))
+						return -rte_mtr_error_set
+						(error, EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+				}
+			}
+			mlx5_l3t_destroy(priv->sh->mtrmng->policy_idx_tbl);
+			priv->sh->mtrmng->policy_idx_tbl = NULL;
+		}
 	} else {
 		TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
 			fm = &legacy_fm->fm;
 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
 				return -rte_mtr_error_set(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+				NULL, "MTR object meter profile invalid.");
 		}
 	}
 	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
@@ -1211,5 +1599,8 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
 		mlx5_free(fmp);
 	}
+	/* Delete default policy table. */
+	mlx5_flow_destroy_def_policy(dev);
+	flow_dv_destroy_mtr_drop_tbls(dev);
 	return 0;
 }
-- 
2.27.0


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

* [dpdk-dev] [PATCH 2/4] net/mlx5: support meter creation with policy
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 1/4] " Li Zhang
@ 2021-04-01  8:16 ` Li Zhang
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-01  8:16 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

Make meter creation with policy to
support actions per color.

The following cases to be considered:
1.Add entry match with meter_id in global drop table.
2.For non-termination policy (policy id 0),
  add jump rule to suffix table for green and
  jump rule to drop table for red.
3.Allocate counter per meter for drop table.
4.Allocate meter resource per domain per color.
5.It can work with ASO meter and legacy meter both.

Signed-off-by: Li Zhang <lizh@nvidia.com>
---
 doc/guides/nics/mlx5.rst           |  12 +
 drivers/net/mlx5/linux/mlx5_os.c   |  13 +-
 drivers/net/mlx5/mlx5.h            |  60 ++---
 drivers/net/mlx5/mlx5_flow.c       |  26 +-
 drivers/net/mlx5/mlx5_flow.h       |  32 +--
 drivers/net/mlx5/mlx5_flow_dv.c    | 368 ++++++++++++++++++++---------
 drivers/net/mlx5/mlx5_flow_meter.c | 345 +++++++++++++++++++++++----
 7 files changed, 626 insertions(+), 230 deletions(-)

diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index fa63e62a5d..6e9a68baf5 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -106,6 +106,7 @@ Features
 - E-Switch mirroring and modify.
 - 21844 flow priorities for ingress or egress flow groups greater than 0 and for any transfer
   flow group.
+- Flow metering, including meter policy API.
 
 Limitations
 -----------
@@ -403,6 +404,17 @@ Limitations
   - Green color is not supported with drop action.
   - Yellow detection is not supported.
   - Red color must be with drop action.
+  - Meter statistics are supported only for drop case.
+  - Meter yellow color detection is not supported.
+  - A meter action created with pre-defined policy must be the last action in the
+    flow except single case where the policy actions are
+    green: NULL or END,
+    yellow: NULL or END,
+    RED: DROP / END.
+  - The only supported meter policy actions:
+    green: QUEUE, RSS, PORT_ID, JUMP, MARK and SET_TAG.
+    yellow: must be empty.
+    red: must be DROP.
 
 Statistics
 ----------
diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 859b9098dc..9ef3e31bb3 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1244,13 +1244,14 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			if (log_obj_size >=
 			config->hca_attr.qos.log_meter_aso_granularity &&
 			log_obj_size <=
-			config->hca_attr.qos.log_meter_aso_max_alloc) {
+			config->hca_attr.qos.log_meter_aso_max_alloc)
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
-				if (err) {
-					err = -err;
-					goto error;
-				}
+		}
+		if (priv->mtr_en) {
+			err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
+			if (err) {
+				err = -err;
+				goto error;
 			}
 		}
 #endif
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index a2d47cff16..a35f9af896 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -700,44 +700,12 @@ struct mlx5_flow_meter_def_policy {
 	/* Jump action per color. */
 };
 
-/* Meter table structure. */
-struct mlx5_meter_domain_info {
-	struct mlx5_flow_tbl_resource *tbl;
-	/**< Meter table. */
-	struct mlx5_flow_tbl_resource *sfx_tbl;
-	/**< Meter suffix table. */
-	struct mlx5_flow_dv_matcher *drop_matcher;
-	/**< Matcher for Drop. */
-	struct mlx5_flow_dv_matcher *color_matcher;
-	/**< Matcher for Color. */
-	void *jump_actn;
-	/**< Meter match action. */
-	void *green_rule;
-	/**< Meter green rule. */
-	void *drop_rule;
-	/**< Meter drop rule. */
-};
-
-/* 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. */
-	void *green_count;
-	/**< Counters for green rule. */
-	void *drop_count;
-	/**< Counters for green rule. */
-};
-
 /* Meter parameter structure. */
 struct mlx5_flow_meter_info {
+	uint32_t meter_id;
+	/**< Meter id. */
+	uint32_t policy_id;
+	/* Policy id, the first sub_policy idx. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
 	rte_spinlock_t sl; /**< Meter action spinlock. */
@@ -776,8 +744,8 @@ struct mlx5_flow_meter_info {
 	 * received by the application.
 	 */
 	uint32_t transfer:1;
-	struct mlx5_meter_domains_infos *mfts;
-	/**< Flow table created for this meter. */
+	void *drop_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop rule in drop table. */
 	uint32_t drop_cnt;
 	/**< Color counter for drop. */
 	uint32_t ref_cnt;
@@ -788,6 +756,11 @@ struct mlx5_flow_meter_info {
 	/**< Flow meter action. */
 };
 
+/* PPS(packets per second) map to BPS(Bytes per second).
+ * HW treat packet as 128bytes in PPS mode
+ */
+#define MLX5_MTRS_PPS_MAP_BPS_SHIFT 7
+
 /* RFC2697 parameter structure. */
 struct mlx5_flow_meter_srtcm_rfc2697_prm {
 	rte_be32_t cbs_cir;
@@ -876,12 +849,17 @@ struct mlx5_flow_mtr_mng {
 	/* Policy index lookup table. */
 	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
 	/* Meter drop table. */
-	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	struct mlx5_flow_dv_matcher *
+			drop_matcher[MLX5_MTR_DOMAIN_MAX][MLX5_REG_BITS];
 	/* Matcher meter in drop table. */
 	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
 	/* default matcher in drop table. */
 	void *def_rule[MLX5_MTR_DOMAIN_MAX];
 	/* default rule in drop table. */
+	uint8_t max_mtr_bits;
+	/* Indicate how many bits are used by meter id at the most. */
+	uint8_t max_mtr_flow_bits;
+	/* Indicate how many bits are used by meter flow id at the most. */
 };
 #define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
 
@@ -1309,10 +1287,6 @@ struct mlx5_priv {
 	uint32_t rss_shared_actions; /* RSS shared actions. */
 	struct mlx5_devx_obj *q_counters; /* DevX queue counter object. */
 	uint32_t counter_set_id; /* Queue counter ID to set in DevX objects. */
-	uint8_t max_mtr_bits;
-	/* Indicate how many bits are used by meter id at the most. */
-	uint8_t max_mtr_flow_bits;
-	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 #define PORT_ID(priv) ((priv)->dev_data->port_id)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 1ca4ea741c..e76db6ffb7 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4506,14 +4506,14 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 				"Failed to allocate meter flow id.");
 	flow_id_bits = MLX5_REG_BITS - __builtin_clz(tag_id - 1);
 	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->max_mtr_bits) > mtr_reg_bits) {
+	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
 		mlx5_ipool_free(fm->flow_ipool, tag_id);
 		return rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				"Meter flow id exceeds max limit.");
 	}
-	if (flow_id_bits > priv->max_mtr_flow_bits)
-		priv->max_mtr_flow_bits = flow_id_bits;
+	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -6785,15 +6785,18 @@ mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  *
  * @return
- *   Pointer to table set on success, NULL otherwise.
+ *   0 on success, -1 otherwise.
  */
-struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+int
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
 	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, mtr_idx, domain_bitmap);
 }
 
 /**
@@ -6803,18 +6806,15 @@ mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  * @param[in] tbl
  *   Pointer to the meter table set.
- *
- * @return
- *   0 on success.
  */
-int
+void
 mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *tbls)
+			   struct mlx5_flow_meter_info *fm)
 {
 	const struct mlx5_flow_driver_ops *fops;
 
 	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->destroy_mtr_tbls(dev, tbls);
+	fops->destroy_mtr_tbls(dev, fm);
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 5d13053f21..b630cfd661 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -222,16 +222,17 @@ enum mlx5_feature_name {
 #define MLX5_FLOW_ACTION_TUNNEL_SET (1ull << 37)
 #define MLX5_FLOW_ACTION_TUNNEL_MATCH (1ull << 38)
 #define MLX5_FLOW_ACTION_MODIFY_FIELD (1ull << 39)
+#define MLX5_FLOW_ACTION_METER_WITE_TERMINATED_POLICY (1ull << 40)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \
 	 MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_JUMP | \
-	 MLX5_FLOW_ACTION_DEFAULT_MISS)
+	 MLX5_FLOW_ACTION_DEFAULT_MISS | \
+	 MLX5_FLOW_ACTION_METER_WITE_TERMINATED_POLICY)
 
 #define MLX5_FLOW_FATE_ESWITCH_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \
-	 MLX5_FLOW_ACTION_JUMP)
-
+	 MLX5_FLOW_ACTION_JUMP | MLX5_FLOW_ACTION_METER_WITE_TERMINATED_POLICY)
 
 #define MLX5_FLOW_MODIFY_HDR_ACTIONS (MLX5_FLOW_ACTION_SET_IPV4_SRC | \
 				      MLX5_FLOW_ACTION_SET_IPV4_DST | \
@@ -831,9 +832,8 @@ struct mlx5_legacy_flow_meter {
 	/* Must be the first in struct. */
 	TAILQ_ENTRY(mlx5_legacy_flow_meter) next;
 	/**< Pointer to the next flow meter structure. */
-	uint32_t meter_id;
-	/**< Meter id. */
-	uint32_t idx; /* Index to meter object. */
+	uint32_t idx;
+	/* Index to meter object. */
 };
 
 #define MLX5_MAX_TUNNELS 256
@@ -1068,10 +1068,12 @@ 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);
+typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
+					struct mlx5_flow_meter_info *fm,
+					uint32_t mtr_idx,
+					uint8_t domain_bitmap);
+typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1387,10 +1389,12 @@ int mlx5_flow_validate_item_ecpri(const struct rte_flow_item *item,
 				  uint16_t ether_type,
 				  const struct rte_flow_item_ecpri *acc_mask,
 				  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);
+int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
+				uint32_t mtr_idx,
+				uint8_t domain_bitmap);
+void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter_info *fm);
 int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
 			  struct rte_mtr_error *error);
 void flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 3992ad6980..7172d045ef 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -4856,11 +4856,14 @@ 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,
+				uint32_t *policy_id,
 				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_info *fm;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 
 	if (!am)
 		return rte_flow_error_set(error, EINVAL,
@@ -4891,10 +4894,41 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
 	      (!fm->ingress && !attr->ingress && attr->egress) ||
 	      (!fm->egress && !attr->egress && attr->ingress)))
 		return rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Flow attributes domain are either invalid "
+			"or have a domain conflict with current "
+			"meter attributes");
+	if (priv->sh->meter_aso_en) {
+		if (fm->policy_id) {
+			mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+			if (!mtr_policy)
+				return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Invalid policy id for meter ");
+			if (!((attr->transfer && mtr_policy->transfer) ||
+				(attr->egress && mtr_policy->egress) ||
+				(attr->ingress && mtr_policy->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");
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		} else {
+			if (!((attr->transfer &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
+				(attr->egress &&
+				mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
+				(attr->ingress &&
+				mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
+				return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		}
+	}
+	*policy_id = fm->policy_id;
 	return 0;
 }
 
@@ -6269,6 +6303,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		.fdb_def_rule = !!priv->fdb_def_rule,
 	};
 	const struct rte_eth_hairpin_conf *conf;
+	uint32_t policy_id = 0;
 
 	if (items == NULL)
 		return -1;
@@ -6610,6 +6645,12 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
 						  actions, "too many actions");
+		if (action_flags &
+			MLX5_FLOW_ACTION_METER_WITE_TERMINATED_POLICY)
+			return rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "meter action with policy "
+				"must be the last action");
 		switch (type) {
 		case RTE_FLOW_ACTION_TYPE_VOID:
 			break;
@@ -7012,10 +7053,14 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			ret = mlx5_flow_validate_action_meter(dev,
 							      action_flags,
 							      actions, attr,
+							      &policy_id,
 							      error);
 			if (ret < 0)
 				return ret;
 			action_flags |= MLX5_FLOW_ACTION_METER;
+			if (policy_id)
+				action_flags |=
+				MLX5_FLOW_ACTION_METER_WITE_TERMINATED_POLICY;
 			++actions_n;
 			/* Meter action will add one more TAG action. */
 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
@@ -7275,6 +7320,36 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 						 "multiple VLAN actions");
 		}
 	}
+	if (action_flags & MLX5_FLOW_ACTION_METER_WITE_TERMINATED_POLICY) {
+		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
+			~MLX5_FLOW_ACTION_METER_WITE_TERMINATED_POLICY)) &&
+			attr->ingress)
+			return rte_flow_error_set
+				(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "fate action not supported for "
+				"meter with policy");
+		if (attr->egress) {
+			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "modify header action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "encap action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "push vlan action in egress "
+					"cannot be done before meter action");
+		}
+	}
 	/*
 	 * Hairpin flow will add one more TAG action in TX implicit mode.
 	 * In TX explicit mode, there will be no hairpin flow ID.
@@ -13975,38 +14050,24 @@ flow_dv_query(struct rte_eth_dev *dev,
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
- * @param[in] tbl
- *   Pointer to the meter table set.
- *
- * @return
- *   Always 0.
+ * @param[in] fm
+ *   Meter information table.
  */
-static int
-flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
-			struct mlx5_meter_domains_infos *tbl)
+static void
+flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_meter_domains_infos *mtd =
-				(struct mlx5_meter_domains_infos *)tbl;
+	int i;
 
-	if (!mtd || !priv->config.dv_flow_en)
-		return 0;
-	if (mtd->egress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.tbl);
-	if (mtd->egress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.sfx_tbl);
-	if (mtd->ingress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->ingress.tbl);
-	if (mtd->ingress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->ingress.sfx_tbl);
-	if (mtd->transfer.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->transfer.tbl);
-	if (mtd->transfer.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->transfer.sfx_tbl);
-	mlx5_free(mtd);
-	return 0;
+	if (!fm || !priv->config.dv_flow_en)
+		return;
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
+		}
+	}
 }
 
 void
@@ -14015,7 +14076,7 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct mlx5_flow_tbl_data_entry *tbl;
-	int i;
+	int i, j;
 
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (mtrmng->def_rule[i]) {
@@ -14030,12 +14091,16 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 				      &mtrmng->def_matcher[i]->entry);
 			mtrmng->def_matcher[i] = NULL;
 		}
-		if (mtrmng->drop_matcher[i]) {
-			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
-				struct mlx5_flow_tbl_data_entry, tbl);
-			mlx5_cache_unregister(&tbl->matchers,
-				      &mtrmng->drop_matcher[i]->entry);
-			mtrmng->drop_matcher[i] = NULL;
+		for (j = 0; j < MLX5_REG_BITS; j++) {
+			if (mtrmng->drop_matcher[i][j]) {
+				tbl =
+				container_of(mtrmng->drop_matcher[i][j]->tbl,
+					     struct mlx5_flow_tbl_data_entry,
+					     tbl);
+				mlx5_cache_unregister(&tbl->matchers,
+					&mtrmng->drop_matcher[i][j]->entry);
+				mtrmng->drop_matcher[i][j] = NULL;
+			}
 		}
 		if (mtrmng->drop_tbl[i]) {
 			flow_dv_tbl_resource_release(MLX5_SH(dev),
@@ -14476,96 +14541,171 @@ flow_dv_create_def_policy(struct rte_eth_dev *dev)
 }
 
 /**
- * Create specify domain meter table and suffix table.
+ * Create the needed meter tables.
+ * Lock free, (mutex should be acquired by caller).
  *
  * @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] fm
+ *   Meter information table.
+ * @param[in] mtr_idx
+ *   Meter index.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] domain_bitmap
+ *   Domain bitmap.
  * @return
  *   0 on success, -1 otherwise.
  */
 static int
-flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *mtb,
-			   uint8_t egress, uint8_t transfer)
-{
-	struct rte_flow_error error;
-	struct mlx5_meter_domain_info *dtb;
-
-	if (transfer)
-		dtb = &mtb->transfer;
-	else if (egress)
-		dtb = &mtb->egress;
-	else
-		dtb = &mtb->ingress;
-	/* Create the meter suffix table with SUFFIX level. */
-	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
-					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
-	if (!dtb->sfx_tbl) {
-		DRV_LOG(ERR, "Failed to create meter suffix table.");
-		return -1;
-	}
-	return 0;
-}
-
-/**
- * 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)
+flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_meter_domains_infos *mtb;
-	int ret;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct rte_flow_error error;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	void *actions[METER_ACTIONS];
+	int domain, ret, i;
+	struct mlx5_flow_counter *cnt;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher_para = {
+		.size = sizeof(matcher_para.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	uint32_t mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
+						     0, &error);
+	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+	};
+	struct mlx5_flow_dv_matcher *drop_matcher;
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = &error,
+		.data = &matcher,
+	};
 
 	if (!priv->mtr_en) {
 		rte_errno = ENOTSUP;
-		return NULL;
-	}
-	mtb = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*mtb), 0, SOCKET_ID_ANY);
-	if (!mtb) {
-		DRV_LOG(ERR, "Failed to allocate memory for meter.");
-		return NULL;
-	}
-	/* Egress meter table. */
-	ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0);
-	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);
-	if (ret) {
-		DRV_LOG(ERR, "Failed to prepare ingress meter table.");
-		goto error_exit;
+		return -1;
 	}
-	/* FDB meter table. */
-	if (priv->config.dv_esw_en) {
-		ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 1);
+	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
+		if (!(domain_bitmap & (1 << domain)) ||
+			(mtrmng->def_rule[domain] && !fm->drop_cnt))
+			continue;
+		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		/* Create the drop table with METER DROP level. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
+					MLX5_FLOW_TABLE_LEVEL_METER_DROP,
+					egress, transfer, false, NULL, 0,
+					0, 0, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create meter drop table.");
+				goto policy_error;
+			}
+		}
+		/* Create default matcher in drop table. */
+		matcher.tbl = mtrmng->drop_tbl[domain],
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		if (!mtrmng->def_matcher[domain]) {
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+				       (enum modify_reg)mtr_id_reg_c,
+				       0, 0);
+			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR, "Failed to register meter "
+				"drop default matcher.");
+				goto policy_error;
+			}
+			mtrmng->def_matcher[domain] = container_of(entry,
+			struct mlx5_flow_dv_matcher, entry);
+		}
+		/* Create default rule in drop table. */
+		if (!mtrmng->def_rule[domain]) {
+			i = 0;
+			actions[i++] = priv->sh->esw_drop_action;
+			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c, 0, 0);
+			ret = mlx5_flow_os_create_flow
+				(mtrmng->def_matcher[domain]->matcher_object,
+				(void *)&value, i, actions,
+				&mtrmng->def_rule[domain]);
+			if (ret) {
+				DRV_LOG(ERR, "Failed to create meter "
+				"default drop rule for drop table.");
+				goto policy_error;
+			}
+		}
+		if (!fm->drop_cnt)
+			continue;
+		MLX5_ASSERT(mtrmng->max_mtr_bits);
+		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
+			/* Create matchers for Drop. */
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+					(enum modify_reg)mtr_id_reg_c, 0,
+					(LS32_MASK(mtrmng->max_mtr_bits) <<
+					 mtr_id_offset));
+			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR,
+				"Failed to register meter drop matcher.");
+				goto policy_error;
+			}
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
+				container_of(entry, struct mlx5_flow_dv_matcher,
+					     entry);
+		}
+		drop_matcher =
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
+		/* Create drop rule, matching meter_id only. */
+		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c,
+				(mtr_idx << mtr_id_offset), UINT32_MAX);
+		i = 0;
+		cnt = flow_dv_counter_get_by_idx(dev,
+					fm->drop_cnt, NULL);
+		actions[i++] = cnt->action;
+		actions[i++] = priv->sh->esw_drop_action;
+		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
+					       (void *)&value, i, actions,
+					       &fm->drop_rule[domain]);
 		if (ret) {
-			DRV_LOG(ERR, "Failed to prepare fdb meter table.");
-			goto error_exit;
+			DRV_LOG(ERR, "Failed to create meter "
+				"drop rule for drop table.");
+				goto policy_error;
 		}
 	}
-	return mtb;
-error_exit:
-	flow_dv_destroy_mtr_tbl(dev, mtb);
-	return NULL;
+	return 0;
+policy_error:
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
+		}
+	}
+	return -1;
 }
 
 /**
@@ -15127,8 +15267,8 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.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,
+	.create_mtr_tbls = flow_dv_create_mtr_tbls,
+	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
 	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 25c78cfd3c..be256a376c 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -614,9 +614,12 @@ mlx5_flow_meter_policy_create(struct rte_eth_dev *dev,
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (!(domain_bitmap & (1 << i)))
 			continue;
-		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
-		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
-		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		if (i == MLX5_MTR_DOMAIN_INGRESS)
+			mtr_policy->ingress = 1;
+		if (i == MLX5_MTR_DOMAIN_EGRESS)
+			mtr_policy->egress = 1;
+		if (i == MLX5_MTR_DOMAIN_TRANSFER)
+			mtr_policy->transfer = 1;
 		sub_policy = mlx5_ipool_zmalloc
 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
 				&sub_policy_idx);
@@ -626,7 +629,7 @@ mlx5_flow_meter_policy_create(struct rte_eth_dev *dev,
 			goto policy_add_err;
 		sub_policy->idx = sub_policy_idx;
 		sub_policy->main_policy = mtr_policy;
-		if (policy_idx) {
+		if (!policy_idx) {
 			policy_idx = sub_policy_idx;
 			sub_policy->main_policy_id = 1;
 		}
@@ -788,6 +791,52 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * 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)
+{
+	/* Meter must use global drop action. */
+	if (!priv->sh->esw_drop_action)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL,
+					  "No drop action ready for meter.");
+	/* 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 meter id. */
+	if (mlx5_flow_meter_find(priv, meter_id, NULL))
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+			"Meter object already exists.");
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -893,13 +942,209 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 #endif
 }
 
-static void
-mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
+static int
+mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
 				uint64_t stats_mask)
 {
 	fm->bytes_dropped =
 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
+	if (fm->bytes_dropped || fm->pkts_dropped) {
+		if (!fm->drop_cnt) {
+			/* Alloc policer counters. */
+			fm->drop_cnt = mlx5_counter_alloc(dev);
+			if (!fm->drop_cnt)
+				return -1;
+		}
+	} else {
+		if (fm->drop_cnt) {
+			mlx5_counter_free(dev, fm->drop_cnt);
+			fm->drop_cnt = 0;
+		}
+	}
+	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_legacy_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_flow_meter_info *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_indexed_pool_config flow_ipool_cfg = {
+		.size = 0,
+		.trunk_size = 64,
+		.need_lock = 1,
+		.type = "mlx5_flow_mtr_flow_id_pool",
+	};
+	struct mlx5_aso_mtr *aso_mtr;
+	uint32_t mtr_idx;
+	union mlx5_l3t_data data;
+	int ret;
+	uint8_t domain_bitmap;
+	uint8_t mtr_id_bits;
+	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
+				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter is not supported");
+	/* 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.");
+	/* Meter policy must exist. */
+	if (params->meter_policy_id != RTE_MTR_DEFAULT_POLICY_ID) {
+		if (!priv->sh->meter_aso_en)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Part of the policies cannot be "
+				"supported without ASO ");
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+				params->meter_policy_id, NULL);
+		if (!mtr_policy)
+			return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+		domain_bitmap = (mtr_policy->ingress ?
+					MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
+				(mtr_policy->egress ?
+					MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
+				(mtr_policy->transfer ?
+					MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
+	} else {
+		if (!priv->sh->meter_aso_en) {
+			if (mlx5_flow_create_def_policy(dev))
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "fail to create default policy.");
+			if (!priv->sh->mtrmng->def_policy_ref_cnt)
+				__atomic_add_fetch
+				(&priv->sh->mtrmng->def_policy_ref_cnt,
+				1, __ATOMIC_RELAXED);
+		} else {
+			if (!priv->sh->mtrmng->def_policy_ref_cnt)
+				return -rte_mtr_error_set(error, ENOENT,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+					NULL, "Meter policy id not valid.");
+		}
+		__atomic_add_fetch
+			(&priv->sh->mtrmng->def_policy_mtr_ref_cnt,
+			1, __ATOMIC_RELAXED);
+		domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
+		if (!priv->config.dv_esw_en)
+			domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	}
+	/* Allocate the flow meter memory. */
+	if (priv->sh->meter_aso_en) {
+		mtr_idx = mlx5_flow_mtr_alloc(dev);
+		if (!mtr_idx)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+		fm = &aso_mtr->fm;
+	} else {
+		legacy_fm = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
+		if (legacy_fm == NULL)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		legacy_fm->idx = mtr_idx;
+		fm = &legacy_fm->fm;
+	}
+	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
+	if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
+	    mtr_reg_bits) {
+		DRV_LOG(ERR, "Meter number exceeds max limit.");
+		goto error;
+	}
+	if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
+		priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
+	/* Fill the flow meter parameters. */
+	fm->meter_id = meter_id;
+	fm->policy_id = params->meter_policy_id;
+	fm->profile = fmp;
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
+		goto error;
+	if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
+		goto error;
+	/* Add to the flow meter list. */
+	if (!priv->sh->meter_aso_en)
+		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
+	/* Add to the flow meter list. */
+	fm->active_state = 1; /* Config meter starts as active. */
+	fm->is_enable = 1;
+	fm->shared = !!shared;
+	__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
+	if (params->meter_policy_id == RTE_MTR_DEFAULT_POLICY_ID) {
+		fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
+		if (!fm->flow_ipool)
+			goto error;
+	}
+	rte_spinlock_init(&fm->sl);
+	/* If ASO meter supported, update ASO flow meter by wqe. */
+	if (priv->sh->meter_aso_en) {
+		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
+		if (ret)
+			goto error;
+		if (!priv->mtr_idx_tbl) {
+			priv->mtr_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+			if (!priv->mtr_idx_tbl)
+				goto error;
+		}
+		data.dword = mtr_idx;
+		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
+			goto error;
+	}
+	if (mtr_policy)
+		__atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
+	return 0;
+error:
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	/* Free policer counters. */
+	if (fm->drop_cnt)
+		mlx5_counter_free(dev, fm->drop_cnt);
+	if (priv->sh->meter_aso_en)
+		mlx5_flow_mtr_free(dev, mtr_idx);
+	else
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
+	return -rte_mtr_error_set(error, ENOTSUP,
+		RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+		NULL, "Failed to create devx meter.");
 }
 
 static int
@@ -911,6 +1156,7 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
+	struct mlx5_flow_meter_policy *mtr_policy;
 
 	/* Meter object must not have any owner. */
 	MLX5_ASSERT(!fm->ref_cnt);
@@ -920,9 +1166,11 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 		return -1;
 	/* Update dependencies. */
 	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
+	fm->profile = NULL;
 	/* Remove from list. */
 	if (!priv->sh->meter_aso_en) {
-		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
+		legacy_fm = container_of(fm,
+			struct mlx5_legacy_flow_meter, fm);
 		TAILQ_REMOVE(fms, legacy_fm, next);
 	}
 	/* Free drop counters. */
@@ -931,12 +1179,27 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 	/* Free meter flow table. */
 	if (fm->flow_ipool)
 		mlx5_ipool_destroy(fm->flow_ipool);
-	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-	if (priv->sh->meter_aso_en)
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	if (fm->policy_id == RTE_MTR_DEFAULT_POLICY_ID) {
+		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_mtr_ref_cnt,
+				1, __ATOMIC_RELAXED);
+	}
+	if (priv->sh->meter_aso_en) {
+		if (fm->policy_id != RTE_MTR_DEFAULT_POLICY_ID) {
+			mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+			if (mtr_policy)
+				__atomic_sub_fetch(&mtr_policy->ref_cnt,
+						1, __ATOMIC_RELAXED);
+			fm->policy_id = 0;
+		}
+		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
+			return -1;
 		mlx5_flow_mtr_free(dev, mtr_idx);
-	else
+	} else {
 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
 					legacy_fm->idx);
+	}
 	return 0;
 }
 
@@ -963,30 +1226,28 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
-					  NULL, "Meter object id not valid.");
+					  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.");
-	if (priv->sh->meter_aso_en) {
-		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id))
-			return -rte_mtr_error_set(error, EBUSY,
-				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Fail to delete ASO Meter in index table.");
-	}
+					  NULL,
+					  "Meter object is being used.");
 	/* Destroy the meter profile. */
 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
 		return -rte_mtr_error_set(error, EINVAL,
 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+					NULL,
+					"MTR object meter profile invalid.");
 	return 0;
 }
 
@@ -1220,7 +1481,11 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
 					  NULL, "Meter object id not valid.");
-	mlx5_flow_meter_stats_enable_update(fm, stats_mask);
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_MTR_ID,
+					  NULL, "Fail to allocate "
+					  "counter for meter.");
 	return 0;
 }
 
@@ -1298,6 +1563,7 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.meter_policy_validate = mlx5_flow_meter_policy_validate,
 	.meter_policy_create = mlx5_flow_meter_policy_create,
 	.meter_policy_delete = mlx5_flow_meter_policy_delete,
+	.create = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -1336,7 +1602,7 @@ mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
  *   Pointer to Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
@@ -1351,30 +1617,27 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 
 	if (priv->sh->meter_aso_en) {
 		rte_spinlock_lock(&pools_mng->mtrsl);
-		if (priv->mtr_idx_tbl) {
-			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
-				meter_id, &data) ||
-				!data.dword) {
-				rte_spinlock_unlock(&pools_mng->mtrsl);
-				return NULL;
-			}
-			if (mtr_idx)
-				*mtr_idx = data.dword;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-			/* Remove reference taken by the mlx5_l3t_get_entry. */
-			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		} else {
-			if (mtr_idx)
-				*mtr_idx = meter_id;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
+		if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
 		}
+		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
+			!data.dword) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
+		}
+		if (mtr_idx)
+			*mtr_idx = data.dword;
+		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+		/* Remove reference taken by the mlx5_l3t_get_entry. */
+		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
 		rte_spinlock_unlock(&pools_mng->mtrsl);
 		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
 			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
-		if (meter_id == legacy_fm->meter_id) {
+		if (meter_id == legacy_fm->fm.meter_id) {
 			if (mtr_idx)
 				*mtr_idx = legacy_fm->idx;
 			return &legacy_fm->fm;
@@ -1391,7 +1654,7 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
  *   Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
@@ -1400,6 +1663,8 @@ flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
 
 	if (priv->sh->meter_aso_en) {
 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
+		if (!aso_mtr)
+			return NULL;
 		return &aso_mtr->fm;
 	} else {
 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
-- 
2.27.0


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

* [dpdk-dev] [PATCH 3/4] net/mlx5: prepare sub-policy for a flow with meter
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 1/4] " Li Zhang
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 2/4] net/mlx5: support meter creation with policy Li Zhang
@ 2021-04-01  8:16 ` Li Zhang
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 4/4] net/mlx5: connect meter policy to created flows Li Zhang
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-01  8:16 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

When a flow with RSS action, the MLX5 PMD splitted the flow
into several sub flow according to the flow RSS hashfield value,
each sub flow requested the different RSS TIR.

The new meter introduces the policy, for the meter flow with RSS
in the policy action, each RSS TIR in meter policy maintains
own sub-policy table resource.

This patch adds the function that find the correct policy table
resource according the RSS sub policy id.

Signed-off-by: Li Zhang <lizh@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.h    |  10 +++
 drivers/net/mlx5/mlx5_flow_dv.c | 136 ++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index b630cfd661..fc9622b498 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1074,6 +1074,11 @@ typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
 					uint8_t domain_bitmap);
 typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 				struct mlx5_flow_meter_info *fm);
+typedef struct mlx5_flow_meter_sub_policy *
+	(*mlx5_flow_meter_sub_policy_prepare_t)
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1165,6 +1170,7 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
 	mlx5_flow_create_def_policy_t create_def_policy;
 	mlx5_flow_destroy_def_policy_t destroy_def_policy;
+	mlx5_flow_meter_sub_policy_prepare_t meter_sub_policy_prepare;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1395,6 +1401,10 @@ int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
 				uint8_t domain_bitmap);
 void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_flow_meter_info *fm);
+struct mlx5_flow_meter_sub_policy *mlx5_flow_meter_sub_policy_prepare
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
 			  struct rte_mtr_error *error);
 void flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 7172d045ef..d93097b755 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -14708,6 +14708,141 @@ flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
 	return -1;
 }
 
+/**
+ * Find the policy table for prefix table with RSS.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ * @return
+ *   Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_dv_meter_sub_policy_prepare(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint32_t sub_policy_idx = 0;
+	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
+	uint32_t i, j;
+	struct mlx5_hrxq *hrxq;
+	struct mlx5_flow_handle dh;
+	struct mlx5_meter_policy_action_container *act_cnt;
+	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
+	uint16_t sub_policy_num;
+
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	MLX5_ASSERT(mtr_policy && mtr_policy->is_rss);
+	rte_spinlock_lock(&mtr_policy->sl);
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
+		if (!hrxq_idx[i]) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return NULL;
+		}
+	}
+	sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+	for (i = 0; i < sub_policy_num;
+		i++) {
+		for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) {
+			if (rss_desc[j] &&
+				hrxq_idx[j] !=
+			mtr_policy->sub_policys[domain][i]->rix_hrxq[j])
+				break;
+		}
+		if (j >= MLX5_MTR_RTE_COLORS) {
+			/*
+			 * Found the sub policy table with
+			 * the same queue per color
+			 */
+			rte_spinlock_unlock(&mtr_policy->sl);
+			for (j = 0; j < MLX5_MTR_RTE_COLORS; j++)
+				mlx5_hrxq_release(dev, hrxq_idx[j]);
+			return mtr_policy->sub_policys[domain][i];
+		}
+	}
+	/* Create sub policy. */
+	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
+		/* Reuse the first dummy sub_policy*/
+		sub_policy = mtr_policy->sub_policys[domain][0];
+		sub_policy_idx = sub_policy->idx;
+	} else {
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy ||
+			sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto rss_sub_policy_error;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		sub_policy->rix_hrxq[i] = hrxq_idx[i];
+		/*
+		 * Overwrite the last action from
+		 * RSS action to Queue action.
+		 */
+		hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+			      hrxq_idx[i]);
+		if (!hrxq) {
+			DRV_LOG(ERR, "Failed to create policy hrxq");
+			goto rss_sub_policy_error;
+		}
+		act_cnt = &mtr_policy->act_cnt[i];
+		if (act_cnt->rix_mark || act_cnt->modify_hdr) {
+			memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+			if (act_cnt->rix_mark)
+				dh.mark = 1;
+			dh.fate_action = MLX5_FLOW_FATE_QUEUE;
+			dh.rix_hrxq = hrxq_idx[i];
+			flow_drv_rxq_flags_set(dev, &dh);
+		}
+	}
+	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+		sub_policy, domain)) {
+		DRV_LOG(ERR, "Failed to create policy "
+			"rules per domain.");
+		goto rss_sub_policy_error;
+	}
+	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+		i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		mtr_policy->sub_policys[domain][i] = sub_policy;
+		i++;
+		if (i > MLX5_MTR_RSS_MAX_SUB_POLICY)
+			goto rss_sub_policy_error;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MARK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
+		mtr_policy->sub_policy_num |=
+			(i & MLX5_MTR_SUB_POLICY_NUM_MARK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return sub_policy;
+rss_sub_policy_error:
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
+		mlx5_hrxq_release(dev, hrxq_idx[i]);
+	if (sub_policy_idx)
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+			sub_policy_idx);
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return NULL;
+}
+
 /**
  * Validate the batch counter support in root table.
  *
@@ -15278,6 +15413,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
 	.create_def_policy = flow_dv_create_def_policy,
 	.destroy_def_policy = flow_dv_destroy_def_policy,
+	.meter_sub_policy_prepare = flow_dv_meter_sub_policy_prepare,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
-- 
2.27.0


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

* [dpdk-dev] [PATCH 4/4] net/mlx5: connect meter policy to created flows
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (2 preceding siblings ...)
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
@ 2021-04-01  8:16 ` Li Zhang
  2021-04-02 15:56 ` [dpdk-dev] [PATCH v2 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-01  8:16 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs
  Cc: dev, thomas, rasland, roniba, Shun Hao

From: Shun Hao <shunh@nvidia.com>

Currently ASO meter must be followed by policy table, so this adds
the support that connecting meter and policy table.

There are several cases to be considered:
1. For non-termination policy, connect meter to the default policy
table.
2. For non-RSS termination policy case, simply get the policy
table id and connect meter to it.
3. For RSS termination policy case, need to split the flow due
to RSS info in policy, and translate each sub-flow using that RSS,
then create the sub policy table to be connected.
4. In termination policy case, if there's no actions to modify the
packet before meter, no need to use set_tag to save meter id in
register. Only add a new flow in drop table using the same match
criteria as suf-flow, to save cache miss.

Signed-off-by: Shun Hao <shunh@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.c    | 425 ++++++++++++++++++++++++++++----
 drivers/net/mlx5/mlx5_flow.h    |   9 +
 drivers/net/mlx5/mlx5_flow_dv.c |  24 +-
 3 files changed, 406 insertions(+), 52 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index e76db6ffb7..d97233c309 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -3359,18 +3359,52 @@ flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 	fops->destroy(dev, flow);
 }
 
+/**
+ * Flow driver find RSS policy tbl API. This abstracts calling driver
+ * specific functions. Parent flow (rte_flow) should have driver
+ * type (drv_type). It will find the RSS policy table that has the rss_desc.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in, out] flow
+ *   Pointer to flow structure.
+ * @param[in] policy_id
+ *   The policy id of a meter.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_drv_meter_sub_policy_prepare(struct rte_eth_dev *dev,
+		struct rte_flow *flow,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	const struct mlx5_flow_driver_ops *fops;
+	enum mlx5_flow_drv_type type = flow->drv_type;
+
+	MLX5_ASSERT(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
+	fops = flow_get_drv_ops(type);
+	return fops->meter_sub_policy_prepare(dev, policy_id, rss_desc);
+}
+
 /**
  * Get RSS action from the action list.
  *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
+ * @param[in] flow
+ *   Parent flow structure pointer.
  *
  * @return
  *   Pointer to the RSS action if exist, else return NULL.
  */
 static const struct rte_flow_action_rss*
-flow_get_rss_action(const struct rte_flow_action actions[])
+flow_get_rss_action(struct rte_eth_dev *dev,
+		    const struct rte_flow_action actions[])
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
 	const struct rte_flow_action_rss *rss = NULL;
 
 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -3388,6 +3422,23 @@ flow_get_rss_action(const struct rte_flow_action actions[])
 					rss = act->conf;
 			break;
 		}
+		case RTE_FLOW_ACTION_TYPE_METER:
+		{
+			uint32_t mtr_idx;
+			struct mlx5_flow_meter_info *fm;
+			struct mlx5_flow_meter_policy *policy;
+			const struct rte_flow_action_meter *mtr = actions->conf;
+
+			fm = mlx5_flow_meter_find(priv, mtr->mtr_id, &mtr_idx);
+			if (fm) {
+				policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+				if (policy && policy->is_rss)
+					rss =
+				policy->act_cnt[RTE_COLOR_GREEN].rss->conf;
+			}
+			break;
+		}
 		default:
 			break;
 		}
@@ -3686,6 +3737,55 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
 	return actions_n + 1;
 }
 
+/**
+ * Check if the action will change packet.
+ *
+ * @param[in] type
+ *   action type.
+ *
+ * @return
+ *   true if action will change packet, false otherwise.
+ */
+static bool flow_check_modify_action_type(enum rte_flow_action_type type)
+{
+	switch (type) {
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
+	case RTE_FLOW_ACTION_TYPE_DEC_TTL:
+	case RTE_FLOW_ACTION_TYPE_SET_TTL:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
+	case RTE_FLOW_ACTION_TYPE_FLAG:
+	case RTE_FLOW_ACTION_TYPE_MARK:
+	case RTE_FLOW_ACTION_TYPE_SET_META:
+	case RTE_FLOW_ACTION_TYPE_SET_TAG:
+	case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+	case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
+		return true;
+	default:
+		return false;
+	}
+}
+
 /**
  * Check meter action from the action list.
  *
@@ -3693,6 +3793,8 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
  *   Pointer to the list of actions.
  * @param[out] has_mtr
  *   Pointer to the meter exist flag.
+ * @param[out] has_modify
+ *   Pointer to the flag showing there's packet change action.
  * @param[out] meter_id
  *   Pointer to the meter id.
  *
@@ -3701,8 +3803,7 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
  */
 static int
 flow_check_meter_action(const struct rte_flow_action actions[],
-			bool *has_mtr,
-			uint32_t *meter_id)
+			bool *has_mtr, bool *has_modify, uint32_t *meter_id)
 {
 	const struct rte_flow_action_meter *mtr = NULL;
 	int actions_n = 0;
@@ -3719,6 +3820,9 @@ flow_check_meter_action(const struct rte_flow_action actions[],
 		default:
 			break;
 		}
+		if (!*has_mtr)
+			*has_modify |=
+				flow_check_modify_action_type(actions->type);
 		actions_n++;
 	}
 	/* Count RTE_FLOW_ACTION_TYPE_END. */
@@ -4361,6 +4465,112 @@ flow_create_split_inner(struct rte_eth_dev *dev,
 	return flow_drv_translate(dev, dev_flow, attr, items, actions, error);
 }
 
+/**
+ * Get the table id of meter policy table.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
+ * @param[in] policy_id;
+ *   Meter Policy id.
+ * @param[in] attr
+ *   Flow rule attributes.
+ * @param[in] items
+ *   Pattern specification (list terminated by the END pattern item).
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   The table id, 0 otherwise and rte_errno is set.
+ */
+static uint32_t
+get_sub_policy_tbl_id(struct rte_eth_dev *dev,
+		      struct rte_flow *flow,
+		      uint32_t policy_id,
+		      const struct rte_flow_attr *attr,
+		      const struct rte_flow_item items[],
+		      struct rte_flow_error *error)
+{
+	uint32_t policy_tbl_id = 0;
+	struct mlx5_flow_meter_policy *policy;
+
+	policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	if (!policy) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Failed to find Meter Policy.");
+		goto exit;
+	}
+	if (policy->is_rss) {
+		struct mlx5_flow_workspace *wks =
+				mlx5_flow_get_thread_workspace();
+		struct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};
+		struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+		uint32_t i;
+
+		MLX5_ASSERT(wks);
+		/** This is a tmp dev_flow,
+		 *  no need to register any matcher for it in translate.
+		 */
+		wks->skip_matcher_reg = 1;
+		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+			struct mlx5_flow dev_flow = {0};
+			struct mlx5_flow_handle dev_handle = {{0}};
+			const void *rss_act = policy->act_cnt[i].rss->conf;
+			struct rte_flow_action rss_actions[2] = {
+				[0] = {
+					.type = RTE_FLOW_ACTION_TYPE_RSS,
+					.conf = rss_act
+				},
+				[1] = {
+					.type = RTE_FLOW_ACTION_TYPE_END,
+					.conf = NULL
+				}
+			};
+
+			dev_flow.handle = &dev_handle;
+			dev_flow.ingress = attr->ingress;
+			dev_flow.flow = flow;
+			dev_flow.external = 0;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+			dev_flow.dv.transfer = attr->transfer;
+#endif
+			/* Translate RSS action to get rss hash fields. */
+			if (flow_drv_translate(dev, &dev_flow, attr,
+						items, rss_actions, error))
+				goto exit;
+			rss_desc_v[i] = wks->rss_desc;
+			rss_desc_v[i].key_len = MLX5_RSS_HASH_KEY_LEN;
+			rss_desc_v[i].hash_fields = dev_flow.hash_fields;
+			rss_desc_v[i].queue_num = rss_desc_v[i].hash_fields ?
+						  rss_desc_v[i].queue_num : 1;
+			rss_desc[i] = &rss_desc_v[i];
+		}
+		sub_policy = flow_drv_meter_sub_policy_prepare(dev,
+						flow, policy_id, rss_desc);
+		if (!sub_policy) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to get meter RSS policy table.");
+			goto exit;
+		}
+		policy_tbl_id = sub_policy->idx;
+	} else {
+		enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+		policy_tbl_id =
+			policy->sub_policys[mtr_domain][0]->idx;
+	}
+exit:
+	return policy_tbl_id;
+}
+
+#define MLX5_MTR_PRE_TAG_NUM 2
+
 /**
  * Split the meter flow.
  *
@@ -4391,13 +4601,15 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *   Suffix flow actions.
  * @param[out] actions_pre
  *   Prefix flow actions.
+ * @param[out] mtr_flow_id
+ *   Pointer to meter flow id.
  * @param[out] error
  *   Perform verbose error reporting if not NULL.
  *
  * @return
- *   The flow id, 0 otherwise and rte_errno is set.
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
-static uint32_t
+static int
 flow_meter_split_prep(struct rte_eth_dev *dev,
 		      struct rte_flow *flow,
 		      struct mlx5_flow_meter_info *fm,
@@ -4407,6 +4619,7 @@ 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[],
+		      uint32_t *mtr_flow_id,
 		      struct rte_flow_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
@@ -4420,7 +4633,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	uint32_t tag_id = 0;
 	bool copy_vlan = false;
 	struct rte_flow_action *hw_mtr_action;
-	struct rte_flow_action_jump *jump_data;
+	struct mlx5_rte_flow_item_mtr_jump *jump_data;
 	struct rte_flow_action *action_pre_head = NULL;
 	bool mtr_first = priv->sh->meter_aso_en &&
 			 (attr->egress ||
@@ -4429,8 +4642,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
 				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
 	uint8_t flow_id_bits = 0;
-	int shift;
-	uint32_t flow_id_val = 0;
 
 	/* For ASO meter, meter must be before tag in TX direction. */
 	if (mtr_first) {
@@ -4474,7 +4685,9 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 			break;
 		}
 		if (!action_cur)
-			action_cur = actions_sfx++;
+			action_cur =
+				(fm->policy_id != RTE_MTR_DEFAULT_POLICY_ID) ?
+					actions_pre++ : actions_sfx++;
 		memcpy(action_cur, actions, sizeof(struct rte_flow_action));
 	}
 	/* Add end action to the actions. */
@@ -4483,37 +4696,56 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		/** For ASO meter, need to add an extra jump action explicitly,
 		 *  to jump from meter to policer table.
 		 */
+		uint32_t sub_policy_tbl_id = 0;
+
+		if (fm->policy_id != RTE_MTR_DEFAULT_POLICY_ID) {
+			sub_policy_tbl_id =
+				get_sub_policy_tbl_id(dev, flow, fm->policy_id,
+						      attr, items, error);
+			if (!sub_policy_tbl_id)
+				return -rte_errno;
+		}
 		hw_mtr_action = actions_pre;
-		hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
+		hw_mtr_action->type = (enum rte_flow_action_type)
+				      MLX5_RTE_FLOW_ACTION_TYPE_MTR_JUMP;
 		actions_pre++;
 		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
 		actions_pre++;
-		jump_data = (struct rte_flow_action_jump *)actions_pre;
-		jump_data->group = attr->transfer ?
+		jump_data = (struct mlx5_rte_flow_item_mtr_jump *)actions_pre;
+		jump_data->table_group.group = attr->transfer ?
 				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
 				 MLX5_FLOW_TABLE_LEVEL_POLICY;
+		jump_data->table_id = sub_policy_tbl_id;
 		hw_mtr_action->conf = jump_data;
 		actions_pre = (struct rte_flow_action *)(jump_data + 1);
 	} else {
 		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
 		actions_pre++;
 	}
-	/* Generate meter flow_id only if support multiple flows per meter. */
-	mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
-	if (!tag_id)
-		return rte_flow_error_set(error, ENOMEM,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Failed to allocate meter flow id.");
-	flow_id_bits = MLX5_REG_BITS - __builtin_clz(tag_id - 1);
-	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
-		mlx5_ipool_free(fm->flow_ipool, tag_id);
-		return rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Meter flow id exceeds max limit.");
+	MLX5_ASSERT(tag_action);
+	if (!mtr_flow_id) {
+		tag_action->type = RTE_FLOW_ACTION_TYPE_VOID;
+		goto exit;
+	}
+	/* Only Non-termination Policy Meter creates mtr flow id. */
+	if (fm->policy_id == RTE_MTR_DEFAULT_POLICY_ID) {
+		mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
+		if (!tag_id)
+			return rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to allocate meter flow id.");
+		flow_id_bits = MLX5_REG_BITS - __builtin_clz(tag_id - 1);
+		flow_id_bits = flow_id_bits ? flow_id_bits : 1;
+		if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) >
+		    mtr_reg_bits) {
+			mlx5_ipool_free(fm->flow_ipool, tag_id);
+			return rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter flow id exceeds max limit.");
+		}
+		if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+			priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	}
-	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
-		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -4543,7 +4775,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
 	sfx_items++;
 	/* Build tag actions and items for meter_id/meter flow_id. */
-	assert(tag_action);
 	set_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;
 	tag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;
 	tag_item_mask = tag_item_spec + 1;
@@ -4554,14 +4785,19 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		.length = mtr_reg_bits,
 		.data = flow->meter,
 	};
-	/*
-	 * The color Reg bits used by flow_id are growing from
-	 * msb to lsb, so must do bit reverse for flow_id val in RegC.
-	 */
-	for (shift = 0; shift < flow_id_bits; shift++)
-		flow_id_val = (flow_id_val << 1) |
-			      (((tag_id - 1) >> shift) & 0x1);
-	set_tag->data |= flow_id_val << (mtr_reg_bits - flow_id_bits);
+	if (tag_id) {
+		int shift;
+		uint32_t flow_id_val = 0;
+
+		/*
+		 * The color Reg bits used by flow_id are growing from
+		 * msb to lsb, so must do bit reverse for flow_id val in RegC.
+		 */
+		for (shift = 0; shift < flow_id_bits; shift++)
+			flow_id_val = (flow_id_val << 1) |
+					(((tag_id - 1) >> shift) & 0x1);
+		set_tag->data |= flow_id_val << (mtr_reg_bits - flow_id_bits);
+	}
 	tag_item_spec->id = set_tag->id;
 	tag_item_spec->data = set_tag->data << mtr_id_offset;
 	tag_item_mask->data = UINT32_MAX << mtr_id_offset;
@@ -4573,7 +4809,10 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	tag_item->spec = tag_item_spec;
 	tag_item->last = NULL;
 	tag_item->mask = tag_item_mask;
-	return tag_id;
+exit:
+	if (mtr_flow_id)
+		*mtr_flow_id = tag_id;
+	return 0;
 }
 
 /**
@@ -5237,6 +5476,57 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/**
+ * Create the Termination Policy Meter drop 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] flow_split_info
+ *   Pointer to flow split info structure.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   0 on success, negative value otherwise
+ */
+static uint32_t
+flow_meter_create_drop_flow_with_org_pattern(struct rte_eth_dev *dev,
+			struct rte_flow *flow,
+			const struct rte_flow_attr *attr,
+			const struct rte_flow_item items[],
+			struct mlx5_flow_split_info *flow_split_info,
+			struct mlx5_flow_meter_info *fm,
+			struct rte_flow_error *error)
+{
+	struct mlx5_flow *dev_flow = NULL;
+	struct rte_flow_attr drop_attr = *attr;
+	struct rte_flow_action drop_actions[3] = {{0}};
+	struct mlx5_flow_split_info drop_split_info = *flow_split_info;
+
+	MLX5_ASSERT(fm->drop_cnt);
+	drop_actions[0].type =
+		MLX5_RTE_FLOW_ACTION_TYPE_MTR_COUNT;
+	drop_actions[0].conf =
+		(void *)(uintptr_t)fm->drop_cnt;
+	drop_actions[1].type =
+		RTE_FLOW_ACTION_TYPE_DROP;
+	drop_actions[2].type =
+		RTE_FLOW_ACTION_TYPE_END;
+	drop_split_info.external = false;
+	drop_split_info.skip_scale |= 1 << MLX5_SCALE_FLOW_GROUP_BIT;
+	drop_attr.group = MLX5_FLOW_TABLE_LEVEL_METER_DROP;
+	return flow_create_split_inner(dev, flow, &dev_flow,
+				&drop_attr, items, drop_actions,
+				&drop_split_info, error);
+}
+
 /**
  * The splitting for meter feature.
  *
@@ -5281,10 +5571,13 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 	struct mlx5_flow *dev_flow = NULL;
 	struct rte_flow_attr sfx_attr = *attr;
 	struct mlx5_flow_meter_info *fm = NULL;
+	uint8_t skip_scale_restore;
 	bool has_mtr = false;
-	uint32_t meter_id;
+	bool has_modify = false;
+	bool set_mtr_reg = true;
+	uint32_t meter_id = 0;
 	uint32_t mtr_idx = 0;
-	uint32_t mtr_tag_id = 0;
+	uint32_t mtr_flow_id = 0;
 	size_t act_size;
 	size_t item_size;
 	int actions_n = 0;
@@ -5292,7 +5585,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 
 	if (priv->mtr_en)
 		actions_n = flow_check_meter_action(actions, &has_mtr,
-						    &meter_id);
+						    &has_modify, &meter_id);
 	if (has_mtr) {
 		if (flow->meter) {
 			fm = flow_dv_meter_find_by_idx(priv, flow->meter);
@@ -5312,7 +5605,18 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 				return -rte_errno;
 			flow->meter = mtr_idx;
 		}
+		MLX5_ASSERT(wks);
 		wks->fm = fm;
+		/*
+		 * If it's Termination Policy Meter, and
+		 * 1. There's no action in flow to change
+		 *    packet (modify/encap/decap etc.), OR
+		 * 2. No drop count needed for this meter.
+		 * no need to use regC to save meter id anymore.
+		 */
+		if (fm->policy_id != RTE_MTR_DEFAULT_POLICY_ID &&
+		    (!has_modify || !fm->drop_cnt))
+			set_mtr_reg = false;
 		/* Prefix actions: meter, decap, encap, tag, jump, end. */
 		act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
 			   sizeof(struct mlx5_rte_flow_action_set_tag);
@@ -5329,27 +5633,48 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 						  "meter flow");
 		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
 			     act_size);
-		pre_actions = sfx_actions + actions_n;
-		mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
-						   items, sfx_items, actions,
-						   sfx_actions, pre_actions,
-						   error);
-		if (!mtr_tag_id) {
+		/* There's no suffix flow for Termination Policy Meter. */
+		if (fm->policy_id != RTE_MTR_DEFAULT_POLICY_ID)
+			pre_actions = sfx_actions + 1;
+		else
+			pre_actions = sfx_actions + actions_n;
+		ret = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+					    items, sfx_items, actions,
+					    sfx_actions, pre_actions,
+					    (set_mtr_reg ? &mtr_flow_id : NULL),
+					    error);
+		if (ret) {
 			ret = -rte_errno;
 			goto exit;
 		}
 		/* Add the prefix subflow. */
 		flow_split_info->prefix_mark = 0;
+		skip_scale_restore = flow_split_info->skip_scale;
+		flow_split_info->skip_scale |=
+			1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT;
 		ret = flow_create_split_inner(dev, flow, &dev_flow,
 					      attr, items, pre_actions,
 					      flow_split_info, error);
 		if (ret) {
-			mlx5_ipool_free(fm->flow_ipool, mtr_tag_id);
+			if (mtr_flow_id)
+				mlx5_ipool_free(fm->flow_ipool, mtr_flow_id);
 			ret = -rte_errno;
 			goto exit;
 		}
-		dev_flow->handle->split_flow_id = mtr_tag_id;
-		dev_flow->handle->is_meter_flow_id = 1;
+		flow_split_info->skip_scale = skip_scale_restore;
+		if (mtr_flow_id) {
+			dev_flow->handle->split_flow_id = mtr_flow_id;
+			dev_flow->handle->is_meter_flow_id = 1;
+		}
+		if (fm->policy_id != RTE_MTR_DEFAULT_POLICY_ID) {
+			if (!set_mtr_reg && fm->drop_cnt)
+				ret =
+			flow_meter_create_drop_flow_with_org_pattern(dev, flow,
+							&sfx_attr, items,
+							flow_split_info,
+							fm, error);
+			goto exit;
+		}
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
 				(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
@@ -5743,7 +6068,7 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,
 	memset(rss_desc, 0, offsetof(struct mlx5_flow_rss_desc, queue));
 	/* RSS Action only works on NIC RX domain */
 	if (attr->ingress && !attr->transfer)
-		rss = flow_get_rss_action(p_actions_rx);
+		rss = flow_get_rss_action(dev, p_actions_rx);
 	if (rss) {
 		if (flow_rss_workspace_adjust(wks, rss_desc, rss->queue_num))
 			return 0;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index fc9622b498..20bb8b584f 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -37,6 +37,8 @@ enum mlx5_rte_flow_action_type {
 	MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS,
 	MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET,
 	MLX5_RTE_FLOW_ACTION_TYPE_AGE,
+	MLX5_RTE_FLOW_ACTION_TYPE_MTR_JUMP,
+	MLX5_RTE_FLOW_ACTION_TYPE_MTR_COUNT,
 };
 
 #define MLX5_SHARED_ACTION_TYPE_OFFSET 30
@@ -70,6 +72,11 @@ struct mlx5_rte_flow_item_tx_queue {
 	uint32_t queue;
 };
 
+struct mlx5_rte_flow_item_mtr_jump {
+	struct rte_flow_action_jump table_group;
+	uint32_t table_id;
+};
+
 /* Feature name to allocate metadata register. */
 enum mlx5_feature_name {
 	MLX5_HAIRPIN_RX,
@@ -1029,6 +1036,8 @@ struct mlx5_flow_workspace {
 	uint32_t rssq_num; /* Allocated queue num in rss_desc. */
 	uint32_t flow_idx; /* Intermediate device flow index. */
 	struct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */
+	uint32_t skip_matcher_reg:1;
+	/* Indicates if need to skip matcher register in translate. */
 };
 
 struct mlx5_flow_split_info {
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index d93097b755..b7b2c5a3d2 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7409,6 +7409,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,
 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
 
 	MLX5_ASSERT(wks);
+	wks->skip_matcher_reg = 0;
 	/* In case of corrupting the memory. */
 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
 		rte_flow_error_set(error, ENOSPC,
@@ -11252,6 +11253,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
 		int action_type = actions->type;
 		const struct rte_flow_action *found_action = NULL;
 		uint32_t jump_group = 0;
+		uint32_t jump_table_id = 0;
+		struct mlx5_flow_counter *cnt;
 
 		if (!mlx5_flow_os_action_supported(action_type))
 			return rte_flow_error_set(error, ENOTSUP,
@@ -11432,6 +11435,15 @@ flow_dv_translate(struct rte_eth_dev *dev,
 				age = action->conf;
 			action_flags |= MLX5_FLOW_ACTION_COUNT;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_MTR_COUNT:
+			cnt = flow_dv_counter_get_by_idx(dev,
+				(uint32_t)(uintptr_t)action->conf, NULL);
+			if (!cnt)
+				return rte_flow_error_set(error, rte_errno,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Failed to get meter counter.");
+			dev_flow->dv.actions[actions_n++] = cnt->action;
+			break;
 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
 			dev_flow->dv.actions[actions_n++] =
 						priv->sh->pop_vlan_action;
@@ -11536,6 +11548,11 @@ flow_dv_translate(struct rte_eth_dev *dev,
 			/* If decap is followed by encap, handle it at encap. */
 			action_flags |= MLX5_FLOW_ACTION_DECAP;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_MTR_JUMP:
+			jump_table_id =
+				((const struct mlx5_rte_flow_item_mtr_jump *)
+				 action->conf)->table_id;
+			/* Fall through */
 		case RTE_FLOW_ACTION_TYPE_JUMP:
 			jump_group = ((const struct rte_flow_action_jump *)
 							action->conf)->group;
@@ -11555,7 +11572,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
 						       attr->transfer,
 						       !!dev_flow->external,
 						       tunnel, jump_group, 0,
-						       0, error);
+						       jump_table_id, error);
 			if (!tbl)
 				return rte_flow_error_set
 						(error, errno,
@@ -12091,6 +12108,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
 	}
 	dev_flow->dv.actions_n = actions_n;
 	dev_flow->act_flags = action_flags;
+	if (wks->skip_matcher_reg)
+		return 0;
 	/* Register matcher. */
 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
 				    matcher.mask.size);
@@ -12242,7 +12261,8 @@ flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
 		dv_h = &dh->dvh;
 		n = dv->actions_n;
 		if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
-			if (dv->transfer) {
+			if (dv->transfer || dev_flow->dv.group ==
+			    MLX5_FLOW_TABLE_LEVEL_METER_DROP) {
 				dv->actions[n++] = priv->sh->esw_drop_action;
 			} else {
 				MLX5_ASSERT(priv->drop_queue.hrxq);
-- 
2.27.0


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

* [dpdk-dev] [PATCH v2 0/4] net/mlx5: support meter policy operations
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (3 preceding siblings ...)
  2021-04-01  8:16 ` [dpdk-dev] [PATCH 4/4] net/mlx5: connect meter policy to created flows Li Zhang
@ 2021-04-02 15:56 ` Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 1/4] " Li Zhang
                     ` (3 more replies)
  2021-04-13  0:19 ` [dpdk-dev] [PATCH v3 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (5 subsequent siblings)
  10 siblings, 4 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-02 15:56 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Depends-on: series=16087  ("Add ASO meter support in MLX5 PMD ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16087

Depends-on: series=16082  ("Support meter policy API ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16082

V2: Add MLX5_MTR_DEFAULT_POLICY_ID in MLX5 PMD

Li Zhang (3):
  net/mlx5: support meter policy operations
  net/mlx5: support meter creation with policy
  net/mlx5: prepare sub-policy for a flow with meter

Shun Hao (1):
  net/mlx5: connect meter policy to created flows

 drivers/net/mlx5/linux/mlx5_os.c   |   13 +-
 drivers/net/mlx5/mlx5.c            |   76 +-
 drivers/net/mlx5/mlx5.h            |  204 ++-
 drivers/net/mlx5/mlx5_flow.c       |  629 +++++++++-
 drivers/net/mlx5/mlx5_flow.h       |  123 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1862 ++++++++++++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_meter.c |  745 ++++++++++-
 8 files changed, 3328 insertions(+), 334 deletions(-)

-- 
2.27.0


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

* [dpdk-dev] [PATCH v2 1/4] net/mlx5: support meter policy operations
  2021-04-02 15:56 ` [dpdk-dev] [PATCH v2 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-02 15:56   ` Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 2/4] net/mlx5: support meter creation with policy Li Zhang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-02 15:56 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Signed-off-by: Li Zhang <lizh@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |    2 +-
 drivers/net/mlx5/mlx5.c            |   76 +-
 drivers/net/mlx5/mlx5.h            |  152 ++-
 drivers/net/mlx5/mlx5_flow.c       |  184 +++-
 drivers/net/mlx5/mlx5_flow.h       |   71 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1394 +++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c |  456 ++++++++-
 8 files changed, 2227 insertions(+), 118 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 772feff598..859b9098dc 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1246,7 +1246,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			log_obj_size <=
 			config->hca_attr.qos.log_meter_aso_max_alloc) {
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv);
+				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
 				if (err) {
 					err = -err;
 					goto error;
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 8841ef0e99..94209e50a0 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -350,6 +350,20 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {
 		.free = mlx5_free,
 		.type = "mlx5_shared_action_rss",
 	},
+	[MLX5_IPOOL_MTR_POLICY] = {
+		/**
+		 * The ipool index should grow continually from small to big,
+		 * for policy idx, so not set grow_trunk to avoid policy index
+		 * not jump continually.
+		 */
+		.size = sizeof(struct mlx5_flow_meter_sub_policy),
+		.trunk_size = 64,
+		.need_lock = 1,
+		.release_mem_en = 1,
+		.malloc = mlx5_malloc,
+		.free = mlx5_free,
+		.type = "mlx5_meter_policy_ipool",
+	},
 };
 
 
@@ -549,27 +563,24 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh)
  *   Pointer to mlx5_dev_ctx_shared object to free
  */
 int
-mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv)
+mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!priv->mtr_idx_tbl) {
-		priv->mtr_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
-		if (!priv->mtr_idx_tbl) {
-			DRV_LOG(ERR, "fail to create meter lookup table.");
-			rte_errno = ENOMEM;
-			return -ENOMEM;
-		}
-	}
-	if (!priv->sh->mtrmng) {
-		priv->sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
-			sizeof(*priv->sh->mtrmng),
+	if (!sh->mtrmng) {
+		sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(*sh->mtrmng),
 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
-		if (!priv->sh->mtrmng) {
-			DRV_LOG(ERR, "mlx5_aso_mtr_pools_mng allocation was failed.");
+		if (!sh->mtrmng) {
+			DRV_LOG(ERR,
+			"mlx5_aso_mtr_pools_mng allocation was failed.");
 			rte_errno = ENOMEM;
 			return -ENOMEM;
 		}
-		rte_spinlock_init(&priv->sh->mtrmng->mtrsl);
-		LIST_INIT(&priv->sh->mtrmng->meters);
+		if (sh->meter_aso_en) {
+			rte_spinlock_init(&sh->mtrmng->pools_mng.mtrsl);
+			LIST_INIT(&sh->mtrmng->pools_mng.meters);
+			sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		}
 	}
 	return 0;
 }
@@ -586,28 +597,31 @@ mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
 {
 	struct mlx5_aso_mtr_pool *mtr_pool;
 	struct mlx5_aso_mtr *aso_mtr;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng;
+	struct mlx5_flow_mtr_mng *mtrmng = sh->mtrmng;
 	uint32_t idx;
 	int i;
 
-	mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
-	idx = mtrmng->n_valid;
-	while (idx--) {
-		mtr_pool = mtrmng->pools[idx];
+	if (sh->meter_aso_en) {
+		mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
+		idx = mtrmng->pools_mng.n_valid;
+		while (idx--) {
+			mtr_pool = mtrmng->pools_mng.pools[idx];
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
-		for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
-			aso_mtr = &mtr_pool->mtrs[i];
-			if (aso_mtr->fm.meter_action)
-				claim_zero(mlx5_glue->destroy_flow_action
-						(aso_mtr->fm.meter_action));
-		}
+			for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
+				aso_mtr = &mtr_pool->mtrs[i];
+				if (aso_mtr->fm.meter_action)
+					claim_zero
+					(mlx5_glue->destroy_flow_action
+					(aso_mtr->fm.meter_action));
+			}
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
-		claim_zero(mlx5_devx_cmd_destroy
+			claim_zero(mlx5_devx_cmd_destroy
 						(mtr_pool->devx_obj));
-		mtrmng->n_valid--;
-		mlx5_free(mtr_pool);
+			mtrmng->pools_mng.n_valid--;
+			mlx5_free(mtr_pool);
+		}
+		mlx5_free(sh->mtrmng->pools_mng.pools);
 	}
-	mlx5_free(sh->mtrmng->pools);
 	mlx5_free(sh->mtrmng);
 	sh->mtrmng = NULL;
 }
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index b182fb6c19..f02360dccf 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -56,6 +56,7 @@ enum mlx5_ipool_index {
 	MLX5_IPOOL_RTE_FLOW, /* Pool for rte_flow. */
 	MLX5_IPOOL_RSS_EXPANTION_FLOW_ID, /* Pool for Queue/RSS flow ID. */
 	MLX5_IPOOL_RSS_SHARED_ACTIONS, /* Pool for RSS shared actions. */
+	MLX5_IPOOL_MTR_POLICY, /* Pool for meter policy resource. */
 	MLX5_IPOOL_MAX,
 };
 
@@ -589,9 +590,122 @@ struct mlx5_dev_shared_port {
 	/* Aging information for per port. */
 };
 
+/*
+ * Max number of actions per DV flow.
+ * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
+ * in rdma-core file providers/mlx5/verbs.c.
+ */
+#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
+
 /*ASO flow meter structures*/
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
+/* Yellow is not supported. */
+#define MLX5_MTR_RTE_COLORS (RTE_COLOR_GREEN + 1)
+/* table_id 22 bits in mlx5_flow_tbl_key so limit policy number. */
+#define MLX5_MAX_SUB_POLICY_TBL_NUM 0x3FFFFF
+
+enum mlx5_meter_domain {
+	MLX5_MTR_DOMAIN_INGRESS,
+	MLX5_MTR_DOMAIN_EGRESS,
+	MLX5_MTR_DOMAIN_TRANSFER,
+	MLX5_MTR_DOMAIN_MAX,
+};
+#define MLX5_MTR_DOMAIN_INGRESS_BIT  (1 << MLX5_MTR_DOMAIN_INGRESS)
+#define MLX5_MTR_DOMAIN_EGRESS_BIT   (1 << MLX5_MTR_DOMAIN_EGRESS)
+#define MLX5_MTR_DOMAIN_TRANSFER_BIT (1 << MLX5_MTR_DOMAIN_TRANSFER)
+#define MLX5_MTR_ALL_DOMAIN_BIT      (0x7)
+
+/* Meter sub-policy structure.
+ * Each RSS TIR in meter policy need its own sub-policy resource.
+ */
+struct mlx5_flow_meter_sub_policy {
+	uint32_t main_policy_id:1;
+	/* Main policy id is same as this sub_policy id. */
+	uint32_t idx:31;
+	/* Index to sub_policy ipool entity. */
+	void *main_policy;
+	/* Point to struct mlx5_flow_meter_policy. */
+	struct mlx5_flow_tbl_resource *tbl_rsc;
+	/* The sub-policy table resource. */
+	uint32_t rix_hrxq[MLX5_MTR_RTE_COLORS];
+	/* Index to TIR resource. */
+	struct mlx5_flow_tbl_resource *jump_tbl[MLX5_MTR_RTE_COLORS];
+	/* Meter jump/drop table. */
+	struct mlx5_flow_dv_matcher *color_matcher[RTE_COLORS];
+	/* Matcher for Color. */
+	void *color_rule[RTE_COLORS];
+	/* Meter green/yellow/drop rule. */
+};
+
+struct mlx5_meter_policy_acts {
+	uint8_t actions_n;
+	/* Number of actions. */
+	void *dv_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS];
+	/* Action list. */
+};
+
+struct mlx5_meter_policy_action_container {
+	uint32_t rix_mark;
+	/* Index to the mark action. */
+	struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
+	/* Pointer to modify header resource in cache. */
+	uint8_t fate_action;
+	/* Fate action type. */
+	union {
+		struct rte_flow_action *rss;
+		/* Rss action configuration. */
+		uint32_t rix_port_id_action;
+		/* Index to port ID action resource. */
+		void *dr_jump_action[MLX5_MTR_DOMAIN_MAX];
+		/* Jump/drop action per color. */
+	};
+};
+
+/* Flow meter policy parameter structure. */
+struct mlx5_flow_meter_policy {
+	uint32_t is_rss:1;
+	/* Is RSS policy table. */
+	uint32_t ingress:1;
+	/* Rule applies to ingress domain. */
+	uint32_t egress:1;
+	/* Rule applies to egress domain. */
+	uint32_t transfer:1;
+	/* Rule applies to transfer domain. */
+	rte_spinlock_t sl;
+	uint32_t ref_cnt;
+	/* Use count. */
+	struct mlx5_meter_policy_action_container act_cnt[MLX5_MTR_RTE_COLORS];
+	/* Policy actions container. */
+	void *dr_drop_action[MLX5_MTR_DOMAIN_MAX];
+	/* drop action for red color. */
+	uint16_t sub_policy_num;
+	/* Count sub policy tables, 3 bits per domain. */
+	struct mlx5_flow_meter_sub_policy **sub_policys[MLX5_MTR_DOMAIN_MAX];
+	/* Sub policy table array must be the end of struct. */
+};
+
+/* The maximum sub policy is relate to struct mlx5_rss_hash_fields[]. */
+#define MLX5_MTR_RSS_MAX_SUB_POLICY 7
+#define MLX5_MTR_SUB_POLICY_NUM_SHIFT  3
+#define MLX5_MTR_SUB_POLICY_NUM_MARK  0x7
+
+/* Flow meter default policy parameter structure.
+ * Policy id 0 is reserved by default policy table.
+ */
+struct mlx5_flow_meter_def_policy {
+	struct mlx5_flow_meter_sub_policy sub_policy;
+	/* Policy rules jump to other tables. */
+	void *dr_jump_action[RTE_COLORS];
+	/* Jump action per color. */
+};
+
+/**
+ * Policy id 0 is default policy.
+ * Action per color as below:
+ * green - do nothing, yellow - do nothing, red - drop
+ */
+#define MLX5_MTR_DEFAULT_POLICY_ID 0
 
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
@@ -755,6 +869,29 @@ struct mlx5_aso_mtr_pools_mng {
 	struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */
 };
 
+/* Meter management structure for global flow meter resource. */
+struct mlx5_flow_mtr_mng {
+	struct mlx5_aso_mtr_pools_mng pools_mng;
+	/* Pools management structure for ASO flow meter pools. */
+	struct mlx5_flow_meter_def_policy *def_policy[MLX5_MTR_DOMAIN_MAX];
+	/* Default policy table. */
+	uint32_t def_policy_ref_cnt;
+	/** def_policy create/delete count. */
+	uint32_t def_policy_mtr_ref_cnt;
+	/** def_policy meter use count. */
+	struct mlx5_l3t_tbl *policy_idx_tbl;
+	/* Policy index lookup table. */
+	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop table. */
+	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Matcher meter in drop table. */
+	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* default matcher in drop table. */
+	void *def_rule[MLX5_MTR_DOMAIN_MAX];
+	/* default rule in drop table. */
+};
+#define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
+
 /* Table key of the hash organization. */
 union mlx5_flow_tbl_key {
 	struct {
@@ -782,8 +919,9 @@ struct mlx5_flow_tbl_resource {
 #define MLX5_FLOW_MREG_CP_TABLE_GROUP (MLX5_MAX_TABLES - 2)
 /* Tables for metering splits should be added here. */
 #define MLX5_FLOW_TABLE_LEVEL_SUFFIX (MLX5_MAX_TABLES - 3)
-#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 4)
-#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_METER
+#define MLX5_FLOW_TABLE_LEVEL_METER_DROP (MLX5_MAX_TABLES - 4)
+#define MLX5_FLOW_TABLE_LEVEL_POLICY (MLX5_MAX_TABLES - 5)
+#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_POLICY
 #define MLX5_MAX_TABLES_FDB UINT16_MAX
 #define MLX5_FLOW_TABLE_FACTOR 10
 
@@ -929,8 +1067,8 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_geneve_tlv_option_resource *geneve_tlv_option_resource;
 	/* Management structure for geneve tlv option */
 	rte_spinlock_t geneve_tlv_opt_sl; /* Lock for geneve tlv resource */
-	struct mlx5_aso_mtr_pools_mng *mtrmng;
-	/* Meter pools management structure. */
+	struct mlx5_flow_mtr_mng *mtrmng;
+	/* Meter management structure. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
 
@@ -1232,7 +1370,7 @@ int mlx5_hairpin_cap_get(struct rte_eth_dev *dev,
 bool mlx5_flex_parser_ecpri_exist(struct rte_eth_dev *dev);
 int mlx5_flex_parser_ecpri_alloc(struct rte_eth_dev *dev);
 int mlx5_flow_aso_age_mng_init(struct mlx5_dev_ctx_shared *sh);
-int mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv);
+int mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh);
 
 /* mlx5_ethdev.c */
 
@@ -1448,6 +1586,10 @@ int mlx5_flow_meter_attach(struct mlx5_priv *priv,
 			   struct rte_flow_error *error);
 void mlx5_flow_meter_detach(struct mlx5_priv *priv,
 			    struct mlx5_flow_meter_info *fm);
+struct mlx5_flow_meter_policy *mlx5_flow_meter_policy_find
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		uint32_t *policy_idx);
 
 /* mlx5_os.c */
 struct rte_pci_driver;
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 2d0daf631a..15ae8b9528 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1044,7 +1044,7 @@ flow_rxq_tunnel_ptype_update(struct mlx5_rxq_ctrl *rxq_ctrl)
  * @param[in] dev_handle
  *   Pointer to device flow handle structure.
  */
-static void
+void
 flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
 		       struct mlx5_flow_handle *dev_handle)
 {
@@ -4490,8 +4490,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		actions_pre++;
 		jump_data = (struct rte_flow_action_jump *)actions_pre;
 		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_METER;
+				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_POLICY;
 		hw_mtr_action->conf = jump_data;
 		actions_pre = (struct rte_flow_action *)(jump_data + 1);
 	} else {
@@ -6615,6 +6615,169 @@ mlx5_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
 	return 0;
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] is_rss
+ *   Is RSS or not.
+ * @param[out] domain_bitmap
+ *   Domain bitmap.
+ * @param[out] is_def_policy
+ *   Is default policy or not.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->validate_mtr_acts(dev, actions, attr,
+			is_rss, domain_bitmap, is_def_policy, error);
+}
+
+/**
+ * Destroy the meter table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_acts(dev, mtr_policy);
+}
+
+/**
+ * Create policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_mtr_acts(dev, mtr_policy, actions, error);
+}
+
+/**
+ * Create policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_def_policy(dev);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_def_policy(dev);
+}
+
 /**
  * Create the needed meter and suffix tables.
  *
@@ -6654,6 +6817,21 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
+/**
+ * Destroy the global meter drop table.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_drop_tbls(dev);
+}
+
 /**
  * Allocate the needed aso flow meter id.
  *
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 8e4530f32c..97e766a6b1 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -691,13 +691,6 @@ struct mlx5_flow_handle {
 #define MLX5_FLOW_HANDLE_VERBS_SIZE (sizeof(struct mlx5_flow_handle))
 #endif
 
-/*
- * Max number of actions per DV flow.
- * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
- * in rdma-core file providers/mlx5/verbs.c.
- */
-#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
-
 /** Device flow structure only for DV flow creation. */
 struct mlx5_flow_dv_workspace {
 	uint32_t group; /**< The group index. */
@@ -1079,6 +1072,7 @@ 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);
+typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1124,6 +1118,32 @@ typedef int (*mlx5_flow_sync_domain_t)
 			(struct rte_eth_dev *dev,
 			 uint32_t domains,
 			 uint32_t flags);
+typedef int (*mlx5_flow_validate_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+			 const struct rte_flow_action *actions[RTE_COLORS],
+			 struct rte_flow_attr *attr,
+			 bool *is_rss,
+			 uint8_t *domain_bitmap,
+			 bool *is_def_policy,
+			 struct rte_mtr_error *error);
+typedef int (*mlx5_flow_create_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+typedef void (*mlx5_flow_destroy_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef void (*mlx5_flow_destroy_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_def_policy_t)
+			(struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_destroy_def_policy_t)
+			(struct rte_eth_dev *dev);
 
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
@@ -1135,8 +1155,16 @@ 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_destroy_mtr_drop_tbls_t destroy_mtr_drop_tbls;
 	mlx5_flow_mtr_alloc_t create_meter;
 	mlx5_flow_mtr_free_t free_meter;
+	mlx5_flow_validate_mtr_acts_t validate_mtr_acts;
+	mlx5_flow_create_mtr_acts_t create_mtr_acts;
+	mlx5_flow_destroy_mtr_acts_t destroy_mtr_acts;
+	mlx5_flow_create_policy_rules_t create_policy_rules;
+	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
+	mlx5_flow_create_def_policy_t create_def_policy;
+	mlx5_flow_destroy_def_policy_t destroy_def_policy;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1213,12 +1241,13 @@ static inline struct mlx5_aso_mtr *
 mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)
 {
 	struct mlx5_aso_mtr_pool *pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 
 	/* Decrease to original index. */
 	idx--;
-	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < mtrmng->n);
-	pool = mtrmng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
+	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n);
+	pool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
 	return &pool->mtrs[idx % MLX5_ASO_MTRS_PER_POOL];
 }
 
@@ -1364,6 +1393,7 @@ 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);
+void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
 			  struct rte_mtr_error *error);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
@@ -1466,4 +1496,25 @@ int mlx5_flow_os_set_specific_workspace(struct mlx5_flow_workspace *data);
 void mlx5_flow_os_release_workspace(void);
 uint32_t mlx5_flow_mtr_alloc(struct rte_eth_dev *dev);
 void mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx);
+int mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+int mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+void mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_def_policy(struct rte_eth_dev *dev);
+void mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev);
+void flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
+		       struct mlx5_flow_handle *dev_handle);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c
index 9ba823f774..93fe08779e 100644
--- a/drivers/net/mlx5/mlx5_flow_aso.c
+++ b/drivers/net/mlx5/mlx5_flow_aso.c
@@ -312,11 +312,11 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh,
 		mlx5_aso_age_init_sq(&sh->aso_age_mng->aso_sq);
 		break;
 	case ASO_OPC_MOD_POLICER:
-		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->sq, 0,
+		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->pools_mng.sq, 0,
 				  sh->tx_uar, sh->pdn, MLX5_ASO_QUEUE_LOG_DESC,
 				  sh->sq_ts_format))
 			return -1;
-		mlx5_aso_mtr_init_sq(&sh->mtrmng->sq);
+		mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq);
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -343,7 +343,7 @@ mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh,
 		sq = &sh->aso_age_mng->aso_sq;
 		break;
 	case ASO_OPC_MOD_POLICER:
-		sq = &sh->mtrmng->sq;
+		sq = &sh->mtrmng->pools_mng.sq;
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -799,7 +799,7 @@ int
 mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	do {
@@ -831,7 +831,7 @@ int
 mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) ==
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index ec6097b395..412e730aaf 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -21,6 +21,8 @@
 #include <rte_gtp.h>
 #include <rte_eal_paging.h>
 #include <rte_mpls.h>
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -184,6 +186,31 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
 	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. */
@@ -4692,10 +4719,6 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev,
 					  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,
@@ -5914,9 +5937,10 @@ static int
 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
-	void *old_pools = mtrmng->pools;
-	uint32_t resize = mtrmng->n + MLX5_MTRS_CONTAINER_RESIZE;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
+	void *old_pools = pools_mng->pools;
+	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
 
@@ -5924,16 +5948,16 @@ flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 		rte_errno = ENOMEM;
 		return -ENOMEM;
 	}
-	if (!mtrmng->n)
+	if (!pools_mng->n)
 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
 			mlx5_free(pools);
 			return -ENOMEM;
 		}
 	if (old_pools)
-		memcpy(pools, old_pools, mtrmng->n *
+		memcpy(pools, old_pools, pools_mng->n *
 				       sizeof(struct mlx5_aso_mtr_pool *));
-	mtrmng->n = resize;
-	mtrmng->pools = pools;
+	pools_mng->n = resize;
+	pools_mng->pools = pools;
 	if (old_pools)
 		mlx5_free(old_pools);
 	return 0;
@@ -5956,7 +5980,8 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 			     struct mlx5_aso_mtr **mtr_free)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool = NULL;
 	struct mlx5_devx_obj *dcs = NULL;
 	uint32_t i;
@@ -5976,17 +6001,17 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 		return NULL;
 	}
 	pool->devx_obj = dcs;
-	pool->index = mtrmng->n_valid;
-	if (pool->index == mtrmng->n && flow_dv_mtr_container_resize(dev)) {
+	pool->index = pools_mng->n_valid;
+	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
 		mlx5_free(pool);
 		claim_zero(mlx5_devx_cmd_destroy(dcs));
 		return NULL;
 	}
-	mtrmng->pools[pool->index] = pool;
-	mtrmng->n_valid++;
+	pools_mng->pools[pool->index] = pool;
+	pools_mng->n_valid++;
 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
 		pool->mtrs[i].offset = i;
-		LIST_INSERT_HEAD(&mtrmng->meters,
+		LIST_INSERT_HEAD(&pools_mng->meters,
 						&pool->mtrs[i], next);
 	}
 	pool->mtrs[0].offset = 0;
@@ -6006,14 +6031,15 @@ static void
 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
 
 	MLX5_ASSERT(aso_mtr);
-	rte_spinlock_lock(&mtrmng->mtrsl);
+	rte_spinlock_lock(&pools_mng->mtrsl);
 	aso_mtr->state = ASO_METER_FREE;
-	LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 }
 
 /**
@@ -6030,7 +6056,8 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_aso_mtr *mtr_free = NULL;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool;
 	struct rte_flow_error error;
 	uint8_t reg_id;
@@ -6042,16 +6069,16 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 	}
 	/* Allocate the flow meter memory. */
 	/* Get free meters from management. */
-	rte_spinlock_lock(&mtrmng->mtrsl);
-	mtr_free = LIST_FIRST(&mtrmng->meters);
+	rte_spinlock_lock(&pools_mng->mtrsl);
+	mtr_free = LIST_FIRST(&pools_mng->meters);
 	if (mtr_free)
 		LIST_REMOVE(mtr_free, next);
 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
 		return 0;
 	}
 	mtr_free->state = ASO_METER_WAIT;
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 	pool = container_of(mtr_free,
 			struct mlx5_aso_mtr_pool,
 			mtrs[mtr_free->offset]);
@@ -13253,6 +13280,555 @@ flow_dv_action_query(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Destroy the meter sub policy table rules.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *   Pointer to meter sub policy table.
+ */
+static void
+__flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_sub_policy *sub_policy)
+{
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (sub_policy->color_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(sub_policy->color_rule[i]));
+			sub_policy->color_rule[i] = NULL;
+		}
+		if (sub_policy->color_matcher[i]) {
+			tbl = container_of(sub_policy->color_matcher[i]->tbl,
+				typeof(*tbl), tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &sub_policy->color_matcher[i]->entry);
+			sub_policy->color_matcher[i] = NULL;
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (sub_policy->rix_hrxq[i]) {
+			mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+			sub_policy->rix_hrxq[i] = 0;
+		}
+		if (sub_policy->jump_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->jump_tbl[i]);
+			sub_policy->jump_tbl[i] = NULL;
+		}
+	}
+	if (sub_policy->tbl_rsc) {
+		flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->tbl_rsc);
+		sub_policy->tbl_rsc = NULL;
+	}
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	uint32_t i, j;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		for (j = 0; j < sub_policy_num; j++) {
+			sub_policy = mtr_policy->sub_policys[i][j];
+			if (sub_policy)
+				__flow_dv_destroy_sub_policy_rules
+						(dev, sub_policy);
+		}
+	}
+}
+
+/**
+ * Destroy policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	struct rte_flow_action *rss_action;
+	struct mlx5_flow_handle dev_handle;
+	uint32_t i, j;
+
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			flow_dv_tag_release(dev,
+				mtr_policy->act_cnt[i].rix_mark);
+			mtr_policy->act_cnt[i].rix_mark = 0;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			dev_handle.dvh.modify_hdr =
+				mtr_policy->act_cnt[i].modify_hdr;
+			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
+		}
+		switch (mtr_policy->act_cnt[i].fate_action) {
+		case MLX5_FLOW_FATE_SHARED_RSS:
+			rss_action = mtr_policy->act_cnt[i].rss;
+			mlx5_free(rss_action);
+			break;
+		case MLX5_FLOW_FATE_PORT_ID:
+			if (mtr_policy->act_cnt[i].rix_port_id_action) {
+				flow_dv_port_id_action_resource_release(dev,
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				mtr_policy->act_cnt[i].rix_port_id_action = 0;
+			}
+			break;
+		case MLX5_FLOW_FATE_DROP:
+		case MLX5_FLOW_FATE_JUMP:
+			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+				mtr_policy->act_cnt[i].dr_jump_action[j] =
+						NULL;
+			break;
+		default:
+			/*Queue action do nothing*/
+			break;
+		}
+	}
+	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+		mtr_policy->dr_drop_action[j] = NULL;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+__flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+			 enum mlx5_meter_domain domain,
+		      struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_error flow_err;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	struct mlx5_flow_handle dh;
+	struct mlx5_flow dev_flow;
+	struct mlx5_flow_dv_port_id_action_resource port_id_action;
+	int i, ret;
+	uint8_t egress, transfer;
+	struct mlx5_meter_policy_action_container *act_cnt = NULL;
+	union {
+		struct mlx5_flow_dv_modify_hdr_resource res;
+		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
+			    sizeof(struct mlx5_modification_cmd) *
+			    (MLX5_MAX_MODIFY_NUM + 1)];
+	} mhdr_dummy;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
+	memset(&port_id_action, 0,
+		sizeof(struct mlx5_flow_dv_port_id_action_resource));
+	dev_flow.handle = &dh;
+	dev_flow.dv.port_id_action = &port_id_action;
+	dev_flow.external = true;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i < MLX5_MTR_RTE_COLORS)
+			act_cnt = &mtr_policy->act_cnt[i];
+		for (act = actions[i];
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_MARK:
+			{
+				uint32_t tag_be = mlx5_flow_mark_set
+					(((const struct rte_flow_action_mark *)
+					(act->conf))->id);
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "mark action for this color");
+				dev_flow.handle->mark = 1;
+				if (flow_dv_tag_resource_register(dev, tag_be,
+						  &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot setup policy mark action");
+				MLX5_ASSERT(dev_flow.dv.tag_resource);
+				act_cnt->rix_mark =
+					dev_flow.handle->dvh.rix_tag;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+			mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+			{
+				struct mlx5_flow_dv_modify_hdr_resource
+					*mhdr_res = &mhdr_dummy.res;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "set tag action for this color");
+				memset(mhdr_res, 0, sizeof(*mhdr_res));
+				mhdr_res->ft_type = transfer ?
+					MLX5DV_FLOW_TABLE_TYPE_FDB :
+					egress ?
+					MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+					MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+				if (flow_dv_convert_action_set_tag
+				(dev, mhdr_res,
+				(const struct rte_flow_action_set_tag *)
+				act->conf,  &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot convert policy "
+					"set tag action");
+				if (!mhdr_res->actions_num)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot find policy "
+					"set tag action");
+				/* create modify action if needed. */
+				dev_flow.dv.group = 1;
+				if (flow_dv_modify_hdr_resource_register
+					(dev, mhdr_res, &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot register policy "
+					"set tag action");
+				act_cnt->modify_hdr =
+				dev_flow.handle->dvh.modify_hdr;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+				mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_DROP:
+			{
+				struct mlx5_flow_mtr_mng *mtrmng =
+						priv->sh->mtrmng;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+
+				/*
+				 * Create the drop table with
+				 * METER DROP level.
+				 */
+				if (!mtrmng->drop_tbl[domain]) {
+					mtrmng->drop_tbl[domain] =
+					flow_dv_tbl_resource_get(dev,
+					MLX5_FLOW_TABLE_LEVEL_METER_DROP,
+					egress, transfer, false, NULL, 0,
+					0, 0, &flow_err);
+					if (!mtrmng->drop_tbl[domain])
+						return -rte_mtr_error_set
+					(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Failed to create meter drop table");
+				}
+				tbl_data = container_of
+				(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				if (i < MLX5_MTR_RTE_COLORS) {
+					act_cnt->dr_jump_action[domain] =
+						tbl_data->jump.action;
+					act_cnt->fate_action =
+						MLX5_FLOW_FATE_DROP;
+				}
+				if (i == RTE_COLOR_RED)
+					mtr_policy->dr_drop_action[domain] =
+						tbl_data->jump.action;
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+			{
+				struct mlx5_hrxq *hrxq;
+				uint32_t hrxq_idx;
+				struct mlx5_flow_rss_desc rss_desc;
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"fate queue for this color");
+				memset(&rss_desc, 0,
+					sizeof(struct mlx5_flow_rss_desc));
+				rss_desc.queue_num = 1;
+				rss_desc.const_q = act->conf;
+				hrxq = flow_dv_hrxq_prepare(dev, &dev_flow,
+						    &rss_desc, &hrxq_idx);
+				if (!hrxq)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot create policy fate queue");
+				sub_policy->rix_hrxq[i] = hrxq_idx;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				dev_flow.handle->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				if (action_flags & MLX5_FLOW_ACTION_MARK ||
+				    action_flags & MLX5_FLOW_ACTION_SET_TAG) {
+					dev_flow.handle->rix_hrxq = hrxq_idx;
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_RSS:
+			{
+				int rss_size;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "rss action for this color");
+				/*
+				 * Save RSS conf into policy struct
+				 * for translate stage.
+				 */
+				rss_size = (int)rte_flow_conv
+						(RTE_FLOW_CONV_OP_ACTION,
+						NULL, 0, act, &flow_err);
+				if (rss_size <= 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Get the wrong "
+					  "rss action struct size");
+				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
+						rss_size, 0, SOCKET_ID_ANY);
+				if (!act_cnt->rss)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "Fail to malloc rss action memory");
+				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
+					act_cnt->rss, rss_size,
+					act, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Fail to save "
+					  "rss action into policy struct");
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_SHARED_RSS;
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+			{
+				struct mlx5_flow_dv_port_id_action_resource
+					port_id_resource;
+				uint32_t port_id = 0;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"port action for this color");
+				memset(&port_id_resource, 0,
+					sizeof(port_id_resource));
+				if (flow_dv_translate_action_port_id(dev, act,
+						&port_id, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot translate "
+					"policy port action");
+				port_id_resource.port_id = port_id;
+				if (flow_dv_port_id_action_resource_register
+					(dev, &port_id_resource,
+					&dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy port action");
+				act_cnt->rix_port_id_action =
+					dev_flow.handle->rix_port_id_action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_PORT_ID;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+			{
+				uint32_t jump_group = 0;
+				uint32_t table = 0;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+				struct flow_grp_info grp_info = {
+					.external = !!dev_flow.external,
+					.transfer = !!transfer,
+					.fdb_def_rule = !!priv->fdb_def_rule,
+					.std_tbl_fix = 0,
+					.skip_scale = dev_flow.skip_scale &
+					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
+				};
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "jump action for this color");
+				jump_group =
+				((const struct rte_flow_action_jump *)
+							act->conf)->group;
+				if (mlx5_flow_group_to_table(dev, NULL,
+						       jump_group,
+						       &table,
+						       &grp_info, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy jump action");
+				sub_policy->jump_tbl[i] =
+				flow_dv_tbl_resource_get(dev,
+					table, egress,
+					transfer,
+					!!dev_flow.external,
+					NULL, jump_group, 0,
+					0, &flow_err);
+				if
+				(!sub_policy->jump_tbl[i])
+					return  -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create jump action.");
+				tbl_data = container_of
+				(sub_policy->jump_tbl[i],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				act_cnt->dr_jump_action[domain] =
+					tbl_data->jump.action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_JUMP;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			}
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "action type not supported");
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	int ret, i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		if (sub_policy_num) {
+			ret = __flow_dv_create_domain_policy_acts(dev,
+				mtr_policy, actions, i, error);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
 /**
  * Query a dv flow  rule for its statistics via devx.
  *
@@ -13433,9 +14009,477 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void
+flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (mtrmng->def_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+					(mtrmng->def_rule[i]));
+			mtrmng->def_rule[i] = NULL;
+		}
+		if (mtrmng->def_matcher[i]) {
+			tbl = container_of(mtrmng->def_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->def_matcher[i]->entry);
+			mtrmng->def_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_matcher[i]) {
+			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->drop_matcher[i]->entry);
+			mtrmng->drop_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+				mtrmng->drop_tbl[i]);
+			mtrmng->drop_tbl[i] = NULL;
+		}
+	}
+}
+
 /* Number of meter flow actions, count and jump or count and drop. */
 #define METER_ACTIONS 2
 
+static void
+__flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
+			      enum mlx5_meter_domain domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_def_policy *def_policy =
+			priv->sh->mtrmng->def_policy[domain];
+
+	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
+	mlx5_free(def_policy);
+	priv->sh->mtrmng->def_policy[domain] = NULL;
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+static void
+flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
+		if (priv->sh->mtrmng->def_policy[i])
+			__flow_dv_destroy_domain_def_policy(dev, i);
+}
+
+static int
+__flow_dv_create_policy_flow(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			enum rte_color color, void *matcher_object,
+			int actions_n, void *actions,
+			bool is_default_policy, void **rule,
+			const struct rte_flow_attr *attr)
+{
+	int ret;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to create meter policy flow with port.");
+			return -1;
+		}
+	}
+	flow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c_idx,
+				       rte_col_2_mlx5_col(color),
+				       UINT32_MAX);
+	ret = mlx5_flow_os_create_flow(matcher_object,
+			(void *)&value, actions_n, actions, rule);
+	if (ret) {
+		DRV_LOG(ERR, "Failed to create meter policy flow.");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			uint16_t priority,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			const struct rte_flow_attr *attr,
+			bool is_default_policy,
+			struct rte_flow_error *error)
+{
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+				MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+		.tbl = tbl_rsc,
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = error,
+		.data = &matcher,
+	};
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to register meter drop matcher with port.");
+			return -1;
+		}
+	}
+	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
+	if (priority < RTE_COLOR_RED)
+		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+					color_reg_c_idx, 0,
+					LS32_MASK(MLX5_MTR_COLOR_BITS));
+	matcher.priority = priority;
+	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
+					matcher.mask.size);
+	entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+	if (!entry) {
+		DRV_LOG(ERR, "Failed to register meter drop matcher.");
+		return -1;
+	}
+	sub_policy->color_matcher[priority] =
+		container_of(entry, struct mlx5_flow_dv_matcher, entry);
+	return 0;
+}
+
+/**
+ * Create the policy rules per domain.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *    Pointer to sub policy table..
+ * @param[in] egress
+ *   Direction of the table.
+ * @param[in] transfer
+ *   E-Switch or NIC flow.
+ * @param[in] acts
+ *   Pointer to policy action list per color.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+__flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_sub_policy *sub_policy,
+		uint8_t egress, uint8_t transfer, bool is_default_policy,
+		struct mlx5_meter_policy_acts acts[RTE_COLORS])
+{
+	struct rte_flow_error flow_err;
+	uint32_t color_reg_c_idx = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,
+						    0, &flow_err);
+	struct rte_flow_attr attr = {
+		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
+		.priority = 0,
+		.ingress = 0,
+		.egress = !!egress,
+		.transfer = !!transfer,
+		.reserved = 0,
+	};
+	int i;
+
+	/* Create policy table with POLICY level. */
+	if (!sub_policy->tbl_rsc)
+		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_POLICY,
+				egress, transfer, false, NULL, 0, 0,
+				sub_policy->idx, &flow_err);
+	if (!sub_policy->tbl_rsc) {
+		DRV_LOG(ERR,
+			"Failed to create meter sub policy table.");
+		return -1;
+	}
+	/* Prepare matchers. */
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i == RTE_COLOR_YELLOW || !acts[i].actions_n)
+			continue;
+		attr.priority = i;
+		if (!sub_policy->color_matcher[i]) {
+			/* Create matchers for Color. */
+			if (__flow_dv_create_policy_matcher(dev,
+				color_reg_c_idx, i, sub_policy,
+				&attr, is_default_policy, &flow_err))
+				return -1;
+		}
+		/* Create flow, matching color. */
+		if (acts[i].actions_n)
+			if (__flow_dv_create_policy_flow(dev,
+				color_reg_c_idx, i,
+				sub_policy->color_matcher[i]->matcher_object,
+				acts[i].actions_n,
+				acts[i].dv_actions,
+				is_default_policy,
+				&sub_policy->color_rule[i],
+				&attr))
+				return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	struct mlx5_flow_dv_tag_resource *tag;
+	struct mlx5_flow_dv_port_id_action_resource *port_action;
+	struct mlx5_hrxq *hrxq;
+	uint8_t egress, transfer;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		acts[i].actions_n = 0;
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (i == RTE_COLOR_RED) {
+			/* Only support drop on red. */
+			acts[i].dv_actions[0] =
+			mtr_policy->dr_drop_action[domain];
+			acts[i].actions_n = 1;
+			continue;
+		}
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
+					mtr_policy->act_cnt[i].rix_mark);
+			if (!tag) {
+				DRV_LOG(ERR, "Failed to find "
+				"mark action for policy.");
+				return -1;
+			}
+			acts[i].dv_actions[acts[i].actions_n] =
+						tag->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			acts[i].dv_actions[acts[i].actions_n] =
+			mtr_policy->act_cnt[i].modify_hdr->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].fate_action) {
+			switch (mtr_policy->act_cnt[i].fate_action) {
+			case MLX5_FLOW_FATE_PORT_ID:
+				port_action = mlx5_ipool_get
+					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				if (!port_action) {
+					DRV_LOG(ERR, "Failed to find "
+						"port action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				port_action->action;
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_DROP:
+			case MLX5_FLOW_FATE_JUMP:
+				acts[i].dv_actions[acts[i].actions_n] =
+				mtr_policy->act_cnt[i].dr_jump_action[domain];
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_SHARED_RSS:
+			case MLX5_FLOW_FATE_QUEUE:
+				hrxq = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+				sub_policy->rix_hrxq[i]);
+				if (!hrxq) {
+					DRV_LOG(ERR, "Failed to find "
+						"queue action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				hrxq->action;
+				acts[i].actions_n++;
+				break;
+			default:
+				/*Queue action do nothing*/
+				break;
+			}
+		}
+	}
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
+				egress, transfer, false, acts)) {
+		DRV_LOG(ERR,
+		"Failed to create policy rules per domain.");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Create the policy rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in,out] mtr_policy
+ *   Pointer to meter policy table.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	int i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		if (!sub_policy_num)
+			continue;
+		/* Prepare actions list and create policy rules*/
+		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+			mtr_policy->sub_policys[i][0], i)) {
+			DRV_LOG(ERR,
+			"Failed to create policy action list per domain.");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_meter_def_policy *def_policy;
+	struct mlx5_flow_tbl_resource *jump_tbl;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	struct rte_flow_error error;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	int ret;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	def_policy = mtrmng->def_policy[domain];
+	if (!def_policy) {
+		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(struct mlx5_flow_meter_def_policy),
+			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+		if (!def_policy) {
+			DRV_LOG(ERR, "Failed to alloc "
+					"default policy table.");
+			goto def_policy_error;
+		}
+		mtrmng->def_policy[domain] = def_policy;
+		/* Create the meter suffix table with SUFFIX level. */
+		jump_tbl = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_SUFFIX,
+				egress, transfer, false, NULL, 0,
+				0, 0, &error);
+		if (!jump_tbl) {
+			DRV_LOG(ERR,
+				"Failed to create meter suffix table.");
+			goto def_policy_error;
+		}
+		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
+		tbl_data = container_of(jump_tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].dv_actions[0] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].actions_n = 1;
+		/* Create jump action to the drop table. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
+				(dev, MLX5_FLOW_TABLE_LEVEL_METER_DROP,
+				egress, transfer, false, NULL, 0,
+				0, 0, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create "
+				"meter drop table for default policy.");
+				goto def_policy_error;
+			}
+		}
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_RED] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
+		acts[RTE_COLOR_RED].actions_n = 1;
+		/* Create default policy rules. */
+		ret = __flow_dv_create_domain_policy_rules(dev,
+					&def_policy->sub_policy,
+					egress, transfer, true, acts);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create "
+				"default policy rules.");
+				goto def_policy_error;
+		}
+	}
+	return 0;
+def_policy_error:
+	__flow_dv_destroy_domain_def_policy(dev, domain);
+	return -1;
+}
+
+/**
+ * Create the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	/* Non-termination policy table*/
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
+			continue;
+		if (__flow_dv_create_domain_def_policy(dev, i)) {
+			DRV_LOG(ERR,
+			"Failed to create default policy");
+			return -1;
+		}
+	}
+	return 0;
+}
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -13465,14 +14509,6 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
 		dtb = &mtb->egress;
 	else
 		dtb = &mtb->ingress;
-	/* Create the meter table with METER level. */
-	dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
-	if (!dtb->tbl) {
-		DRV_LOG(ERR, "Failed to create meter policer table.");
-		return -1;
-	}
 	/* Create the meter suffix table with SUFFIX level. */
 	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
 					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
@@ -13795,6 +14831,288 @@ flow_dv_action_validate(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_dev_config *dev_conf = &priv->config;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	int actions_n;
+	int i, ret;
+	struct rte_flow_error flow_err;
+	uint8_t domain_color[RTE_COLORS] = {0};
+	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
+
+	if (!priv->config.dv_esw_en)
+		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	*domain_bitmap = def_domain;
+	/*
+	 * Check default policy actions:
+	 * Green/Yellow: no action, Red: drop action
+	 */
+	if ((!actions[RTE_COLOR_GREEN] ||
+		actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END) &&
+	    (!actions[RTE_COLOR_YELLOW] ||
+		actions[RTE_COLOR_YELLOW]->type == RTE_FLOW_ACTION_TYPE_END) &&
+	    (actions[RTE_COLOR_RED] &&
+	     actions[RTE_COLOR_RED]->type == RTE_FLOW_ACTION_TYPE_DROP)) {
+		*is_def_policy = true;
+		return 0;
+	}
+	for (i = 0; i < RTE_COLORS; i++) {
+		act = actions[i];
+		if (i == RTE_COLOR_RED &&
+			(!act || act->type != RTE_FLOW_ACTION_TYPE_DROP))
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Red color only supports drop action.");
+		for (action_flags = 0, actions_n = 0;
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			if (i == RTE_COLOR_YELLOW)
+				return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"Yellow color does not support any action.");
+			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "too many actions");
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+				if (!priv->config.dv_esw_en)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "PORT action validate check"
+					" fail for ESW disable");
+				ret = flow_dv_validate_action_port_id(dev,
+						action_flags,
+						act, attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"PORT action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			case RTE_FLOW_ACTION_TYPE_MARK:
+				ret = flow_dv_validate_action_mark(dev, act,
+							   action_flags,
+							   attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Mark action validate check fail");
+				if (dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "Extend MARK action is "
+					"not supported. Please try use "
+					"policy id 0 for meter.");
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+				ret = flow_dv_validate_action_set_tag(dev,
+							act, action_flags,
+							attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Set tag action validate check fail");
+				/* Count all modify-header actions
+				 * as one action.
+				 */
+				if (!(action_flags &
+					MLX5_FLOW_MODIFY_HDR_ACTIONS))
+					++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			case RTE_FLOW_ACTION_TYPE_DROP:
+				ret = mlx5_flow_validate_action_drop
+					(action_flags,
+					attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Drop action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+				/* Check whether extensive
+				 * metadata feature is engaged.
+				 */
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Queue action with meta "
+					  "is not supported. Please try use "
+					  "policy id 0 for meter.");
+				ret = mlx5_flow_validate_action_queue(act,
+							action_flags, dev,
+							attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Queue action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_RSS:
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "RSS action with meta "
+					  "is not supported. Please try use "
+					  "policy id 0 for meter.");
+				ret = mlx5_validate_action_rss(dev, act,
+						&flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "RSS action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				++actions_n;
+				*is_rss = true;
+				break;
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+				ret = flow_dv_validate_action_jump(dev,
+					NULL, act, action_flags,
+					attr, true, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Jump action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Doesn't support optional action");
+			}
+		}
+		/* Yellow is not supported, just skip. */
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
+		else if ((action_flags &
+			(MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
+			(action_flags & MLX5_FLOW_ACTION_MARK))
+			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
+		else
+			domain_color[i] = def_domain;
+		/*
+		 * Validate the drop action mutual exclusion
+		 * with other actions. Drop action is mutually-exclusive
+		 * with any other action, except for Count action.
+		 */
+		if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
+			(action_flags & ~MLX5_FLOW_ACTION_DROP)) {
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Drop action is mutually-exclusive "
+				"with any other action");
+		}
+		/* Eswitch has few restrictions on using items and actions */
+		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
+			if (!mlx5_flow_ext_mreg_supported(dev) &&
+				action_flags & MLX5_FLOW_ACTION_MARK)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action MARK");
+			if (action_flags & MLX5_FLOW_ACTION_QUEUE)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action QUEUE");
+			if (action_flags & MLX5_FLOW_ACTION_RSS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action RSS");
+			if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+		} else {
+			if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) &&
+				(domain_color[i] &
+				MLX5_MTR_DOMAIN_INGRESS_BIT)) {
+				if ((domain_color[i] &
+					MLX5_MTR_DOMAIN_EGRESS_BIT))
+					domain_color[i] =
+					MLX5_MTR_DOMAIN_EGRESS_BIT;
+				else
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+			}
+		}
+		if (domain_color[i] != def_domain)
+			*domain_bitmap = domain_color[i];
+	}
+	return 0;
+}
+
 static int
 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
 {
@@ -13830,8 +15148,16 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.query = flow_dv_query,
 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
+	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
+	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
+	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
+	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
+	.create_policy_rules = flow_dv_create_policy_rules,
+	.destroy_policy_rules = flow_dv_destroy_policy_rules,
+	.create_def_policy = flow_dv_create_def_policy,
+	.destroy_def_policy = flow_dv_destroy_def_policy,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index af0a1c18cb..495ae5c67b 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -38,6 +38,12 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
 	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
 	uint32_t val;
+	enum mlx5_meter_domain domain =
+		fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+			fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
+				MLX5_MTR_DOMAIN_INGRESS;
+	struct mlx5_flow_meter_def_policy *def_policy =
+		priv->sh->mtrmng->def_policy[domain];
 
 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
@@ -57,10 +63,7 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
-	mtr_init.next_table =
-		fm->transfer ? fm->mfts->transfer.tbl->obj :
-			fm->egress ? fm->mfts->egress.tbl->obj :
-				fm->mfts->ingress.tbl->obj;
+	mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
 	mtr_init.flow_meter_parameter = fmp;
 	mtr_init.flow_meter_parameter_sz =
@@ -317,7 +320,7 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
 					  "Meter is not supported");
 	memset(cap, 0, sizeof(*cap));
 	if (priv->sh->meter_aso_en)
-	    /* 2 meters per one ASO cache line. */
+		/* 2 meters per one ASO cache line. */
 		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
 	else
 		cap->n_max = 1 << qattr->log_max_flow_meter;
@@ -435,6 +438,357 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * Find policy by id.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param policy_id
+ *   Policy id.
+ *
+ * @return
+ *   Pointer to the policy found on success, NULL otherwise.
+ */
+struct mlx5_flow_meter_policy *
+mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
+			    uint32_t policy_id,
+			    uint32_t *policy_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	union mlx5_l3t_data data;
+
+	if (!policy_id || policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM ||
+		!priv->sh->mtrmng->policy_idx_tbl)
+		return NULL;
+	if (mlx5_l3t_get_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data) ||
+				!data.dword) {
+		return NULL;
+	}
+	if (policy_idx)
+		*policy_idx = data.dword;
+	sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				data.dword);
+	/* Remove reference taken by the mlx5_l3t_get_entry. */
+	(void)mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id);
+	if (sub_policy) {
+		if (sub_policy->main_policy_id)
+			return sub_policy->main_policy;
+	}
+	return NULL;
+}
+
+/**
+ * Callback to check MTR policy action validate
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_validate(struct rte_eth_dev *dev,
+	const struct rte_flow_action *actions[RTE_COLORS],
+	struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint8_t domain_bitmap;
+	int ret;
+
+	if (!priv->mtr_en || !priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "meter policy unsupported.");
+	ret = mlx5_flow_validate_mtr_acts(dev, actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+/**
+ * Callback to add MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] policy_id
+ *   Pointer to policy id
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_create(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	uint32_t sub_policy_idx = 0;
+	uint32_t policy_idx = 0;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint32_t i;
+	int ret;
+	uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
+	uint16_t sub_policy_num;
+	uint8_t domain_bitmap = 0;
+	union mlx5_l3t_data data;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "meter policy unsupported.");
+	if (!priv->sh->meter_aso_en &&
+		policy_id != MLX5_MTR_DEFAULT_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "please use default policy id.");
+	ret = mlx5_flow_validate_mtr_acts(dev, actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	if (is_def_policy) {
+		if (policy_id != MLX5_MTR_DEFAULT_POLICY_ID)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "please use default policy id.");
+		if (mlx5_flow_create_def_policy(dev))
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "fail to create default policy.");
+		__atomic_add_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
+				1, __ATOMIC_RELAXED);
+		return 0;
+	}
+	if (policy_id == MLX5_MTR_DEFAULT_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+			NULL, "invalid actions for default policy.");
+	if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy id is invalid. ");
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id,
+				&policy_idx);
+	if (mtr_policy)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy object already exists. ");
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		if (is_rss) {
+			policy_size +=
+			sizeof(struct mlx5_flow_meter_sub_policy  *) *
+			MLX5_MTR_RSS_MAX_SUB_POLICY;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
+	}
+	mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
+			 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+				"Memory alloc failed for meter policy.");
+	policy_size = sizeof(struct mlx5_flow_meter_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
+		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy)
+			goto policy_add_err;
+		if (sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto policy_add_err;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+		if (policy_idx) {
+			policy_idx = sub_policy_idx;
+			sub_policy->main_policy_id = 1;
+		}
+		mtr_policy->sub_policys[i] =
+		(struct mlx5_flow_meter_sub_policy **)
+			((uint8_t *)mtr_policy + policy_size);
+		mtr_policy->sub_policys[i][0] = sub_policy;
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		sub_policy_num++;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MARK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
+		mtr_policy->sub_policy_num |=
+			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MARK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
+		if (is_rss) {
+			mtr_policy->is_rss = 1;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
+	}
+	ret = mlx5_flow_create_mtr_acts(dev, mtr_policy, actions, error);
+	if (ret)
+		goto policy_add_err;
+	if (!is_rss) {
+		/* Create policy rules in HW. */
+		ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
+		if (ret)
+			goto policy_add_err;
+	}
+	if (!priv->sh->mtrmng->policy_idx_tbl)
+		priv->sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+	if (!priv->sh->mtrmng->policy_idx_tbl)
+		goto policy_add_err;
+	data.dword = policy_idx;
+	if (mlx5_l3t_set_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data))
+		goto policy_add_err;
+	rte_spinlock_init(&mtr_policy->sl);
+	return 0;
+policy_add_err:
+	if (mtr_policy) {
+		mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
+		if (!is_rss)
+			mlx5_flow_destroy_policy_rules(dev, mtr_policy);
+		for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+			sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+			if (sub_policy_num) {
+				sub_policy = mtr_policy->sub_policys[i][0];
+				if (sub_policy)
+					mlx5_ipool_free
+					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+			}
+		}
+		mlx5_free(mtr_policy);
+	}
+	return -rte_mtr_error_set(error, ENOTSUP,
+				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+				  NULL, "Failed to create devx policy.");
+}
+
+static int
+__mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint32_t i, j;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	if (mtr_policy->ref_cnt) {
+		rte_spinlock_unlock(&mtr_policy->sl);
+		return -rte_mtr_error_set(error, EBUSY,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				 NULL,
+				"Meter policy object is being used.");
+	}
+	mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
+	mlx5_flow_destroy_policy_rules(dev, mtr_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		if (sub_policy_num) {
+			for (j = 0; j < sub_policy_num; j++) {
+				sub_policy = mtr_policy->sub_policys[i][j];
+				if (sub_policy)
+					mlx5_ipool_free
+					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+			}
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl && policy_id)
+		if (mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+					policy_id)) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Fail to delete policy in index table.");
+		}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return 0;
+}
+
+/**
+ * Callback to delete MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Meter policy 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_policy_delete(struct rte_eth_dev *dev,
+			  uint32_t policy_id,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	int ret;
+
+	if (policy_id == MLX5_MTR_DEFAULT_POLICY_ID) {
+		if (!priv->sh->mtrmng->def_policy_ref_cnt)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy id is invalid.");
+		if (priv->sh->mtrmng->def_policy_mtr_ref_cnt > 0)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter object is being used.");
+		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
+					1, __ATOMIC_RELAXED);
+		return 0;
+	}
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy id is invalid. ");
+	ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
+						error);
+	if (ret)
+		return ret;
+	mlx5_free(mtr_policy);
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -942,6 +1296,9 @@ 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,
+	.meter_policy_validate = mlx5_flow_meter_policy_validate,
+	.meter_policy_create = mlx5_flow_meter_policy_create,
+	.meter_policy_delete = mlx5_flow_meter_policy_delete,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -989,22 +1346,32 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_aso_mtr *aso_mtr;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	union mlx5_l3t_data data;
 
 	if (priv->sh->meter_aso_en) {
-		rte_spinlock_lock(&mtrmng->mtrsl);
-		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
-			!data.dword) {
-			rte_spinlock_unlock(&mtrmng->mtrsl);
-			return NULL;
+		rte_spinlock_lock(&pools_mng->mtrsl);
+		if (priv->mtr_idx_tbl) {
+			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
+				meter_id, &data) ||
+				!data.dword) {
+				rte_spinlock_unlock(&pools_mng->mtrsl);
+				return NULL;
+			}
+			if (mtr_idx)
+				*mtr_idx = data.dword;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+			/* Remove reference taken by the mlx5_l3t_get_entry. */
+			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
+		} else {
+			if (mtr_idx)
+				*mtr_idx = meter_id;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
 		}
-		if (mtr_idx)
-			*mtr_idx = data.dword;
-		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-		/* Remove reference taken by the mlx5_l3t_get_entry. */
-		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
+		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
+			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
@@ -1169,39 +1536,67 @@ 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_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
 	struct mlx5_aso_mtr_pool *mtr_pool;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
 	void *tmp;
-	uint32_t i, offset, mtr_idx;
+	uint32_t i, offset, mtr_idx, policy_idx;
+	void *entry;
 
 	if (priv->sh->meter_aso_en) {
-		i = mtrmng->n_valid;
+		i = pools_mng->n_valid;
 		while (i--) {
-			mtr_pool = mtrmng->pools[i];
+			mtr_pool = pools_mng->pools[i];
 			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
 				offset++) {
 				fm = &mtr_pool->mtrs[offset].fm;
 				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				if (mlx5_flow_meter_params_flush(dev,
-						fm, mtr_idx))
-					return -rte_mtr_error_set
-					(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				(void)mlx5_flow_meter_params_flush(dev,
+						fm, mtr_idx);
 			}
 		}
+		if (priv->sh->mtrmng->policy_idx_tbl) {
+			MLX5_L3T_FOREACH(priv->sh->mtrmng->policy_idx_tbl,
+					i, entry) {
+				policy_idx = *(uint32_t *)entry;
+				if (policy_idx) {
+					sub_policy =
+					mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					policy_idx);
+					if (!sub_policy)
+						return -rte_mtr_error_set
+						(error, EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+					if (__mlx5_flow_meter_policy_delete
+						(dev, 0,
+						sub_policy->main_policy,
+						error))
+						return -rte_mtr_error_set
+						(error, EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+				}
+			}
+			mlx5_l3t_destroy(priv->sh->mtrmng->policy_idx_tbl);
+			priv->sh->mtrmng->policy_idx_tbl = NULL;
+		}
 	} else {
 		TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
 			fm = &legacy_fm->fm;
 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
 				return -rte_mtr_error_set(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+				NULL, "MTR object meter profile invalid.");
 		}
 	}
 	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
@@ -1211,5 +1606,8 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
 		mlx5_free(fmp);
 	}
+	/* Delete default policy table. */
+	mlx5_flow_destroy_def_policy(dev);
+	mlx5_flow_destroy_mtr_drop_tbls(dev);
 	return 0;
 }
-- 
2.27.0


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

* [dpdk-dev] [PATCH v2 2/4] net/mlx5: support meter creation with policy
  2021-04-02 15:56 ` [dpdk-dev] [PATCH v2 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 1/4] " Li Zhang
@ 2021-04-02 15:56   ` Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-02 15:56 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

Make meter creation with policy to
support actions per color.

The following cases to be considered:
1.Add entry match with meter_id in global drop table.
2.For non-termination policy (policy id 0),
  add jump rule to suffix table for green and
  jump rule to drop table for red.
3.Allocate counter per meter for drop table.
4.Allocate meter resource per domain per color.
5.It can work with ASO meter and legacy meter both.

Signed-off-by: Li Zhang <lizh@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |  13 +-
 drivers/net/mlx5/mlx5.h            |  60 ++---
 drivers/net/mlx5/mlx5_flow.c       |  26 +-
 drivers/net/mlx5/mlx5_flow.h       |  32 +--
 drivers/net/mlx5/mlx5_flow_dv.c    | 368 ++++++++++++++++++++---------
 drivers/net/mlx5/mlx5_flow_meter.c | 345 +++++++++++++++++++++++----
 6 files changed, 614 insertions(+), 230 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 859b9098dc..9ef3e31bb3 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1244,13 +1244,14 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			if (log_obj_size >=
 			config->hca_attr.qos.log_meter_aso_granularity &&
 			log_obj_size <=
-			config->hca_attr.qos.log_meter_aso_max_alloc) {
+			config->hca_attr.qos.log_meter_aso_max_alloc)
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
-				if (err) {
-					err = -err;
-					goto error;
-				}
+		}
+		if (priv->mtr_en) {
+			err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
+			if (err) {
+				err = -err;
+				goto error;
 			}
 		}
 #endif
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index f02360dccf..81341236e6 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -707,44 +707,12 @@ struct mlx5_flow_meter_def_policy {
  */
 #define MLX5_MTR_DEFAULT_POLICY_ID 0
 
-/* Meter table structure. */
-struct mlx5_meter_domain_info {
-	struct mlx5_flow_tbl_resource *tbl;
-	/**< Meter table. */
-	struct mlx5_flow_tbl_resource *sfx_tbl;
-	/**< Meter suffix table. */
-	struct mlx5_flow_dv_matcher *drop_matcher;
-	/**< Matcher for Drop. */
-	struct mlx5_flow_dv_matcher *color_matcher;
-	/**< Matcher for Color. */
-	void *jump_actn;
-	/**< Meter match action. */
-	void *green_rule;
-	/**< Meter green rule. */
-	void *drop_rule;
-	/**< Meter drop rule. */
-};
-
-/* 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. */
-	void *green_count;
-	/**< Counters for green rule. */
-	void *drop_count;
-	/**< Counters for green rule. */
-};
-
 /* Meter parameter structure. */
 struct mlx5_flow_meter_info {
+	uint32_t meter_id;
+	/**< Meter id. */
+	uint32_t policy_id;
+	/* Policy id, the first sub_policy idx. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
 	rte_spinlock_t sl; /**< Meter action spinlock. */
@@ -783,8 +751,8 @@ struct mlx5_flow_meter_info {
 	 * received by the application.
 	 */
 	uint32_t transfer:1;
-	struct mlx5_meter_domains_infos *mfts;
-	/**< Flow table created for this meter. */
+	void *drop_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop rule in drop table. */
 	uint32_t drop_cnt;
 	/**< Color counter for drop. */
 	uint32_t ref_cnt;
@@ -795,6 +763,11 @@ struct mlx5_flow_meter_info {
 	/**< Flow meter action. */
 };
 
+/* PPS(packets per second) map to BPS(Bytes per second).
+ * HW treat packet as 128bytes in PPS mode
+ */
+#define MLX5_MTRS_PPS_MAP_BPS_SHIFT 7
+
 /* RFC2697 parameter structure. */
 struct mlx5_flow_meter_srtcm_rfc2697_prm {
 	rte_be32_t cbs_cir;
@@ -883,12 +856,17 @@ struct mlx5_flow_mtr_mng {
 	/* Policy index lookup table. */
 	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
 	/* Meter drop table. */
-	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	struct mlx5_flow_dv_matcher *
+			drop_matcher[MLX5_MTR_DOMAIN_MAX][MLX5_REG_BITS];
 	/* Matcher meter in drop table. */
 	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
 	/* default matcher in drop table. */
 	void *def_rule[MLX5_MTR_DOMAIN_MAX];
 	/* default rule in drop table. */
+	uint8_t max_mtr_bits;
+	/* Indicate how many bits are used by meter id at the most. */
+	uint8_t max_mtr_flow_bits;
+	/* Indicate how many bits are used by meter flow id at the most. */
 };
 #define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
 
@@ -1316,10 +1294,6 @@ struct mlx5_priv {
 	uint32_t rss_shared_actions; /* RSS shared actions. */
 	struct mlx5_devx_obj *q_counters; /* DevX queue counter object. */
 	uint32_t counter_set_id; /* Queue counter ID to set in DevX objects. */
-	uint8_t max_mtr_bits;
-	/* Indicate how many bits are used by meter id at the most. */
-	uint8_t max_mtr_flow_bits;
-	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 #define PORT_ID(priv) ((priv)->dev_data->port_id)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 15ae8b9528..b41bf6456d 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4506,14 +4506,14 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 				"Failed to allocate meter flow id.");
 	flow_id_bits = MLX5_REG_BITS - __builtin_clz(tag_id - 1);
 	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->max_mtr_bits) > mtr_reg_bits) {
+	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
 		mlx5_ipool_free(fm->flow_ipool, tag_id);
 		return rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				"Meter flow id exceeds max limit.");
 	}
-	if (flow_id_bits > priv->max_mtr_flow_bits)
-		priv->max_mtr_flow_bits = flow_id_bits;
+	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -6785,15 +6785,18 @@ mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  *
  * @return
- *   Pointer to table set on success, NULL otherwise.
+ *   0 on success, -1 otherwise.
  */
-struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+int
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
 	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, mtr_idx, domain_bitmap);
 }
 
 /**
@@ -6803,18 +6806,15 @@ mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  * @param[in] tbl
  *   Pointer to the meter table set.
- *
- * @return
- *   0 on success.
  */
-int
+void
 mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *tbls)
+			   struct mlx5_flow_meter_info *fm)
 {
 	const struct mlx5_flow_driver_ops *fops;
 
 	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->destroy_mtr_tbls(dev, tbls);
+	fops->destroy_mtr_tbls(dev, fm);
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 97e766a6b1..5672df983e 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -222,16 +222,17 @@ enum mlx5_feature_name {
 #define MLX5_FLOW_ACTION_TUNNEL_SET (1ull << 37)
 #define MLX5_FLOW_ACTION_TUNNEL_MATCH (1ull << 38)
 #define MLX5_FLOW_ACTION_MODIFY_FIELD (1ull << 39)
+#define MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY (1ull << 40)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \
 	 MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_JUMP | \
-	 MLX5_FLOW_ACTION_DEFAULT_MISS)
+	 MLX5_FLOW_ACTION_DEFAULT_MISS | \
+	 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_FATE_ESWITCH_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \
-	 MLX5_FLOW_ACTION_JUMP)
-
+	 MLX5_FLOW_ACTION_JUMP | MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_MODIFY_HDR_ACTIONS (MLX5_FLOW_ACTION_SET_IPV4_SRC | \
 				      MLX5_FLOW_ACTION_SET_IPV4_DST | \
@@ -831,9 +832,8 @@ struct mlx5_legacy_flow_meter {
 	/* Must be the first in struct. */
 	TAILQ_ENTRY(mlx5_legacy_flow_meter) next;
 	/**< Pointer to the next flow meter structure. */
-	uint32_t meter_id;
-	/**< Meter id. */
-	uint32_t idx; /* Index to meter object. */
+	uint32_t idx;
+	/* Index to meter object. */
 };
 
 #define MLX5_MAX_TUNNELS 256
@@ -1068,10 +1068,12 @@ 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);
+typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
+					struct mlx5_flow_meter_info *fm,
+					uint32_t mtr_idx,
+					uint8_t domain_bitmap);
+typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm);
 typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
@@ -1389,10 +1391,12 @@ int mlx5_flow_validate_item_ecpri(const struct rte_flow_item *item,
 				  uint16_t ether_type,
 				  const struct rte_flow_item_ecpri *acc_mask,
 				  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);
+int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
+				uint32_t mtr_idx,
+				uint8_t domain_bitmap);
+void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter_info *fm);
 void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
 			  struct rte_mtr_error *error);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 412e730aaf..adf7a8f1e7 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -4856,11 +4856,14 @@ 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,
+				uint32_t *policy_id,
 				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_info *fm;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 
 	if (!am)
 		return rte_flow_error_set(error, EINVAL,
@@ -4891,10 +4894,41 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
 	      (!fm->ingress && !attr->ingress && attr->egress) ||
 	      (!fm->egress && !attr->egress && attr->ingress)))
 		return rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Flow attributes domain are either invalid "
+			"or have a domain conflict with current "
+			"meter attributes");
+	if (priv->sh->meter_aso_en) {
+		if (fm->policy_id) {
+			mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+			if (!mtr_policy)
+				return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Invalid policy id for meter ");
+			if (!((attr->transfer && mtr_policy->transfer) ||
+				(attr->egress && mtr_policy->egress) ||
+				(attr->ingress && mtr_policy->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");
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		} else {
+			if (!((attr->transfer &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
+				(attr->egress &&
+				mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
+				(attr->ingress &&
+				mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
+				return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		}
+	}
+	*policy_id = fm->policy_id;
 	return 0;
 }
 
@@ -6269,6 +6303,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		.fdb_def_rule = !!priv->fdb_def_rule,
 	};
 	const struct rte_eth_hairpin_conf *conf;
+	uint32_t policy_id = 0;
 
 	if (items == NULL)
 		return -1;
@@ -6610,6 +6645,12 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
 						  actions, "too many actions");
+		if (action_flags &
+			MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
+			return rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "meter action with policy "
+				"must be the last action");
 		switch (type) {
 		case RTE_FLOW_ACTION_TYPE_VOID:
 			break;
@@ -7012,10 +7053,14 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			ret = mlx5_flow_validate_action_meter(dev,
 							      action_flags,
 							      actions, attr,
+							      &policy_id,
 							      error);
 			if (ret < 0)
 				return ret;
 			action_flags |= MLX5_FLOW_ACTION_METER;
+			if (policy_id)
+				action_flags |=
+				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
 			++actions_n;
 			/* Meter action will add one more TAG action. */
 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
@@ -7275,6 +7320,36 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 						 "multiple VLAN actions");
 		}
 	}
+	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
+		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
+			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
+			attr->ingress)
+			return rte_flow_error_set
+				(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "fate action not supported for "
+				"meter with policy");
+		if (attr->egress) {
+			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "modify header action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "encap action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "push vlan action in egress "
+					"cannot be done before meter action");
+		}
+	}
 	/*
 	 * Hairpin flow will add one more TAG action in TX implicit mode.
 	 * In TX explicit mode, there will be no hairpin flow ID.
@@ -13975,38 +14050,24 @@ flow_dv_query(struct rte_eth_dev *dev,
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
- * @param[in] tbl
- *   Pointer to the meter table set.
- *
- * @return
- *   Always 0.
+ * @param[in] fm
+ *   Meter information table.
  */
-static int
-flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
-			struct mlx5_meter_domains_infos *tbl)
+static void
+flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_meter_domains_infos *mtd =
-				(struct mlx5_meter_domains_infos *)tbl;
+	int i;
 
-	if (!mtd || !priv->config.dv_flow_en)
-		return 0;
-	if (mtd->egress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.tbl);
-	if (mtd->egress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.sfx_tbl);
-	if (mtd->ingress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->ingress.tbl);
-	if (mtd->ingress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->ingress.sfx_tbl);
-	if (mtd->transfer.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->transfer.tbl);
-	if (mtd->transfer.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->transfer.sfx_tbl);
-	mlx5_free(mtd);
-	return 0;
+	if (!fm || !priv->config.dv_flow_en)
+		return;
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
+		}
+	}
 }
 
 static void
@@ -14015,7 +14076,7 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct mlx5_flow_tbl_data_entry *tbl;
-	int i;
+	int i, j;
 
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (mtrmng->def_rule[i]) {
@@ -14030,12 +14091,16 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 				      &mtrmng->def_matcher[i]->entry);
 			mtrmng->def_matcher[i] = NULL;
 		}
-		if (mtrmng->drop_matcher[i]) {
-			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
-				struct mlx5_flow_tbl_data_entry, tbl);
-			mlx5_cache_unregister(&tbl->matchers,
-				      &mtrmng->drop_matcher[i]->entry);
-			mtrmng->drop_matcher[i] = NULL;
+		for (j = 0; j < MLX5_REG_BITS; j++) {
+			if (mtrmng->drop_matcher[i][j]) {
+				tbl =
+				container_of(mtrmng->drop_matcher[i][j]->tbl,
+					     struct mlx5_flow_tbl_data_entry,
+					     tbl);
+				mlx5_cache_unregister(&tbl->matchers,
+					&mtrmng->drop_matcher[i][j]->entry);
+				mtrmng->drop_matcher[i][j] = NULL;
+			}
 		}
 		if (mtrmng->drop_tbl[i]) {
 			flow_dv_tbl_resource_release(MLX5_SH(dev),
@@ -14481,96 +14546,171 @@ flow_dv_create_def_policy(struct rte_eth_dev *dev)
 }
 
 /**
- * Create specify domain meter table and suffix table.
+ * Create the needed meter tables.
+ * Lock free, (mutex should be acquired by caller).
  *
  * @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] fm
+ *   Meter information table.
+ * @param[in] mtr_idx
+ *   Meter index.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] domain_bitmap
+ *   Domain bitmap.
  * @return
  *   0 on success, -1 otherwise.
  */
 static int
-flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *mtb,
-			   uint8_t egress, uint8_t transfer)
-{
-	struct rte_flow_error error;
-	struct mlx5_meter_domain_info *dtb;
-
-	if (transfer)
-		dtb = &mtb->transfer;
-	else if (egress)
-		dtb = &mtb->egress;
-	else
-		dtb = &mtb->ingress;
-	/* Create the meter suffix table with SUFFIX level. */
-	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
-					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
-	if (!dtb->sfx_tbl) {
-		DRV_LOG(ERR, "Failed to create meter suffix table.");
-		return -1;
-	}
-	return 0;
-}
-
-/**
- * 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)
+flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_meter_domains_infos *mtb;
-	int ret;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct rte_flow_error error;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	void *actions[METER_ACTIONS];
+	int domain, ret, i;
+	struct mlx5_flow_counter *cnt;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher_para = {
+		.size = sizeof(matcher_para.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	uint32_t mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
+						     0, &error);
+	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+	};
+	struct mlx5_flow_dv_matcher *drop_matcher;
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = &error,
+		.data = &matcher,
+	};
 
 	if (!priv->mtr_en) {
 		rte_errno = ENOTSUP;
-		return NULL;
-	}
-	mtb = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*mtb), 0, SOCKET_ID_ANY);
-	if (!mtb) {
-		DRV_LOG(ERR, "Failed to allocate memory for meter.");
-		return NULL;
-	}
-	/* Egress meter table. */
-	ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0);
-	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);
-	if (ret) {
-		DRV_LOG(ERR, "Failed to prepare ingress meter table.");
-		goto error_exit;
+		return -1;
 	}
-	/* FDB meter table. */
-	if (priv->config.dv_esw_en) {
-		ret = flow_dv_prepare_mtr_tables(dev, mtb, 0, 1);
+	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
+		if (!(domain_bitmap & (1 << domain)) ||
+			(mtrmng->def_rule[domain] && !fm->drop_cnt))
+			continue;
+		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		/* Create the drop table with METER DROP level. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
+					MLX5_FLOW_TABLE_LEVEL_METER_DROP,
+					egress, transfer, false, NULL, 0,
+					0, 0, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create meter drop table.");
+				goto policy_error;
+			}
+		}
+		/* Create default matcher in drop table. */
+		matcher.tbl = mtrmng->drop_tbl[domain],
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		if (!mtrmng->def_matcher[domain]) {
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+				       (enum modify_reg)mtr_id_reg_c,
+				       0, 0);
+			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR, "Failed to register meter "
+				"drop default matcher.");
+				goto policy_error;
+			}
+			mtrmng->def_matcher[domain] = container_of(entry,
+			struct mlx5_flow_dv_matcher, entry);
+		}
+		/* Create default rule in drop table. */
+		if (!mtrmng->def_rule[domain]) {
+			i = 0;
+			actions[i++] = priv->sh->esw_drop_action;
+			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c, 0, 0);
+			ret = mlx5_flow_os_create_flow
+				(mtrmng->def_matcher[domain]->matcher_object,
+				(void *)&value, i, actions,
+				&mtrmng->def_rule[domain]);
+			if (ret) {
+				DRV_LOG(ERR, "Failed to create meter "
+				"default drop rule for drop table.");
+				goto policy_error;
+			}
+		}
+		if (!fm->drop_cnt)
+			continue;
+		MLX5_ASSERT(mtrmng->max_mtr_bits);
+		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
+			/* Create matchers for Drop. */
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+					(enum modify_reg)mtr_id_reg_c, 0,
+					(LS32_MASK(mtrmng->max_mtr_bits) <<
+					 mtr_id_offset));
+			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR,
+				"Failed to register meter drop matcher.");
+				goto policy_error;
+			}
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
+				container_of(entry, struct mlx5_flow_dv_matcher,
+					     entry);
+		}
+		drop_matcher =
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
+		/* Create drop rule, matching meter_id only. */
+		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c,
+				(mtr_idx << mtr_id_offset), UINT32_MAX);
+		i = 0;
+		cnt = flow_dv_counter_get_by_idx(dev,
+					fm->drop_cnt, NULL);
+		actions[i++] = cnt->action;
+		actions[i++] = priv->sh->esw_drop_action;
+		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
+					       (void *)&value, i, actions,
+					       &fm->drop_rule[domain]);
 		if (ret) {
-			DRV_LOG(ERR, "Failed to prepare fdb meter table.");
-			goto error_exit;
+			DRV_LOG(ERR, "Failed to create meter "
+				"drop rule for drop table.");
+				goto policy_error;
 		}
 	}
-	return mtb;
-error_exit:
-	flow_dv_destroy_mtr_tbl(dev, mtb);
-	return NULL;
+	return 0;
+policy_error:
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
+		}
+	}
+	return -1;
 }
 
 /**
@@ -15146,8 +15286,8 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.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,
+	.create_mtr_tbls = flow_dv_create_mtr_tbls,
+	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
 	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 495ae5c67b..62b000c1fa 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -615,9 +615,12 @@ mlx5_flow_meter_policy_create(struct rte_eth_dev *dev,
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (!(domain_bitmap & (1 << i)))
 			continue;
-		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
-		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
-		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		if (i == MLX5_MTR_DOMAIN_INGRESS)
+			mtr_policy->ingress = 1;
+		if (i == MLX5_MTR_DOMAIN_EGRESS)
+			mtr_policy->egress = 1;
+		if (i == MLX5_MTR_DOMAIN_TRANSFER)
+			mtr_policy->transfer = 1;
 		sub_policy = mlx5_ipool_zmalloc
 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
 				&sub_policy_idx);
@@ -627,7 +630,7 @@ mlx5_flow_meter_policy_create(struct rte_eth_dev *dev,
 			goto policy_add_err;
 		sub_policy->idx = sub_policy_idx;
 		sub_policy->main_policy = mtr_policy;
-		if (policy_idx) {
+		if (!policy_idx) {
 			policy_idx = sub_policy_idx;
 			sub_policy->main_policy_id = 1;
 		}
@@ -789,6 +792,52 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * 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)
+{
+	/* Meter must use global drop action. */
+	if (!priv->sh->esw_drop_action)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL,
+					  "No drop action ready for meter.");
+	/* 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 meter id. */
+	if (mlx5_flow_meter_find(priv, meter_id, NULL))
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+			"Meter object already exists.");
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -894,13 +943,209 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 #endif
 }
 
-static void
-mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
+static int
+mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
 				uint64_t stats_mask)
 {
 	fm->bytes_dropped =
 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
+	if (fm->bytes_dropped || fm->pkts_dropped) {
+		if (!fm->drop_cnt) {
+			/* Alloc policer counters. */
+			fm->drop_cnt = mlx5_counter_alloc(dev);
+			if (!fm->drop_cnt)
+				return -1;
+		}
+	} else {
+		if (fm->drop_cnt) {
+			mlx5_counter_free(dev, fm->drop_cnt);
+			fm->drop_cnt = 0;
+		}
+	}
+	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_legacy_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_flow_meter_info *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_indexed_pool_config flow_ipool_cfg = {
+		.size = 0,
+		.trunk_size = 64,
+		.need_lock = 1,
+		.type = "mlx5_flow_mtr_flow_id_pool",
+	};
+	struct mlx5_aso_mtr *aso_mtr;
+	uint32_t mtr_idx;
+	union mlx5_l3t_data data;
+	int ret;
+	uint8_t domain_bitmap;
+	uint8_t mtr_id_bits;
+	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
+				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter is not supported");
+	/* 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.");
+	/* Meter policy must exist. */
+	if (params->meter_policy_id != MLX5_MTR_DEFAULT_POLICY_ID) {
+		if (!priv->sh->meter_aso_en)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Part of the policies cannot be "
+				"supported without ASO ");
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+				params->meter_policy_id, NULL);
+		if (!mtr_policy)
+			return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+		domain_bitmap = (mtr_policy->ingress ?
+					MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
+				(mtr_policy->egress ?
+					MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
+				(mtr_policy->transfer ?
+					MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
+	} else {
+		if (!priv->sh->meter_aso_en) {
+			if (mlx5_flow_create_def_policy(dev))
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "fail to create default policy.");
+			if (!priv->sh->mtrmng->def_policy_ref_cnt)
+				__atomic_add_fetch
+				(&priv->sh->mtrmng->def_policy_ref_cnt,
+				1, __ATOMIC_RELAXED);
+		} else {
+			if (!priv->sh->mtrmng->def_policy_ref_cnt)
+				return -rte_mtr_error_set(error, ENOENT,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+					NULL, "Meter policy id not valid.");
+		}
+		__atomic_add_fetch
+			(&priv->sh->mtrmng->def_policy_mtr_ref_cnt,
+			1, __ATOMIC_RELAXED);
+		domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
+		if (!priv->config.dv_esw_en)
+			domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	}
+	/* Allocate the flow meter memory. */
+	if (priv->sh->meter_aso_en) {
+		mtr_idx = mlx5_flow_mtr_alloc(dev);
+		if (!mtr_idx)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+		fm = &aso_mtr->fm;
+	} else {
+		legacy_fm = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
+		if (legacy_fm == NULL)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		legacy_fm->idx = mtr_idx;
+		fm = &legacy_fm->fm;
+	}
+	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
+	if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
+	    mtr_reg_bits) {
+		DRV_LOG(ERR, "Meter number exceeds max limit.");
+		goto error;
+	}
+	if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
+		priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
+	/* Fill the flow meter parameters. */
+	fm->meter_id = meter_id;
+	fm->policy_id = params->meter_policy_id;
+	fm->profile = fmp;
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
+		goto error;
+	if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
+		goto error;
+	/* Add to the flow meter list. */
+	if (!priv->sh->meter_aso_en)
+		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
+	/* Add to the flow meter list. */
+	fm->active_state = 1; /* Config meter starts as active. */
+	fm->is_enable = 1;
+	fm->shared = !!shared;
+	__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
+	if (params->meter_policy_id == MLX5_MTR_DEFAULT_POLICY_ID) {
+		fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
+		if (!fm->flow_ipool)
+			goto error;
+	}
+	rte_spinlock_init(&fm->sl);
+	/* If ASO meter supported, update ASO flow meter by wqe. */
+	if (priv->sh->meter_aso_en) {
+		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
+		if (ret)
+			goto error;
+		if (!priv->mtr_idx_tbl) {
+			priv->mtr_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+			if (!priv->mtr_idx_tbl)
+				goto error;
+		}
+		data.dword = mtr_idx;
+		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
+			goto error;
+	}
+	if (mtr_policy)
+		__atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
+	return 0;
+error:
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	/* Free policer counters. */
+	if (fm->drop_cnt)
+		mlx5_counter_free(dev, fm->drop_cnt);
+	if (priv->sh->meter_aso_en)
+		mlx5_flow_mtr_free(dev, mtr_idx);
+	else
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
+	return -rte_mtr_error_set(error, ENOTSUP,
+		RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+		NULL, "Failed to create devx meter.");
 }
 
 static int
@@ -912,6 +1157,7 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
+	struct mlx5_flow_meter_policy *mtr_policy;
 
 	/* Meter object must not have any owner. */
 	MLX5_ASSERT(!fm->ref_cnt);
@@ -921,9 +1167,11 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 		return -1;
 	/* Update dependencies. */
 	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
+	fm->profile = NULL;
 	/* Remove from list. */
 	if (!priv->sh->meter_aso_en) {
-		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
+		legacy_fm = container_of(fm,
+			struct mlx5_legacy_flow_meter, fm);
 		TAILQ_REMOVE(fms, legacy_fm, next);
 	}
 	/* Free drop counters. */
@@ -932,12 +1180,27 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 	/* Free meter flow table. */
 	if (fm->flow_ipool)
 		mlx5_ipool_destroy(fm->flow_ipool);
-	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-	if (priv->sh->meter_aso_en)
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	if (fm->policy_id == MLX5_MTR_DEFAULT_POLICY_ID) {
+		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_mtr_ref_cnt,
+				1, __ATOMIC_RELAXED);
+	}
+	if (priv->sh->meter_aso_en) {
+		if (fm->policy_id != MLX5_MTR_DEFAULT_POLICY_ID) {
+			mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+			if (mtr_policy)
+				__atomic_sub_fetch(&mtr_policy->ref_cnt,
+						1, __ATOMIC_RELAXED);
+			fm->policy_id = 0;
+		}
+		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
+			return -1;
 		mlx5_flow_mtr_free(dev, mtr_idx);
-	else
+	} else {
 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
 					legacy_fm->idx);
+	}
 	return 0;
 }
 
@@ -964,30 +1227,28 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
-					  NULL, "Meter object id not valid.");
+					  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.");
-	if (priv->sh->meter_aso_en) {
-		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id))
-			return -rte_mtr_error_set(error, EBUSY,
-				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Fail to delete ASO Meter in index table.");
-	}
+					  NULL,
+					  "Meter object is being used.");
 	/* Destroy the meter profile. */
 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
 		return -rte_mtr_error_set(error, EINVAL,
 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+					NULL,
+					"MTR object meter profile invalid.");
 	return 0;
 }
 
@@ -1221,7 +1482,11 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
 					  NULL, "Meter object id not valid.");
-	mlx5_flow_meter_stats_enable_update(fm, stats_mask);
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_MTR_ID,
+					  NULL, "Fail to allocate "
+					  "counter for meter.");
 	return 0;
 }
 
@@ -1299,6 +1564,7 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.meter_policy_validate = mlx5_flow_meter_policy_validate,
 	.meter_policy_create = mlx5_flow_meter_policy_create,
 	.meter_policy_delete = mlx5_flow_meter_policy_delete,
+	.create = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -1337,7 +1603,7 @@ mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
  *   Pointer to Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
@@ -1352,30 +1618,27 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 
 	if (priv->sh->meter_aso_en) {
 		rte_spinlock_lock(&pools_mng->mtrsl);
-		if (priv->mtr_idx_tbl) {
-			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
-				meter_id, &data) ||
-				!data.dword) {
-				rte_spinlock_unlock(&pools_mng->mtrsl);
-				return NULL;
-			}
-			if (mtr_idx)
-				*mtr_idx = data.dword;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-			/* Remove reference taken by the mlx5_l3t_get_entry. */
-			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		} else {
-			if (mtr_idx)
-				*mtr_idx = meter_id;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
+		if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
 		}
+		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
+			!data.dword) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
+		}
+		if (mtr_idx)
+			*mtr_idx = data.dword;
+		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+		/* Remove reference taken by the mlx5_l3t_get_entry. */
+		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
 		rte_spinlock_unlock(&pools_mng->mtrsl);
 		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
 			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
-		if (meter_id == legacy_fm->meter_id) {
+		if (meter_id == legacy_fm->fm.meter_id) {
 			if (mtr_idx)
 				*mtr_idx = legacy_fm->idx;
 			return &legacy_fm->fm;
@@ -1392,7 +1655,7 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
  *   Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
@@ -1401,6 +1664,8 @@ flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
 
 	if (priv->sh->meter_aso_en) {
 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
+		if (!aso_mtr)
+			return NULL;
 		return &aso_mtr->fm;
 	} else {
 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
-- 
2.27.0


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

* [dpdk-dev] [PATCH v2 3/4] net/mlx5: prepare sub-policy for a flow with meter
  2021-04-02 15:56 ` [dpdk-dev] [PATCH v2 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 1/4] " Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 2/4] net/mlx5: support meter creation with policy Li Zhang
@ 2021-04-02 15:56   ` Li Zhang
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-02 15:56 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

When a flow with RSS action, the MLX5 PMD split the flow
into several sub flow according to the flow RSS hashfield value,
each sub flow requested the different RSS TIR.

The new meter introduces the policy, for the meter flow with RSS
in the policy action, each RSS TIR in meter policy maintains
own sub-policy table resource.

This patch adds the function that find the correct policy table
resource according the RSS sub policy id.

Signed-off-by: Li Zhang <lizh@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.h    |  11 +++
 drivers/net/mlx5/mlx5_flow_dv.c | 136 ++++++++++++++++++++++++++++++++
 2 files changed, 147 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 5672df983e..3024bd9b60 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1075,6 +1075,11 @@ typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
 typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 				struct mlx5_flow_meter_info *fm);
 typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
+typedef struct mlx5_flow_meter_sub_policy *
+	(*mlx5_flow_meter_sub_policy_prepare_t)
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1167,6 +1172,7 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
 	mlx5_flow_create_def_policy_t create_def_policy;
 	mlx5_flow_destroy_def_policy_t destroy_def_policy;
+	mlx5_flow_meter_sub_policy_prepare_t meter_sub_policy_prepare;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1398,6 +1404,11 @@ int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
 void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_flow_meter_info *fm);
 void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
+
+struct mlx5_flow_meter_sub_policy *mlx5_flow_meter_sub_policy_prepare
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
 			  struct rte_mtr_error *error);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index adf7a8f1e7..b646b330ac 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -14713,6 +14713,141 @@ flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
 	return -1;
 }
 
+/**
+ * Find the policy table for prefix table with RSS.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ * @return
+ *   Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_dv_meter_sub_policy_prepare(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint32_t sub_policy_idx = 0;
+	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
+	uint32_t i, j;
+	struct mlx5_hrxq *hrxq;
+	struct mlx5_flow_handle dh;
+	struct mlx5_meter_policy_action_container *act_cnt;
+	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
+	uint16_t sub_policy_num;
+
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	MLX5_ASSERT(mtr_policy && mtr_policy->is_rss);
+	rte_spinlock_lock(&mtr_policy->sl);
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
+		if (!hrxq_idx[i]) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return NULL;
+		}
+	}
+	sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+	for (i = 0; i < sub_policy_num;
+		i++) {
+		for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) {
+			if (rss_desc[j] &&
+				hrxq_idx[j] !=
+			mtr_policy->sub_policys[domain][i]->rix_hrxq[j])
+				break;
+		}
+		if (j >= MLX5_MTR_RTE_COLORS) {
+			/*
+			 * Found the sub policy table with
+			 * the same queue per color
+			 */
+			rte_spinlock_unlock(&mtr_policy->sl);
+			for (j = 0; j < MLX5_MTR_RTE_COLORS; j++)
+				mlx5_hrxq_release(dev, hrxq_idx[j]);
+			return mtr_policy->sub_policys[domain][i];
+		}
+	}
+	/* Create sub policy. */
+	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
+		/* Reuse the first dummy sub_policy*/
+		sub_policy = mtr_policy->sub_policys[domain][0];
+		sub_policy_idx = sub_policy->idx;
+	} else {
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy ||
+			sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto rss_sub_policy_error;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		sub_policy->rix_hrxq[i] = hrxq_idx[i];
+		/*
+		 * Overwrite the last action from
+		 * RSS action to Queue action.
+		 */
+		hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+			      hrxq_idx[i]);
+		if (!hrxq) {
+			DRV_LOG(ERR, "Failed to create policy hrxq");
+			goto rss_sub_policy_error;
+		}
+		act_cnt = &mtr_policy->act_cnt[i];
+		if (act_cnt->rix_mark || act_cnt->modify_hdr) {
+			memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+			if (act_cnt->rix_mark)
+				dh.mark = 1;
+			dh.fate_action = MLX5_FLOW_FATE_QUEUE;
+			dh.rix_hrxq = hrxq_idx[i];
+			flow_drv_rxq_flags_set(dev, &dh);
+		}
+	}
+	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+		sub_policy, domain)) {
+		DRV_LOG(ERR, "Failed to create policy "
+			"rules per domain.");
+		goto rss_sub_policy_error;
+	}
+	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+		i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MARK;
+		mtr_policy->sub_policys[domain][i] = sub_policy;
+		i++;
+		if (i > MLX5_MTR_RSS_MAX_SUB_POLICY)
+			goto rss_sub_policy_error;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MARK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
+		mtr_policy->sub_policy_num |=
+			(i & MLX5_MTR_SUB_POLICY_NUM_MARK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return sub_policy;
+rss_sub_policy_error:
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
+		mlx5_hrxq_release(dev, hrxq_idx[i]);
+	if (sub_policy_idx)
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+			sub_policy_idx);
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return NULL;
+}
+
 /**
  * Validate the batch counter support in root table.
  *
@@ -15298,6 +15433,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
 	.create_def_policy = flow_dv_create_def_policy,
 	.destroy_def_policy = flow_dv_destroy_def_policy,
+	.meter_sub_policy_prepare = flow_dv_meter_sub_policy_prepare,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
-- 
2.27.0


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

* [dpdk-dev] [PATCH v2 4/4] net/mlx5: connect meter policy to created flows
  2021-04-02 15:56 ` [dpdk-dev] [PATCH v2 0/4] net/mlx5: support meter policy operations Li Zhang
                     ` (2 preceding siblings ...)
  2021-04-02 15:56   ` [dpdk-dev] [PATCH v2 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
@ 2021-04-02 15:56   ` Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-02 15:56 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs
  Cc: dev, thomas, rasland, roniba, Shun Hao

From: Shun Hao <shunh@nvidia.com>

Currently ASO meter must be followed by policy table, so this adds
the support that connecting meter and policy table.

There are several cases to be considered:
1. For non-termination policy, connect meter to the default policy
table.
2. For non-RSS termination policy case, simply get the policy
table id and connect meter to it.
3. For RSS termination policy case, need to split the flow due
to RSS info in policy, and translate each sub-flow using that RSS,
then create the sub policy table to be connected.
4. In termination policy case, if there's no actions to modify the
packet before meter, no need to use set_tag to save meter id in
register. Only add a new flow in drop table using the same match
criteria as suf-flow, to save cache miss.

Signed-off-by: Shun Hao <shunh@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.c    | 425 ++++++++++++++++++++++++++++----
 drivers/net/mlx5/mlx5_flow.h    |   9 +
 drivers/net/mlx5/mlx5_flow_dv.c |  24 +-
 3 files changed, 406 insertions(+), 52 deletions(-)

diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index b41bf6456d..56d0e480cb 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -3359,18 +3359,52 @@ flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 	fops->destroy(dev, flow);
 }
 
+/**
+ * Flow driver find RSS policy tbl API. This abstracts calling driver
+ * specific functions. Parent flow (rte_flow) should have driver
+ * type (drv_type). It will find the RSS policy table that has the rss_desc.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in, out] flow
+ *   Pointer to flow structure.
+ * @param[in] policy_id
+ *   The policy id of a meter.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_drv_meter_sub_policy_prepare(struct rte_eth_dev *dev,
+		struct rte_flow *flow,
+		uint32_t policy_id,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	const struct mlx5_flow_driver_ops *fops;
+	enum mlx5_flow_drv_type type = flow->drv_type;
+
+	MLX5_ASSERT(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
+	fops = flow_get_drv_ops(type);
+	return fops->meter_sub_policy_prepare(dev, policy_id, rss_desc);
+}
+
 /**
  * Get RSS action from the action list.
  *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
+ * @param[in] flow
+ *   Parent flow structure pointer.
  *
  * @return
  *   Pointer to the RSS action if exist, else return NULL.
  */
 static const struct rte_flow_action_rss*
-flow_get_rss_action(const struct rte_flow_action actions[])
+flow_get_rss_action(struct rte_eth_dev *dev,
+		    const struct rte_flow_action actions[])
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
 	const struct rte_flow_action_rss *rss = NULL;
 
 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -3388,6 +3422,23 @@ flow_get_rss_action(const struct rte_flow_action actions[])
 					rss = act->conf;
 			break;
 		}
+		case RTE_FLOW_ACTION_TYPE_METER:
+		{
+			uint32_t mtr_idx;
+			struct mlx5_flow_meter_info *fm;
+			struct mlx5_flow_meter_policy *policy;
+			const struct rte_flow_action_meter *mtr = actions->conf;
+
+			fm = mlx5_flow_meter_find(priv, mtr->mtr_id, &mtr_idx);
+			if (fm) {
+				policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+				if (policy && policy->is_rss)
+					rss =
+				policy->act_cnt[RTE_COLOR_GREEN].rss->conf;
+			}
+			break;
+		}
 		default:
 			break;
 		}
@@ -3686,6 +3737,55 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
 	return actions_n + 1;
 }
 
+/**
+ * Check if the action will change packet.
+ *
+ * @param[in] type
+ *   action type.
+ *
+ * @return
+ *   true if action will change packet, false otherwise.
+ */
+static bool flow_check_modify_action_type(enum rte_flow_action_type type)
+{
+	switch (type) {
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
+	case RTE_FLOW_ACTION_TYPE_DEC_TTL:
+	case RTE_FLOW_ACTION_TYPE_SET_TTL:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
+	case RTE_FLOW_ACTION_TYPE_FLAG:
+	case RTE_FLOW_ACTION_TYPE_MARK:
+	case RTE_FLOW_ACTION_TYPE_SET_META:
+	case RTE_FLOW_ACTION_TYPE_SET_TAG:
+	case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+	case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
+		return true;
+	default:
+		return false;
+	}
+}
+
 /**
  * Check meter action from the action list.
  *
@@ -3693,6 +3793,8 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
  *   Pointer to the list of actions.
  * @param[out] has_mtr
  *   Pointer to the meter exist flag.
+ * @param[out] has_modify
+ *   Pointer to the flag showing there's packet change action.
  * @param[out] meter_id
  *   Pointer to the meter id.
  *
@@ -3701,8 +3803,7 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
  */
 static int
 flow_check_meter_action(const struct rte_flow_action actions[],
-			bool *has_mtr,
-			uint32_t *meter_id)
+			bool *has_mtr, bool *has_modify, uint32_t *meter_id)
 {
 	const struct rte_flow_action_meter *mtr = NULL;
 	int actions_n = 0;
@@ -3719,6 +3820,9 @@ flow_check_meter_action(const struct rte_flow_action actions[],
 		default:
 			break;
 		}
+		if (!*has_mtr)
+			*has_modify |=
+				flow_check_modify_action_type(actions->type);
 		actions_n++;
 	}
 	/* Count RTE_FLOW_ACTION_TYPE_END. */
@@ -4361,6 +4465,112 @@ flow_create_split_inner(struct rte_eth_dev *dev,
 	return flow_drv_translate(dev, dev_flow, attr, items, actions, error);
 }
 
+/**
+ * Get the table id of meter policy table.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
+ * @param[in] policy_id;
+ *   Meter Policy id.
+ * @param[in] attr
+ *   Flow rule attributes.
+ * @param[in] items
+ *   Pattern specification (list terminated by the END pattern item).
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   The table id, 0 otherwise and rte_errno is set.
+ */
+static uint32_t
+get_sub_policy_tbl_id(struct rte_eth_dev *dev,
+		      struct rte_flow *flow,
+		      uint32_t policy_id,
+		      const struct rte_flow_attr *attr,
+		      const struct rte_flow_item items[],
+		      struct rte_flow_error *error)
+{
+	uint32_t policy_tbl_id = 0;
+	struct mlx5_flow_meter_policy *policy;
+
+	policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	if (!policy) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Failed to find Meter Policy.");
+		goto exit;
+	}
+	if (policy->is_rss) {
+		struct mlx5_flow_workspace *wks =
+				mlx5_flow_get_thread_workspace();
+		struct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};
+		struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+		uint32_t i;
+
+		MLX5_ASSERT(wks);
+		/** This is a tmp dev_flow,
+		 *  no need to register any matcher for it in translate.
+		 */
+		wks->skip_matcher_reg = 1;
+		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+			struct mlx5_flow dev_flow = {0};
+			struct mlx5_flow_handle dev_handle = {{0}};
+			const void *rss_act = policy->act_cnt[i].rss->conf;
+			struct rte_flow_action rss_actions[2] = {
+				[0] = {
+					.type = RTE_FLOW_ACTION_TYPE_RSS,
+					.conf = rss_act
+				},
+				[1] = {
+					.type = RTE_FLOW_ACTION_TYPE_END,
+					.conf = NULL
+				}
+			};
+
+			dev_flow.handle = &dev_handle;
+			dev_flow.ingress = attr->ingress;
+			dev_flow.flow = flow;
+			dev_flow.external = 0;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+			dev_flow.dv.transfer = attr->transfer;
+#endif
+			/* Translate RSS action to get rss hash fields. */
+			if (flow_drv_translate(dev, &dev_flow, attr,
+						items, rss_actions, error))
+				goto exit;
+			rss_desc_v[i] = wks->rss_desc;
+			rss_desc_v[i].key_len = MLX5_RSS_HASH_KEY_LEN;
+			rss_desc_v[i].hash_fields = dev_flow.hash_fields;
+			rss_desc_v[i].queue_num = rss_desc_v[i].hash_fields ?
+						  rss_desc_v[i].queue_num : 1;
+			rss_desc[i] = &rss_desc_v[i];
+		}
+		sub_policy = flow_drv_meter_sub_policy_prepare(dev,
+						flow, policy_id, rss_desc);
+		if (!sub_policy) {
+			rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Failed to get meter RSS policy table.");
+			goto exit;
+		}
+		policy_tbl_id = sub_policy->idx;
+	} else {
+		enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+		policy_tbl_id =
+			policy->sub_policys[mtr_domain][0]->idx;
+	}
+exit:
+	return policy_tbl_id;
+}
+
+#define MLX5_MTR_PRE_TAG_NUM 2
+
 /**
  * Split the meter flow.
  *
@@ -4391,13 +4601,15 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *   Suffix flow actions.
  * @param[out] actions_pre
  *   Prefix flow actions.
+ * @param[out] mtr_flow_id
+ *   Pointer to meter flow id.
  * @param[out] error
  *   Perform verbose error reporting if not NULL.
  *
  * @return
- *   The flow id, 0 otherwise and rte_errno is set.
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
-static uint32_t
+static int
 flow_meter_split_prep(struct rte_eth_dev *dev,
 		      struct rte_flow *flow,
 		      struct mlx5_flow_meter_info *fm,
@@ -4407,6 +4619,7 @@ 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[],
+		      uint32_t *mtr_flow_id,
 		      struct rte_flow_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
@@ -4420,7 +4633,7 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	uint32_t tag_id = 0;
 	bool copy_vlan = false;
 	struct rte_flow_action *hw_mtr_action;
-	struct rte_flow_action_jump *jump_data;
+	struct mlx5_rte_flow_item_mtr_jump *jump_data;
 	struct rte_flow_action *action_pre_head = NULL;
 	bool mtr_first = priv->sh->meter_aso_en &&
 			 (attr->egress ||
@@ -4429,8 +4642,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
 				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
 	uint8_t flow_id_bits = 0;
-	int shift;
-	uint32_t flow_id_val = 0;
 
 	/* For ASO meter, meter must be before tag in TX direction. */
 	if (mtr_first) {
@@ -4474,7 +4685,9 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 			break;
 		}
 		if (!action_cur)
-			action_cur = actions_sfx++;
+			action_cur =
+				(fm->policy_id != MLX5_MTR_DEFAULT_POLICY_ID) ?
+					actions_pre++ : actions_sfx++;
 		memcpy(action_cur, actions, sizeof(struct rte_flow_action));
 	}
 	/* Add end action to the actions. */
@@ -4483,37 +4696,56 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		/** For ASO meter, need to add an extra jump action explicitly,
 		 *  to jump from meter to policer table.
 		 */
+		uint32_t sub_policy_tbl_id = 0;
+
+		if (fm->policy_id != MLX5_MTR_DEFAULT_POLICY_ID) {
+			sub_policy_tbl_id =
+				get_sub_policy_tbl_id(dev, flow, fm->policy_id,
+						      attr, items, error);
+			if (!sub_policy_tbl_id)
+				return -rte_errno;
+		}
 		hw_mtr_action = actions_pre;
-		hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
+		hw_mtr_action->type = (enum rte_flow_action_type)
+				      MLX5_RTE_FLOW_ACTION_TYPE_MTR_JUMP;
 		actions_pre++;
 		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
 		actions_pre++;
-		jump_data = (struct rte_flow_action_jump *)actions_pre;
-		jump_data->group = attr->transfer ?
+		jump_data = (struct mlx5_rte_flow_item_mtr_jump *)actions_pre;
+		jump_data->table_group.group = attr->transfer ?
 				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
 				 MLX5_FLOW_TABLE_LEVEL_POLICY;
+		jump_data->table_id = sub_policy_tbl_id;
 		hw_mtr_action->conf = jump_data;
 		actions_pre = (struct rte_flow_action *)(jump_data + 1);
 	} else {
 		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
 		actions_pre++;
 	}
-	/* Generate meter flow_id only if support multiple flows per meter. */
-	mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
-	if (!tag_id)
-		return rte_flow_error_set(error, ENOMEM,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Failed to allocate meter flow id.");
-	flow_id_bits = MLX5_REG_BITS - __builtin_clz(tag_id - 1);
-	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
-		mlx5_ipool_free(fm->flow_ipool, tag_id);
-		return rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Meter flow id exceeds max limit.");
+	MLX5_ASSERT(tag_action);
+	if (!mtr_flow_id) {
+		tag_action->type = RTE_FLOW_ACTION_TYPE_VOID;
+		goto exit;
+	}
+	/* Only Non-termination Policy Meter creates mtr flow id. */
+	if (fm->policy_id == MLX5_MTR_DEFAULT_POLICY_ID) {
+		mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
+		if (!tag_id)
+			return rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to allocate meter flow id.");
+		flow_id_bits = MLX5_REG_BITS - __builtin_clz(tag_id - 1);
+		flow_id_bits = flow_id_bits ? flow_id_bits : 1;
+		if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) >
+		    mtr_reg_bits) {
+			mlx5_ipool_free(fm->flow_ipool, tag_id);
+			return rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter flow id exceeds max limit.");
+		}
+		if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+			priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	}
-	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
-		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -4543,7 +4775,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
 	sfx_items++;
 	/* Build tag actions and items for meter_id/meter flow_id. */
-	assert(tag_action);
 	set_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;
 	tag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;
 	tag_item_mask = tag_item_spec + 1;
@@ -4554,14 +4785,19 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		.length = mtr_reg_bits,
 		.data = flow->meter,
 	};
-	/*
-	 * The color Reg bits used by flow_id are growing from
-	 * msb to lsb, so must do bit reverse for flow_id val in RegC.
-	 */
-	for (shift = 0; shift < flow_id_bits; shift++)
-		flow_id_val = (flow_id_val << 1) |
-			      (((tag_id - 1) >> shift) & 0x1);
-	set_tag->data |= flow_id_val << (mtr_reg_bits - flow_id_bits);
+	if (tag_id) {
+		int shift;
+		uint32_t flow_id_val = 0;
+
+		/*
+		 * The color Reg bits used by flow_id are growing from
+		 * msb to lsb, so must do bit reverse for flow_id val in RegC.
+		 */
+		for (shift = 0; shift < flow_id_bits; shift++)
+			flow_id_val = (flow_id_val << 1) |
+					(((tag_id - 1) >> shift) & 0x1);
+		set_tag->data |= flow_id_val << (mtr_reg_bits - flow_id_bits);
+	}
 	tag_item_spec->id = set_tag->id;
 	tag_item_spec->data = set_tag->data << mtr_id_offset;
 	tag_item_mask->data = UINT32_MAX << mtr_id_offset;
@@ -4573,7 +4809,10 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	tag_item->spec = tag_item_spec;
 	tag_item->last = NULL;
 	tag_item->mask = tag_item_mask;
-	return tag_id;
+exit:
+	if (mtr_flow_id)
+		*mtr_flow_id = tag_id;
+	return 0;
 }
 
 /**
@@ -5237,6 +5476,57 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/**
+ * Create the Termination Policy Meter drop 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] flow_split_info
+ *   Pointer to flow split info structure.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   0 on success, negative value otherwise
+ */
+static uint32_t
+flow_meter_create_drop_flow_with_org_pattern(struct rte_eth_dev *dev,
+			struct rte_flow *flow,
+			const struct rte_flow_attr *attr,
+			const struct rte_flow_item items[],
+			struct mlx5_flow_split_info *flow_split_info,
+			struct mlx5_flow_meter_info *fm,
+			struct rte_flow_error *error)
+{
+	struct mlx5_flow *dev_flow = NULL;
+	struct rte_flow_attr drop_attr = *attr;
+	struct rte_flow_action drop_actions[3] = {{0}};
+	struct mlx5_flow_split_info drop_split_info = *flow_split_info;
+
+	MLX5_ASSERT(fm->drop_cnt);
+	drop_actions[0].type =
+		(enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_MTR_COUNT;
+	drop_actions[0].conf =
+		(void *)(uintptr_t)fm->drop_cnt;
+	drop_actions[1].type =
+		RTE_FLOW_ACTION_TYPE_DROP;
+	drop_actions[2].type =
+		RTE_FLOW_ACTION_TYPE_END;
+	drop_split_info.external = false;
+	drop_split_info.skip_scale |= 1 << MLX5_SCALE_FLOW_GROUP_BIT;
+	drop_attr.group = MLX5_FLOW_TABLE_LEVEL_METER_DROP;
+	return flow_create_split_inner(dev, flow, &dev_flow,
+				&drop_attr, items, drop_actions,
+				&drop_split_info, error);
+}
+
 /**
  * The splitting for meter feature.
  *
@@ -5281,10 +5571,13 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 	struct mlx5_flow *dev_flow = NULL;
 	struct rte_flow_attr sfx_attr = *attr;
 	struct mlx5_flow_meter_info *fm = NULL;
+	uint8_t skip_scale_restore;
 	bool has_mtr = false;
-	uint32_t meter_id;
+	bool has_modify = false;
+	bool set_mtr_reg = true;
+	uint32_t meter_id = 0;
 	uint32_t mtr_idx = 0;
-	uint32_t mtr_tag_id = 0;
+	uint32_t mtr_flow_id = 0;
 	size_t act_size;
 	size_t item_size;
 	int actions_n = 0;
@@ -5292,7 +5585,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 
 	if (priv->mtr_en)
 		actions_n = flow_check_meter_action(actions, &has_mtr,
-						    &meter_id);
+						    &has_modify, &meter_id);
 	if (has_mtr) {
 		if (flow->meter) {
 			fm = flow_dv_meter_find_by_idx(priv, flow->meter);
@@ -5312,7 +5605,18 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 				return -rte_errno;
 			flow->meter = mtr_idx;
 		}
+		MLX5_ASSERT(wks);
 		wks->fm = fm;
+		/*
+		 * If it's Termination Policy Meter, and
+		 * 1. There's no action in flow to change
+		 *    packet (modify/encap/decap etc.), OR
+		 * 2. No drop count needed for this meter.
+		 * no need to use regC to save meter id anymore.
+		 */
+		if (fm->policy_id != MLX5_MTR_DEFAULT_POLICY_ID &&
+		    (!has_modify || !fm->drop_cnt))
+			set_mtr_reg = false;
 		/* Prefix actions: meter, decap, encap, tag, jump, end. */
 		act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
 			   sizeof(struct mlx5_rte_flow_action_set_tag);
@@ -5329,27 +5633,48 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 						  "meter flow");
 		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
 			     act_size);
-		pre_actions = sfx_actions + actions_n;
-		mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
-						   items, sfx_items, actions,
-						   sfx_actions, pre_actions,
-						   error);
-		if (!mtr_tag_id) {
+		/* There's no suffix flow for Termination Policy Meter. */
+		if (fm->policy_id != MLX5_MTR_DEFAULT_POLICY_ID)
+			pre_actions = sfx_actions + 1;
+		else
+			pre_actions = sfx_actions + actions_n;
+		ret = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+					    items, sfx_items, actions,
+					    sfx_actions, pre_actions,
+					    (set_mtr_reg ? &mtr_flow_id : NULL),
+					    error);
+		if (ret) {
 			ret = -rte_errno;
 			goto exit;
 		}
 		/* Add the prefix subflow. */
 		flow_split_info->prefix_mark = 0;
+		skip_scale_restore = flow_split_info->skip_scale;
+		flow_split_info->skip_scale |=
+			1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT;
 		ret = flow_create_split_inner(dev, flow, &dev_flow,
 					      attr, items, pre_actions,
 					      flow_split_info, error);
 		if (ret) {
-			mlx5_ipool_free(fm->flow_ipool, mtr_tag_id);
+			if (mtr_flow_id)
+				mlx5_ipool_free(fm->flow_ipool, mtr_flow_id);
 			ret = -rte_errno;
 			goto exit;
 		}
-		dev_flow->handle->split_flow_id = mtr_tag_id;
-		dev_flow->handle->is_meter_flow_id = 1;
+		flow_split_info->skip_scale = skip_scale_restore;
+		if (mtr_flow_id) {
+			dev_flow->handle->split_flow_id = mtr_flow_id;
+			dev_flow->handle->is_meter_flow_id = 1;
+		}
+		if (fm->policy_id != MLX5_MTR_DEFAULT_POLICY_ID) {
+			if (!set_mtr_reg && fm->drop_cnt)
+				ret =
+			flow_meter_create_drop_flow_with_org_pattern(dev, flow,
+							&sfx_attr, items,
+							flow_split_info,
+							fm, error);
+			goto exit;
+		}
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
 				(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
@@ -5743,7 +6068,7 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,
 	memset(rss_desc, 0, offsetof(struct mlx5_flow_rss_desc, queue));
 	/* RSS Action only works on NIC RX domain */
 	if (attr->ingress && !attr->transfer)
-		rss = flow_get_rss_action(p_actions_rx);
+		rss = flow_get_rss_action(dev, p_actions_rx);
 	if (rss) {
 		if (flow_rss_workspace_adjust(wks, rss_desc, rss->queue_num))
 			return 0;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 3024bd9b60..cdbaf95085 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -37,6 +37,8 @@ enum mlx5_rte_flow_action_type {
 	MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS,
 	MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET,
 	MLX5_RTE_FLOW_ACTION_TYPE_AGE,
+	MLX5_RTE_FLOW_ACTION_TYPE_MTR_JUMP,
+	MLX5_RTE_FLOW_ACTION_TYPE_MTR_COUNT,
 };
 
 #define MLX5_SHARED_ACTION_TYPE_OFFSET 30
@@ -70,6 +72,11 @@ struct mlx5_rte_flow_item_tx_queue {
 	uint32_t queue;
 };
 
+struct mlx5_rte_flow_item_mtr_jump {
+	struct rte_flow_action_jump table_group;
+	uint32_t table_id;
+};
+
 /* Feature name to allocate metadata register. */
 enum mlx5_feature_name {
 	MLX5_HAIRPIN_RX,
@@ -1029,6 +1036,8 @@ struct mlx5_flow_workspace {
 	uint32_t rssq_num; /* Allocated queue num in rss_desc. */
 	uint32_t flow_idx; /* Intermediate device flow index. */
 	struct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */
+	uint32_t skip_matcher_reg:1;
+	/* Indicates if need to skip matcher register in translate. */
 };
 
 struct mlx5_flow_split_info {
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index b646b330ac..9f5945379e 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7409,6 +7409,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,
 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
 
 	MLX5_ASSERT(wks);
+	wks->skip_matcher_reg = 0;
 	/* In case of corrupting the memory. */
 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
 		rte_flow_error_set(error, ENOSPC,
@@ -11252,6 +11253,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
 		int action_type = actions->type;
 		const struct rte_flow_action *found_action = NULL;
 		uint32_t jump_group = 0;
+		uint32_t jump_table_id = 0;
+		struct mlx5_flow_counter *cnt;
 
 		if (!mlx5_flow_os_action_supported(action_type))
 			return rte_flow_error_set(error, ENOTSUP,
@@ -11432,6 +11435,15 @@ flow_dv_translate(struct rte_eth_dev *dev,
 				age = action->conf;
 			action_flags |= MLX5_FLOW_ACTION_COUNT;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_MTR_COUNT:
+			cnt = flow_dv_counter_get_by_idx(dev,
+				(uint32_t)(uintptr_t)action->conf, NULL);
+			if (!cnt)
+				return rte_flow_error_set(error, rte_errno,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+					NULL, "Failed to get meter counter.");
+			dev_flow->dv.actions[actions_n++] = cnt->action;
+			break;
 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
 			dev_flow->dv.actions[actions_n++] =
 						priv->sh->pop_vlan_action;
@@ -11536,6 +11548,11 @@ flow_dv_translate(struct rte_eth_dev *dev,
 			/* If decap is followed by encap, handle it at encap. */
 			action_flags |= MLX5_FLOW_ACTION_DECAP;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_MTR_JUMP:
+			jump_table_id =
+				((const struct mlx5_rte_flow_item_mtr_jump *)
+				 action->conf)->table_id;
+			/* Fall through */
 		case RTE_FLOW_ACTION_TYPE_JUMP:
 			jump_group = ((const struct rte_flow_action_jump *)
 							action->conf)->group;
@@ -11555,7 +11572,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
 						       attr->transfer,
 						       !!dev_flow->external,
 						       tunnel, jump_group, 0,
-						       0, error);
+						       jump_table_id, error);
 			if (!tbl)
 				return rte_flow_error_set
 						(error, errno,
@@ -12091,6 +12108,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
 	}
 	dev_flow->dv.actions_n = actions_n;
 	dev_flow->act_flags = action_flags;
+	if (wks->skip_matcher_reg)
+		return 0;
 	/* Register matcher. */
 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
 				    matcher.mask.size);
@@ -12242,7 +12261,8 @@ flow_dv_apply(struct rte_eth_dev *dev, struct rte_flow *flow,
 		dv_h = &dh->dvh;
 		n = dv->actions_n;
 		if (dh->fate_action == MLX5_FLOW_FATE_DROP) {
-			if (dv->transfer) {
+			if (dv->transfer || dev_flow->dv.group ==
+			    MLX5_FLOW_TABLE_LEVEL_METER_DROP) {
 				dv->actions[n++] = priv->sh->esw_drop_action;
 			} else {
 				MLX5_ASSERT(priv->drop_queue.hrxq);
-- 
2.27.0


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

* [dpdk-dev] [PATCH v3 0/4] net/mlx5: support meter policy operations
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (4 preceding siblings ...)
  2021-04-02 15:56 ` [dpdk-dev] [PATCH v2 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-13  0:19 ` Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 1/4] " Li Zhang
                     ` (3 more replies)
  2021-04-14  6:40 ` [dpdk-dev] [PATCH v4 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (4 subsequent siblings)
  10 siblings, 4 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-13  0:19 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Depends-on: series=16300  ("Add ASO meter support in MLX5 PMD ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16300

Depends-on: series=16301  ("Support meter policy API ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16301

V2: Add MLX5_MTR_DEFAULT_POLICY_ID in MLX5 PMD
V3: Fix comments.

Li Zhang (3):
  net/mlx5: support meter policy operations
  net/mlx5: support meter creation with policy
  net/mlx5: prepare sub-policy for a flow with meter

Shun Hao (1):
  net/mlx5: connect meter policy to created flows

 doc/guides/nics/mlx5.rst           |   12 +
 drivers/net/mlx5/linux/mlx5_os.c   |   13 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  212 +++-
 drivers/net/mlx5/mlx5_flow.c       |  654 ++++++++--
 drivers/net/mlx5/mlx5_flow.h       |  119 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1896 ++++++++++++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_meter.c |  728 ++++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 10 files changed, 3365 insertions(+), 357 deletions(-)

-- 
2.27.0


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

* [dpdk-dev] [PATCH v3 1/4] net/mlx5: support meter policy operations
  2021-04-13  0:19 ` [dpdk-dev] [PATCH v3 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-13  0:19   ` Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 2/4] net/mlx5: support meter creation with policy Li Zhang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-13  0:19 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

Implement the next policy operations:
validate:
The driver doesn't support to configure actions in the flow
after the meter action except one case when the meter policy
is configured to do nothing in GREEN\YELLOW and only DROP action
in RED, this special policy is called non-terminated policy
and is handed as a singleton object internally.

For all the terminated policies, the next actions are supported:
GREEN - QUEUE, RSS, PORT_ID, JUMP, DROP, MARK and SET_TAG.
YELLOW - not supported at all -> must be empty.
RED - must include DROP action.

Hence, in ingress case, for example,
QUEUE\RSS\JUMP must be configured as last action for GREEN color.

All the above limitations will be validated.

create:
Validate the policy configuration.
Prepare the related tables and actions.

destroy:
Release the created policy resources.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |    2 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  158 +++-
 drivers/net/mlx5/mlx5_flow.c       |  192 +++-
 drivers/net/mlx5/mlx5_flow.h       |   73 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1412 +++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c |  445 ++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 9 files changed, 2242 insertions(+), 128 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index bec288c840..276283d492 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1299,7 +1299,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			log_obj_size <=
 			config->hca_attr.qos.log_meter_aso_max_alloc) {
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv);
+				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
 				if (err) {
 					err = -err;
 					goto error;
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 048cb259d2..54b1df79b7 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -350,6 +350,20 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {
 		.free = mlx5_free,
 		.type = "mlx5_shared_action_rss",
 	},
+	[MLX5_IPOOL_MTR_POLICY] = {
+		/**
+		 * The ipool index should grow continually from small to big,
+		 * for policy idx, so not set grow_trunk to avoid policy index
+		 * not jump continually.
+		 */
+		.size = sizeof(struct mlx5_flow_meter_sub_policy),
+		.trunk_size = 64,
+		.need_lock = 1,
+		.release_mem_en = 1,
+		.malloc = mlx5_malloc,
+		.free = mlx5_free,
+		.type = "mlx5_meter_policy_ipool",
+	},
 };
 
 
@@ -569,27 +583,25 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh)
  *   Pointer to mlx5_dev_ctx_shared object to free
  */
 int
-mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv)
+mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!priv->mtr_idx_tbl) {
-		priv->mtr_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
-		if (!priv->mtr_idx_tbl) {
-			DRV_LOG(ERR, "fail to create meter lookup table.");
-			rte_errno = ENOMEM;
-			return -ENOMEM;
-		}
-	}
-	if (!priv->sh->mtrmng) {
-		priv->sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
-			sizeof(*priv->sh->mtrmng),
+	if (!sh->mtrmng) {
+		sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(*sh->mtrmng),
 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
-		if (!priv->sh->mtrmng) {
-			DRV_LOG(ERR, "mlx5_aso_mtr_pools_mng allocation was failed.");
+		if (!sh->mtrmng) {
+			DRV_LOG(ERR,
+			"meter management allocation was failed.");
 			rte_errno = ENOMEM;
 			return -ENOMEM;
 		}
-		rte_spinlock_init(&priv->sh->mtrmng->mtrsl);
-		LIST_INIT(&priv->sh->mtrmng->meters);
+		if (sh->meter_aso_en) {
+			rte_spinlock_init(&sh->mtrmng->pools_mng.mtrsl);
+			LIST_INIT(&sh->mtrmng->pools_mng.meters);
+			sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		}
+		sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
 	}
 	return 0;
 }
@@ -605,31 +617,34 @@ static void
 mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
 {
 	struct mlx5_aso_mtr_pool *mtr_pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng;
+	struct mlx5_flow_mtr_mng *mtrmng = sh->mtrmng;
 	uint32_t idx;
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
 	struct mlx5_aso_mtr *aso_mtr;
 	int i;
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
 
-	mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
-	idx = mtrmng->n_valid;
-	while (idx--) {
-		mtr_pool = mtrmng->pools[idx];
+	if (sh->meter_aso_en) {
+		mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
+		idx = mtrmng->pools_mng.n_valid;
+		while (idx--) {
+			mtr_pool = mtrmng->pools_mng.pools[idx];
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
-		for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
-			aso_mtr = &mtr_pool->mtrs[i];
-			if (aso_mtr->fm.meter_action)
-				claim_zero(mlx5_glue->destroy_flow_action
-						(aso_mtr->fm.meter_action));
-		}
+			for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
+				aso_mtr = &mtr_pool->mtrs[i];
+				if (aso_mtr->fm.meter_action)
+					claim_zero
+					(mlx5_glue->destroy_flow_action
+					(aso_mtr->fm.meter_action));
+			}
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
-		claim_zero(mlx5_devx_cmd_destroy
+			claim_zero(mlx5_devx_cmd_destroy
 						(mtr_pool->devx_obj));
-		mtrmng->n_valid--;
-		mlx5_free(mtr_pool);
+			mtrmng->pools_mng.n_valid--;
+			mlx5_free(mtr_pool);
+		}
+		mlx5_free(sh->mtrmng->pools_mng.pools);
 	}
-	mlx5_free(sh->mtrmng->pools);
 	mlx5_free(sh->mtrmng);
 	sh->mtrmng = NULL;
 }
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index a8e11023cc..cb7c75aa2e 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -56,6 +56,7 @@ enum mlx5_ipool_index {
 	MLX5_IPOOL_RTE_FLOW, /* Pool for rte_flow. */
 	MLX5_IPOOL_RSS_EXPANTION_FLOW_ID, /* Pool for Queue/RSS flow ID. */
 	MLX5_IPOOL_RSS_SHARED_ACTIONS, /* Pool for RSS shared actions. */
+	MLX5_IPOOL_MTR_POLICY, /* Pool for meter policy resource. */
 	MLX5_IPOOL_MAX,
 };
 
@@ -580,9 +581,126 @@ struct mlx5_dev_shared_port {
 	/* Aging information for per port. */
 };
 
+/*
+ * Max number of actions per DV flow.
+ * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
+ * in rdma-core file providers/mlx5/verbs.c.
+ */
+#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
+
 /*ASO flow meter structures*/
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
+/* Yellow is not supported. */
+#define MLX5_MTR_RTE_COLORS (RTE_COLOR_GREEN + 1)
+/* table_id 22 bits in mlx5_flow_tbl_key so limit policy number. */
+#define MLX5_MAX_SUB_POLICY_TBL_NUM 0x3FFFFF
+#define MLX5_INVALID_POLICY_ID UINT32_MAX
+/* Suffix table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_SUFFIX 1
+/* Drop table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_DROP 2
+
+enum mlx5_meter_domain {
+	MLX5_MTR_DOMAIN_INGRESS,
+	MLX5_MTR_DOMAIN_EGRESS,
+	MLX5_MTR_DOMAIN_TRANSFER,
+	MLX5_MTR_DOMAIN_MAX,
+};
+#define MLX5_MTR_DOMAIN_INGRESS_BIT  (1 << MLX5_MTR_DOMAIN_INGRESS)
+#define MLX5_MTR_DOMAIN_EGRESS_BIT   (1 << MLX5_MTR_DOMAIN_EGRESS)
+#define MLX5_MTR_DOMAIN_TRANSFER_BIT (1 << MLX5_MTR_DOMAIN_TRANSFER)
+#define MLX5_MTR_ALL_DOMAIN_BIT      (MLX5_MTR_DOMAIN_INGRESS_BIT | \
+					MLX5_MTR_DOMAIN_EGRESS_BIT | \
+					MLX5_MTR_DOMAIN_TRANSFER_BIT)
+
+/*
+ * Meter sub-policy structure.
+ * Each RSS TIR in meter policy need its own sub-policy resource.
+ */
+struct mlx5_flow_meter_sub_policy {
+	uint32_t main_policy_id:1;
+	/* Main policy id is same as this sub_policy id. */
+	uint32_t idx:31;
+	/* Index to sub_policy ipool entity. */
+	void *main_policy;
+	/* Point to struct mlx5_flow_meter_policy. */
+	struct mlx5_flow_tbl_resource *tbl_rsc;
+	/* The sub-policy table resource. */
+	uint32_t rix_hrxq[MLX5_MTR_RTE_COLORS];
+	/* Index to TIR resource. */
+	struct mlx5_flow_tbl_resource *jump_tbl[MLX5_MTR_RTE_COLORS];
+	/* Meter jump/drop table. */
+	struct mlx5_flow_dv_matcher *color_matcher[RTE_COLORS];
+	/* Matcher for Color. */
+	void *color_rule[RTE_COLORS];
+	/* Meter green/yellow/drop rule. */
+};
+
+struct mlx5_meter_policy_acts {
+	uint8_t actions_n;
+	/* Number of actions. */
+	void *dv_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS];
+	/* Action list. */
+};
+
+struct mlx5_meter_policy_action_container {
+	uint32_t rix_mark;
+	/* Index to the mark action. */
+	struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
+	/* Pointer to modify header resource in cache. */
+	uint8_t fate_action;
+	/* Fate action type. */
+	union {
+		struct rte_flow_action *rss;
+		/* Rss action configuration. */
+		uint32_t rix_port_id_action;
+		/* Index to port ID action resource. */
+		void *dr_jump_action[MLX5_MTR_DOMAIN_MAX];
+		/* Jump/drop action per color. */
+	};
+};
+
+/* Flow meter policy parameter structure. */
+struct mlx5_flow_meter_policy {
+	uint32_t is_rss:1;
+	/* Is RSS policy table. */
+	uint32_t ingress:1;
+	/* Rule applies to ingress domain. */
+	uint32_t egress:1;
+	/* Rule applies to egress domain. */
+	uint32_t transfer:1;
+	/* Rule applies to transfer domain. */
+	rte_spinlock_t sl;
+	uint32_t ref_cnt;
+	/* Use count. */
+	struct mlx5_meter_policy_action_container act_cnt[MLX5_MTR_RTE_COLORS];
+	/* Policy actions container. */
+	void *dr_drop_action[MLX5_MTR_DOMAIN_MAX];
+	/* drop action for red color. */
+	uint16_t sub_policy_num;
+	/* Count sub policy tables, 3 bits per domain. */
+	struct mlx5_flow_meter_sub_policy **sub_policys[MLX5_MTR_DOMAIN_MAX];
+	/* Sub policy table array must be the end of struct. */
+};
+
+/* The maximum sub policy is relate to struct mlx5_rss_hash_fields[]. */
+#define MLX5_MTR_RSS_MAX_SUB_POLICY 7
+#define MLX5_MTR_SUB_POLICY_NUM_SHIFT  3
+#define MLX5_MTR_SUB_POLICY_NUM_MASK  0x7
+#define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
+
+/* Flow meter default policy parameter structure.
+ * Policy index 0 is reserved by default policy table.
+ * Action per color as below:
+ * green - do nothing, yellow - do nothing, red - drop
+ */
+struct mlx5_flow_meter_def_policy {
+	struct mlx5_flow_meter_sub_policy sub_policy;
+	/* Policy rules jump to other tables. */
+	void *dr_jump_action[RTE_COLORS];
+	/* Jump action per color. */
+};
 
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
@@ -746,6 +864,28 @@ struct mlx5_aso_mtr_pools_mng {
 	struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */
 };
 
+/* Meter management structure for global flow meter resource. */
+struct mlx5_flow_mtr_mng {
+	struct mlx5_aso_mtr_pools_mng pools_mng;
+	/* Pools management structure for ASO flow meter pools. */
+	struct mlx5_flow_meter_def_policy *def_policy[MLX5_MTR_DOMAIN_MAX];
+	/* Default policy table. */
+	uint32_t def_policy_id;
+	/* Default policy id. */
+	uint32_t def_policy_ref_cnt;
+	/** def_policy meter use count. */
+	struct mlx5_l3t_tbl *policy_idx_tbl;
+	/* Policy index lookup table. */
+	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop table. */
+	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Matcher meter in drop table. */
+	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Default matcher in drop table. */
+	void *def_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Default rule in drop table. */
+};
+
 /* Table key of the hash organization. */
 union mlx5_flow_tbl_key {
 	struct {
@@ -772,9 +912,9 @@ struct mlx5_flow_tbl_resource {
 #define MLX5_FLOW_MREG_ACT_TABLE_GROUP (MLX5_MAX_TABLES - 1)
 #define MLX5_FLOW_MREG_CP_TABLE_GROUP (MLX5_MAX_TABLES - 2)
 /* Tables for metering splits should be added here. */
-#define MLX5_FLOW_TABLE_LEVEL_SUFFIX (MLX5_MAX_TABLES - 3)
-#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 4)
-#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_METER
+#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 3)
+#define MLX5_FLOW_TABLE_LEVEL_POLICY (MLX5_MAX_TABLES - 4)
+#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_POLICY
 #define MLX5_MAX_TABLES_FDB UINT16_MAX
 #define MLX5_FLOW_TABLE_FACTOR 10
 
@@ -935,8 +1075,8 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_geneve_tlv_option_resource *geneve_tlv_option_resource;
 	/* Management structure for geneve tlv option */
 	rte_spinlock_t geneve_tlv_opt_sl; /* Lock for geneve tlv resource */
-	struct mlx5_aso_mtr_pools_mng *mtrmng;
-	/* Meter pools management structure. */
+	struct mlx5_flow_mtr_mng *mtrmng;
+	/* Meter management structure. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
 
@@ -1237,7 +1377,7 @@ int mlx5_hairpin_cap_get(struct rte_eth_dev *dev,
 bool mlx5_flex_parser_ecpri_exist(struct rte_eth_dev *dev);
 int mlx5_flex_parser_ecpri_alloc(struct rte_eth_dev *dev);
 int mlx5_flow_aso_age_mng_init(struct mlx5_dev_ctx_shared *sh);
-int mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv);
+int mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh);
 
 /* mlx5_ethdev.c */
 
@@ -1463,6 +1603,12 @@ int mlx5_flow_meter_attach(struct mlx5_priv *priv,
 			   struct rte_flow_error *error);
 void mlx5_flow_meter_detach(struct mlx5_priv *priv,
 			    struct mlx5_flow_meter_info *fm);
+struct mlx5_flow_meter_policy *mlx5_flow_meter_policy_find
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		uint32_t *policy_idx);
+int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
+			  struct rte_mtr_error *error);
 
 /* mlx5_os.c */
 struct rte_pci_driver;
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ee2c351649..81e0e3b7a9 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1028,7 +1028,7 @@ flow_rxq_tunnel_ptype_update(struct mlx5_rxq_ctrl *rxq_ctrl)
  * @param[in] dev_handle
  *   Pointer to device flow handle structure.
  */
-static void
+void
 flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
 		       struct mlx5_flow_handle *dev_handle)
 {
@@ -4479,8 +4479,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		actions_pre++;
 		jump_data = (struct rte_flow_action_jump *)actions_pre;
 		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_METER;
+				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_POLICY;
 		hw_mtr_action->conf = jump_data;
 		actions_pre = (struct rte_flow_action *)(jump_data + 1);
 	} else {
@@ -5079,8 +5079,8 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	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);
+			  (MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+			  MLX5_FLOW_TABLE_LEVEL_METER);
 		/*
 		 * 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
@@ -5344,8 +5344,8 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 		dev_flow->handle->is_meter_flow_id = 1;
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_SUFFIX;
+				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_METER;
 		flow_split_info->prefix_layers =
 				flow_get_prefix_layer_flags(dev_flow);
 		flow_split_info->prefix_mark = dev_flow->handle->mark;
@@ -6608,6 +6608,169 @@ mlx5_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
 	return 0;
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] is_rss
+ *   Is RSS or not.
+ * @param[out] domain_bitmap
+ *   Domain bitmap.
+ * @param[out] is_def_policy
+ *   Is default policy or not.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->validate_mtr_acts(dev, actions, attr,
+			is_rss, domain_bitmap, is_def_policy, error);
+}
+
+/**
+ * Destroy the meter table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_acts(dev, mtr_policy);
+}
+
+/**
+ * Create policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_mtr_acts(dev, mtr_policy, actions, error);
+}
+
+/**
+ * Create policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_def_policy(dev);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_def_policy(dev);
+}
+
 /**
  * Create the needed meter and suffix tables.
  *
@@ -6647,6 +6810,21 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
+/**
+ * Destroy the global meter drop table.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_drop_tbls(dev);
+}
+
 /**
  * Allocate the needed aso flow meter id.
  *
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 7fa15eef7b..51d040c4d2 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -691,13 +691,6 @@ struct mlx5_flow_handle {
 #define MLX5_FLOW_HANDLE_VERBS_SIZE (sizeof(struct mlx5_flow_handle))
 #endif
 
-/*
- * Max number of actions per DV flow.
- * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
- * in rdma-core file providers/mlx5/verbs.c.
- */
-#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
-
 /** Device flow structure only for DV flow creation. */
 struct mlx5_flow_dv_workspace {
 	uint32_t group; /**< The group index. */
@@ -1099,6 +1092,7 @@ 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);
+typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1144,6 +1138,32 @@ typedef int (*mlx5_flow_sync_domain_t)
 			(struct rte_eth_dev *dev,
 			 uint32_t domains,
 			 uint32_t flags);
+typedef int (*mlx5_flow_validate_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+			 const struct rte_flow_action *actions[RTE_COLORS],
+			 struct rte_flow_attr *attr,
+			 bool *is_rss,
+			 uint8_t *domain_bitmap,
+			 bool *is_def_policy,
+			 struct rte_mtr_error *error);
+typedef int (*mlx5_flow_create_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+typedef void (*mlx5_flow_destroy_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef void (*mlx5_flow_destroy_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_def_policy_t)
+			(struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_destroy_def_policy_t)
+			(struct rte_eth_dev *dev);
 
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
@@ -1155,8 +1175,16 @@ 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_destroy_mtr_drop_tbls_t destroy_mtr_drop_tbls;
 	mlx5_flow_mtr_alloc_t create_meter;
 	mlx5_flow_mtr_free_t free_meter;
+	mlx5_flow_validate_mtr_acts_t validate_mtr_acts;
+	mlx5_flow_create_mtr_acts_t create_mtr_acts;
+	mlx5_flow_destroy_mtr_acts_t destroy_mtr_acts;
+	mlx5_flow_create_policy_rules_t create_policy_rules;
+	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
+	mlx5_flow_create_def_policy_t create_def_policy;
+	mlx5_flow_destroy_def_policy_t destroy_def_policy;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1233,12 +1261,13 @@ static inline struct mlx5_aso_mtr *
 mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)
 {
 	struct mlx5_aso_mtr_pool *pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 
 	/* Decrease to original index. */
 	idx--;
-	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < mtrmng->n);
-	pool = mtrmng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
+	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n);
+	pool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
 	return &pool->mtrs[idx % MLX5_ASO_MTRS_PER_POOL];
 }
 
@@ -1384,8 +1413,7 @@ 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_meter_flush(struct rte_eth_dev *dev,
-			  struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
@@ -1486,4 +1514,25 @@ int mlx5_flow_os_set_specific_workspace(struct mlx5_flow_workspace *data);
 void mlx5_flow_os_release_workspace(void);
 uint32_t mlx5_flow_mtr_alloc(struct rte_eth_dev *dev);
 void mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx);
+int mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+int mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+void mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_def_policy(struct rte_eth_dev *dev);
+void mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev);
+void flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
+		       struct mlx5_flow_handle *dev_handle);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c
index 62d2df054b..20cd4fe18c 100644
--- a/drivers/net/mlx5/mlx5_flow_aso.c
+++ b/drivers/net/mlx5/mlx5_flow_aso.c
@@ -311,11 +311,11 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh,
 		mlx5_aso_age_init_sq(&sh->aso_age_mng->aso_sq);
 		break;
 	case ASO_OPC_MOD_POLICER:
-		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->sq, 0,
+		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->pools_mng.sq, 0,
 				  sh->tx_uar, sh->pdn, MLX5_ASO_QUEUE_LOG_DESC,
 				  sh->sq_ts_format))
 			return -1;
-		mlx5_aso_mtr_init_sq(&sh->mtrmng->sq);
+		mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq);
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -342,7 +342,7 @@ mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh,
 		sq = &sh->aso_age_mng->aso_sq;
 		break;
 	case ASO_OPC_MOD_POLICER:
-		sq = &sh->mtrmng->sq;
+		sq = &sh->mtrmng->pools_mng.sq;
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -798,7 +798,7 @@ int
 mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	do {
@@ -830,7 +830,7 @@ int
 mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) ==
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index af3397fb55..759731333d 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -21,6 +21,8 @@
 #include <rte_gtp.h>
 #include <rte_eal_paging.h>
 #include <rte_mpls.h>
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -184,6 +186,31 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
 	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. */
@@ -4695,10 +4722,6 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev,
 					  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,
@@ -5928,9 +5951,10 @@ static int
 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
-	void *old_pools = mtrmng->pools;
-	uint32_t resize = mtrmng->n + MLX5_MTRS_CONTAINER_RESIZE;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
+	void *old_pools = pools_mng->pools;
+	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
 
@@ -5938,16 +5962,16 @@ flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 		rte_errno = ENOMEM;
 		return -ENOMEM;
 	}
-	if (!mtrmng->n)
+	if (!pools_mng->n)
 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
 			mlx5_free(pools);
 			return -ENOMEM;
 		}
 	if (old_pools)
-		memcpy(pools, old_pools, mtrmng->n *
+		memcpy(pools, old_pools, pools_mng->n *
 				       sizeof(struct mlx5_aso_mtr_pool *));
-	mtrmng->n = resize;
-	mtrmng->pools = pools;
+	pools_mng->n = resize;
+	pools_mng->pools = pools;
 	if (old_pools)
 		mlx5_free(old_pools);
 	return 0;
@@ -5970,7 +5994,8 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 			     struct mlx5_aso_mtr **mtr_free)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool = NULL;
 	struct mlx5_devx_obj *dcs = NULL;
 	uint32_t i;
@@ -5990,17 +6015,17 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 		return NULL;
 	}
 	pool->devx_obj = dcs;
-	pool->index = mtrmng->n_valid;
-	if (pool->index == mtrmng->n && flow_dv_mtr_container_resize(dev)) {
+	pool->index = pools_mng->n_valid;
+	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
 		mlx5_free(pool);
 		claim_zero(mlx5_devx_cmd_destroy(dcs));
 		return NULL;
 	}
-	mtrmng->pools[pool->index] = pool;
-	mtrmng->n_valid++;
+	pools_mng->pools[pool->index] = pool;
+	pools_mng->n_valid++;
 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
 		pool->mtrs[i].offset = i;
-		LIST_INSERT_HEAD(&mtrmng->meters,
+		LIST_INSERT_HEAD(&pools_mng->meters,
 						&pool->mtrs[i], next);
 	}
 	pool->mtrs[0].offset = 0;
@@ -6020,15 +6045,16 @@ static void
 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
 
 	MLX5_ASSERT(aso_mtr);
-	rte_spinlock_lock(&mtrmng->mtrsl);
+	rte_spinlock_lock(&pools_mng->mtrsl);
 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
 	aso_mtr->state = ASO_METER_FREE;
-	LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 }
 
 /**
@@ -6045,7 +6071,8 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_aso_mtr *mtr_free = NULL;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool;
 	uint32_t mtr_idx = 0;
 
@@ -6055,16 +6082,16 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 	}
 	/* Allocate the flow meter memory. */
 	/* Get free meters from management. */
-	rte_spinlock_lock(&mtrmng->mtrsl);
-	mtr_free = LIST_FIRST(&mtrmng->meters);
+	rte_spinlock_lock(&pools_mng->mtrsl);
+	mtr_free = LIST_FIRST(&pools_mng->meters);
 	if (mtr_free)
 		LIST_REMOVE(mtr_free, next);
 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
 		return 0;
 	}
 	mtr_free->state = ASO_METER_WAIT;
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 	pool = container_of(mtr_free,
 			struct mlx5_aso_mtr_pool,
 			mtrs[mtr_free->offset]);
@@ -13390,6 +13417,556 @@ flow_dv_action_query(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Destroy the meter sub policy table rules.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *   Pointer to meter sub policy table.
+ */
+static void
+__flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_sub_policy *sub_policy)
+{
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (sub_policy->color_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(sub_policy->color_rule[i]));
+			sub_policy->color_rule[i] = NULL;
+		}
+		if (sub_policy->color_matcher[i]) {
+			tbl = container_of(sub_policy->color_matcher[i]->tbl,
+				typeof(*tbl), tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &sub_policy->color_matcher[i]->entry);
+			sub_policy->color_matcher[i] = NULL;
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (sub_policy->rix_hrxq[i]) {
+			mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+			sub_policy->rix_hrxq[i] = 0;
+		}
+		if (sub_policy->jump_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->jump_tbl[i]);
+			sub_policy->jump_tbl[i] = NULL;
+		}
+	}
+	if (sub_policy->tbl_rsc) {
+		flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->tbl_rsc);
+		sub_policy->tbl_rsc = NULL;
+	}
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	uint32_t i, j;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		for (j = 0; j < sub_policy_num; j++) {
+			sub_policy = mtr_policy->sub_policys[i][j];
+			if (sub_policy)
+				__flow_dv_destroy_sub_policy_rules
+						(dev, sub_policy);
+		}
+	}
+}
+
+/**
+ * Destroy policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	struct rte_flow_action *rss_action;
+	struct mlx5_flow_handle dev_handle;
+	uint32_t i, j;
+
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			flow_dv_tag_release(dev,
+				mtr_policy->act_cnt[i].rix_mark);
+			mtr_policy->act_cnt[i].rix_mark = 0;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			dev_handle.dvh.modify_hdr =
+				mtr_policy->act_cnt[i].modify_hdr;
+			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
+		}
+		switch (mtr_policy->act_cnt[i].fate_action) {
+		case MLX5_FLOW_FATE_SHARED_RSS:
+			rss_action = mtr_policy->act_cnt[i].rss;
+			mlx5_free(rss_action);
+			break;
+		case MLX5_FLOW_FATE_PORT_ID:
+			if (mtr_policy->act_cnt[i].rix_port_id_action) {
+				flow_dv_port_id_action_resource_release(dev,
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				mtr_policy->act_cnt[i].rix_port_id_action = 0;
+			}
+			break;
+		case MLX5_FLOW_FATE_DROP:
+		case MLX5_FLOW_FATE_JUMP:
+			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+				mtr_policy->act_cnt[i].dr_jump_action[j] =
+						NULL;
+			break;
+		default:
+			/*Queue action do nothing*/
+			break;
+		}
+	}
+	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+		mtr_policy->dr_drop_action[j] = NULL;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+__flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			enum mlx5_meter_domain domain,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_error flow_err;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	struct mlx5_flow_handle dh;
+	struct mlx5_flow dev_flow;
+	struct mlx5_flow_dv_port_id_action_resource port_id_action;
+	int i, ret;
+	uint8_t egress, transfer;
+	struct mlx5_meter_policy_action_container *act_cnt = NULL;
+	union {
+		struct mlx5_flow_dv_modify_hdr_resource res;
+		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
+			    sizeof(struct mlx5_modification_cmd) *
+			    (MLX5_MAX_MODIFY_NUM + 1)];
+	} mhdr_dummy;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
+	memset(&port_id_action, 0,
+		sizeof(struct mlx5_flow_dv_port_id_action_resource));
+	dev_flow.handle = &dh;
+	dev_flow.dv.port_id_action = &port_id_action;
+	dev_flow.external = true;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i < MLX5_MTR_RTE_COLORS)
+			act_cnt = &mtr_policy->act_cnt[i];
+		for (act = actions[i];
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_MARK:
+			{
+				uint32_t tag_be = mlx5_flow_mark_set
+					(((const struct rte_flow_action_mark *)
+					(act->conf))->id);
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "mark action for this color");
+				dev_flow.handle->mark = 1;
+				if (flow_dv_tag_resource_register(dev, tag_be,
+						  &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot setup policy mark action");
+				MLX5_ASSERT(dev_flow.dv.tag_resource);
+				act_cnt->rix_mark =
+					dev_flow.handle->dvh.rix_tag;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+			mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+			{
+				struct mlx5_flow_dv_modify_hdr_resource
+					*mhdr_res = &mhdr_dummy.res;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "set tag action for this color");
+				memset(mhdr_res, 0, sizeof(*mhdr_res));
+				mhdr_res->ft_type = transfer ?
+					MLX5DV_FLOW_TABLE_TYPE_FDB :
+					egress ?
+					MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+					MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+				if (flow_dv_convert_action_set_tag
+				(dev, mhdr_res,
+				(const struct rte_flow_action_set_tag *)
+				act->conf,  &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot convert policy "
+					"set tag action");
+				if (!mhdr_res->actions_num)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot find policy "
+					"set tag action");
+				/* create modify action if needed. */
+				dev_flow.dv.group = 1;
+				if (flow_dv_modify_hdr_resource_register
+					(dev, mhdr_res, &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot register policy "
+					"set tag action");
+				act_cnt->modify_hdr =
+				dev_flow.handle->dvh.modify_hdr;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+				mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_DROP:
+			{
+				struct mlx5_flow_mtr_mng *mtrmng =
+						priv->sh->mtrmng;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+
+				/*
+				 * Create the drop table with
+				 * METER DROP level.
+				 */
+				if (!mtrmng->drop_tbl[domain]) {
+					mtrmng->drop_tbl[domain] =
+					flow_dv_tbl_resource_get(dev,
+					MLX5_FLOW_TABLE_LEVEL_METER,
+					egress, transfer, false, NULL, 0,
+					0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
+					if (!mtrmng->drop_tbl[domain])
+						return -rte_mtr_error_set
+					(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Failed to create meter drop table");
+				}
+				tbl_data = container_of
+				(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				if (i < MLX5_MTR_RTE_COLORS) {
+					act_cnt->dr_jump_action[domain] =
+						tbl_data->jump.action;
+					act_cnt->fate_action =
+						MLX5_FLOW_FATE_DROP;
+				}
+				if (i == RTE_COLOR_RED)
+					mtr_policy->dr_drop_action[domain] =
+						tbl_data->jump.action;
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+			{
+				struct mlx5_hrxq *hrxq;
+				uint32_t hrxq_idx;
+				struct mlx5_flow_rss_desc rss_desc;
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"fate queue for this color");
+				memset(&rss_desc, 0,
+					sizeof(struct mlx5_flow_rss_desc));
+				rss_desc.queue_num = 1;
+				rss_desc.const_q = act->conf;
+				hrxq = flow_dv_hrxq_prepare(dev, &dev_flow,
+						    &rss_desc, &hrxq_idx);
+				if (!hrxq)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot create policy fate queue");
+				sub_policy->rix_hrxq[i] = hrxq_idx;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				dev_flow.handle->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				if (action_flags & MLX5_FLOW_ACTION_MARK ||
+				    action_flags & MLX5_FLOW_ACTION_SET_TAG) {
+					dev_flow.handle->rix_hrxq = hrxq_idx;
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_RSS:
+			{
+				int rss_size;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "rss action for this color");
+				/*
+				 * Save RSS conf into policy struct
+				 * for translate stage.
+				 */
+				rss_size = (int)rte_flow_conv
+					(RTE_FLOW_CONV_OP_ACTION,
+					NULL, 0, act, &flow_err);
+				if (rss_size <= 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Get the wrong "
+					  "rss action struct size");
+				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
+						rss_size, 0, SOCKET_ID_ANY);
+				if (!act_cnt->rss)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "Fail to malloc rss action memory");
+				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
+					act_cnt->rss, rss_size,
+					act, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Fail to save "
+					  "rss action into policy struct");
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_SHARED_RSS;
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+			{
+				struct mlx5_flow_dv_port_id_action_resource
+					port_id_resource;
+				uint32_t port_id = 0;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"port action for this color");
+				memset(&port_id_resource, 0,
+					sizeof(port_id_resource));
+				if (flow_dv_translate_action_port_id(dev, act,
+						&port_id, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot translate "
+					"policy port action");
+				port_id_resource.port_id = port_id;
+				if (flow_dv_port_id_action_resource_register
+					(dev, &port_id_resource,
+					&dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy port action");
+				act_cnt->rix_port_id_action =
+					dev_flow.handle->rix_port_id_action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_PORT_ID;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+			{
+				uint32_t jump_group = 0;
+				uint32_t table = 0;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+				struct flow_grp_info grp_info = {
+					.external = !!dev_flow.external,
+					.transfer = !!transfer,
+					.fdb_def_rule = !!priv->fdb_def_rule,
+					.std_tbl_fix = 0,
+					.skip_scale = dev_flow.skip_scale &
+					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
+				};
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "jump action for this color");
+				jump_group =
+				((const struct rte_flow_action_jump *)
+							act->conf)->group;
+				if (mlx5_flow_group_to_table(dev, NULL,
+						       jump_group,
+						       &table,
+						       &grp_info, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy jump action");
+				sub_policy->jump_tbl[i] =
+				flow_dv_tbl_resource_get(dev,
+					table, egress,
+					transfer,
+					!!dev_flow.external,
+					NULL, jump_group, 0,
+					0, &flow_err);
+				if
+				(!sub_policy->jump_tbl[i])
+					return  -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create jump action.");
+				tbl_data = container_of
+				(sub_policy->jump_tbl[i],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				act_cnt->dr_jump_action[domain] =
+					tbl_data->jump.action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_JUMP;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			}
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "action type not supported");
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	int ret, i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (sub_policy_num) {
+			ret = __flow_dv_create_domain_policy_acts(dev,
+				mtr_policy, actions,
+				(enum mlx5_meter_domain)i, error);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
 /**
  * Query a dv flow  rule for its statistics via devx.
  *
@@ -13570,9 +14147,484 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void
+flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (mtrmng->def_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+					(mtrmng->def_rule[i]));
+			mtrmng->def_rule[i] = NULL;
+		}
+		if (mtrmng->def_matcher[i]) {
+			tbl = container_of(mtrmng->def_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->def_matcher[i]->entry);
+			mtrmng->def_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_matcher[i]) {
+			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->drop_matcher[i]->entry);
+			mtrmng->drop_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+				mtrmng->drop_tbl[i]);
+			mtrmng->drop_tbl[i] = NULL;
+		}
+	}
+}
+
 /* Number of meter flow actions, count and jump or count and drop. */
 #define METER_ACTIONS 2
 
+static void
+__flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
+			      enum mlx5_meter_domain domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_def_policy *def_policy =
+			priv->sh->mtrmng->def_policy[domain];
+
+	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
+	mlx5_free(def_policy);
+	priv->sh->mtrmng->def_policy[domain] = NULL;
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+static void
+flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
+		if (priv->sh->mtrmng->def_policy[i])
+			__flow_dv_destroy_domain_def_policy(dev,
+					(enum mlx5_meter_domain)i);
+	priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
+}
+
+static int
+__flow_dv_create_policy_flow(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			enum rte_color color, void *matcher_object,
+			int actions_n, void *actions,
+			bool is_default_policy, void **rule,
+			const struct rte_flow_attr *attr)
+{
+	int ret;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to create meter policy flow with port.");
+			return -1;
+		}
+	}
+	flow_dv_match_meta_reg(matcher.buf, value.buf,
+				(enum modify_reg)color_reg_c_idx,
+				rte_col_2_mlx5_col(color),
+				UINT32_MAX);
+	ret = mlx5_flow_os_create_flow(matcher_object,
+			(void *)&value, actions_n, actions, rule);
+	if (ret) {
+		DRV_LOG(ERR, "Failed to create meter policy flow.");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			uint16_t priority,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			const struct rte_flow_attr *attr,
+			bool is_default_policy,
+			struct rte_flow_error *error)
+{
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+				MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+		.tbl = tbl_rsc,
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = error,
+		.data = &matcher,
+	};
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	struct mlx5_priv *priv = dev->data->dev_private;
+	uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to register meter drop matcher with port.");
+			return -1;
+		}
+	}
+	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
+	if (priority < RTE_COLOR_RED)
+		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+			(enum modify_reg)color_reg_c_idx, 0, color_mask);
+	matcher.priority = priority;
+	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
+					matcher.mask.size);
+	entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+	if (!entry) {
+		DRV_LOG(ERR, "Failed to register meter drop matcher.");
+		return -1;
+	}
+	sub_policy->color_matcher[priority] =
+		container_of(entry, struct mlx5_flow_dv_matcher, entry);
+	return 0;
+}
+
+/**
+ * Create the policy rules per domain.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *    Pointer to sub policy table..
+ * @param[in] egress
+ *   Direction of the table.
+ * @param[in] transfer
+ *   E-Switch or NIC flow.
+ * @param[in] acts
+ *   Pointer to policy action list per color.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+__flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_sub_policy *sub_policy,
+		uint8_t egress, uint8_t transfer, bool is_default_policy,
+		struct mlx5_meter_policy_acts acts[RTE_COLORS])
+{
+	struct rte_flow_error flow_err;
+	uint32_t color_reg_c_idx;
+	struct rte_flow_attr attr = {
+		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
+		.priority = 0,
+		.ingress = 0,
+		.egress = !!egress,
+		.transfer = !!transfer,
+		.reserved = 0,
+	};
+	int i;
+	int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
+
+	if (ret < 0)
+		return -1;
+	/* Create policy table with POLICY level. */
+	if (!sub_policy->tbl_rsc)
+		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_POLICY,
+				egress, transfer, false, NULL, 0, 0,
+				sub_policy->idx, &flow_err);
+	if (!sub_policy->tbl_rsc) {
+		DRV_LOG(ERR,
+			"Failed to create meter sub policy table.");
+		return -1;
+	}
+	/* Prepare matchers. */
+	color_reg_c_idx = ret;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i == RTE_COLOR_YELLOW || !acts[i].actions_n)
+			continue;
+		attr.priority = i;
+		if (!sub_policy->color_matcher[i]) {
+			/* Create matchers for Color. */
+			if (__flow_dv_create_policy_matcher(dev,
+				color_reg_c_idx, i, sub_policy,
+				&attr, is_default_policy, &flow_err))
+				return -1;
+		}
+		/* Create flow, matching color. */
+		if (acts[i].actions_n)
+			if (__flow_dv_create_policy_flow(dev,
+				color_reg_c_idx, (enum rte_color)i,
+				sub_policy->color_matcher[i]->matcher_object,
+				acts[i].actions_n,
+				acts[i].dv_actions,
+				is_default_policy,
+				&sub_policy->color_rule[i],
+				&attr))
+				return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	struct mlx5_flow_dv_tag_resource *tag;
+	struct mlx5_flow_dv_port_id_action_resource *port_action;
+	struct mlx5_hrxq *hrxq;
+	uint8_t egress, transfer;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		acts[i].actions_n = 0;
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (i == RTE_COLOR_RED) {
+			/* Only support drop on red. */
+			acts[i].dv_actions[0] =
+			mtr_policy->dr_drop_action[domain];
+			acts[i].actions_n = 1;
+			continue;
+		}
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
+					mtr_policy->act_cnt[i].rix_mark);
+			if (!tag) {
+				DRV_LOG(ERR, "Failed to find "
+				"mark action for policy.");
+				return -1;
+			}
+			acts[i].dv_actions[acts[i].actions_n] =
+						tag->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			acts[i].dv_actions[acts[i].actions_n] =
+			mtr_policy->act_cnt[i].modify_hdr->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].fate_action) {
+			switch (mtr_policy->act_cnt[i].fate_action) {
+			case MLX5_FLOW_FATE_PORT_ID:
+				port_action = mlx5_ipool_get
+					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				if (!port_action) {
+					DRV_LOG(ERR, "Failed to find "
+						"port action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				port_action->action;
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_DROP:
+			case MLX5_FLOW_FATE_JUMP:
+				acts[i].dv_actions[acts[i].actions_n] =
+				mtr_policy->act_cnt[i].dr_jump_action[domain];
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_SHARED_RSS:
+			case MLX5_FLOW_FATE_QUEUE:
+				hrxq = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+				sub_policy->rix_hrxq[i]);
+				if (!hrxq) {
+					DRV_LOG(ERR, "Failed to find "
+						"queue action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				hrxq->action;
+				acts[i].actions_n++;
+				break;
+			default:
+				/*Queue action do nothing*/
+				break;
+			}
+		}
+	}
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
+				egress, transfer, false, acts)) {
+		DRV_LOG(ERR,
+		"Failed to create policy rules per domain.");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Create the policy rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in,out] mtr_policy
+ *   Pointer to meter policy table.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	int i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (!sub_policy_num)
+			continue;
+		/* Prepare actions list and create policy rules. */
+		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+			mtr_policy->sub_policys[i][0], i)) {
+			DRV_LOG(ERR,
+			"Failed to create policy action list per domain.");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_meter_def_policy *def_policy;
+	struct mlx5_flow_tbl_resource *jump_tbl;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	struct rte_flow_error error;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	int ret;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	def_policy = mtrmng->def_policy[domain];
+	if (!def_policy) {
+		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(struct mlx5_flow_meter_def_policy),
+			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+		if (!def_policy) {
+			DRV_LOG(ERR, "Failed to alloc "
+					"default policy table.");
+			goto def_policy_error;
+		}
+		mtrmng->def_policy[domain] = def_policy;
+		/* Create the meter suffix table with SUFFIX level. */
+		jump_tbl = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_METER,
+				egress, transfer, false, NULL, 0,
+				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
+		if (!jump_tbl) {
+			DRV_LOG(ERR,
+				"Failed to create meter suffix table.");
+			goto def_policy_error;
+		}
+		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
+		tbl_data = container_of(jump_tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].dv_actions[0] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].actions_n = 1;
+		/* Create jump action to the drop table. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
+				(dev, MLX5_FLOW_TABLE_LEVEL_METER,
+				egress, transfer, false, NULL, 0,
+				0, MLX5_MTR_TABLE_ID_DROP, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create "
+				"meter drop table for default policy.");
+				goto def_policy_error;
+			}
+		}
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_RED] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
+		acts[RTE_COLOR_RED].actions_n = 1;
+		/* Create default policy rules. */
+		ret = __flow_dv_create_domain_policy_rules(dev,
+					&def_policy->sub_policy,
+					egress, transfer, true, acts);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create "
+				"default policy rules.");
+				goto def_policy_error;
+		}
+	}
+	return 0;
+def_policy_error:
+	__flow_dv_destroy_domain_def_policy(dev,
+			(enum mlx5_meter_domain)domain);
+	return -1;
+}
+
+/**
+ * Create the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	/* Non-termination policy table. */
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
+			continue;
+		if (__flow_dv_create_domain_def_policy(dev, i)) {
+			DRV_LOG(ERR,
+			"Failed to create default policy");
+			return -1;
+		}
+	}
+	return 0;
+}
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -13602,19 +14654,11 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
 		dtb = &mtb->egress;
 	else
 		dtb = &mtb->ingress;
-	/* Create the meter table with METER level. */
-	dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
-	if (!dtb->tbl) {
-		DRV_LOG(ERR, "Failed to create meter policer table.");
-		return -1;
-	}
 	/* Create the meter suffix table with SUFFIX level. */
 	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
-					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
+					MLX5_FLOW_TABLE_LEVEL_METER,
+					egress, transfer, false, NULL, 0,
+					0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
 	if (!dtb->sfx_tbl) {
 		DRV_LOG(ERR, "Failed to create meter suffix table.");
 		return -1;
@@ -13933,6 +14977,292 @@ flow_dv_action_validate(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_dev_config *dev_conf = &priv->config;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	int actions_n;
+	int i, ret;
+	struct rte_flow_error flow_err;
+	uint8_t domain_color[RTE_COLORS] = {0};
+	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
+
+	if (!priv->config.dv_esw_en)
+		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	*domain_bitmap = def_domain;
+	if (actions[RTE_COLOR_YELLOW] &&
+		actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_END)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"Yellow color does not support any action.");
+	if (actions[RTE_COLOR_YELLOW] &&
+		actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_DROP)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Red color only supports drop action.");
+	/*
+	 * Check default policy actions:
+	 * Green/Yellow: no action, Red: drop action
+	 */
+	if ((!actions[RTE_COLOR_GREEN] ||
+		actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)) {
+		*is_def_policy = true;
+		return 0;
+	}
+	flow_err.message = NULL;
+	for (i = 0; i < RTE_COLORS; i++) {
+		act = actions[i];
+		for (action_flags = 0, actions_n = 0;
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "too many actions");
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+				if (!priv->config.dv_esw_en)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "PORT action validate check"
+					" fail for ESW disable");
+				ret = flow_dv_validate_action_port_id(dev,
+						action_flags,
+						act, attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"PORT action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			case RTE_FLOW_ACTION_TYPE_MARK:
+				ret = flow_dv_validate_action_mark(dev, act,
+							   action_flags,
+							   attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Mark action validate check fail");
+				if (dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "Extend MARK action is "
+					"not supported. Please try use "
+					"default policy for meter.");
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+				ret = flow_dv_validate_action_set_tag(dev,
+							act, action_flags,
+							attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Set tag action validate check fail");
+				/*
+				 * Count all modify-header actions
+				 * as one action.
+				 */
+				if (!(action_flags &
+					MLX5_FLOW_MODIFY_HDR_ACTIONS))
+					++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			case RTE_FLOW_ACTION_TYPE_DROP:
+				ret = mlx5_flow_validate_action_drop
+					(action_flags,
+					attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Drop action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+				/*
+				 * Check whether extensive
+				 * metadata feature is engaged.
+				 */
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Queue action with meta "
+					  "is not supported. Please try use "
+					  "default policy for meter.");
+				ret = mlx5_flow_validate_action_queue(act,
+							action_flags, dev,
+							attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Queue action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_RSS:
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "RSS action with meta "
+					  "is not supported. Please try use "
+					  "default policy for meter.");
+				ret = mlx5_validate_action_rss(dev, act,
+						&flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "RSS action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				++actions_n;
+				*is_rss = true;
+				break;
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+				ret = flow_dv_validate_action_jump(dev,
+					NULL, act, action_flags,
+					attr, true, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Jump action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Doesn't support optional action");
+			}
+		}
+		/* Yellow is not supported, just skip. */
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
+		else if ((action_flags &
+			(MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
+			(action_flags & MLX5_FLOW_ACTION_MARK))
+			/*
+			 * Only support MLX5_XMETA_MODE_LEGACY
+			 * so MARK action only in ingress domain.
+			 */
+			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
+		else
+			domain_color[i] = def_domain;
+		/*
+		 * Validate the drop action mutual exclusion
+		 * with other actions. Drop action is mutually-exclusive
+		 * with any other action, except for Count action.
+		 */
+		if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
+			(action_flags & ~MLX5_FLOW_ACTION_DROP)) {
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Drop action is mutually-exclusive "
+				"with any other action");
+		}
+		/* Eswitch has few restrictions on using items and actions */
+		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
+			if (!mlx5_flow_ext_mreg_supported(dev) &&
+				action_flags & MLX5_FLOW_ACTION_MARK)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action MARK");
+			if (action_flags & MLX5_FLOW_ACTION_QUEUE)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action QUEUE");
+			if (action_flags & MLX5_FLOW_ACTION_RSS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action RSS");
+			if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+		} else {
+			if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) &&
+				(domain_color[i] &
+				MLX5_MTR_DOMAIN_INGRESS_BIT)) {
+				if ((domain_color[i] &
+					MLX5_MTR_DOMAIN_EGRESS_BIT))
+					domain_color[i] =
+					MLX5_MTR_DOMAIN_EGRESS_BIT;
+				else
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+			}
+		}
+		if (domain_color[i] != def_domain)
+			*domain_bitmap = domain_color[i];
+	}
+	return 0;
+}
+
 static int
 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
 {
@@ -13968,8 +15298,16 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.query = flow_dv_query,
 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
+	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
+	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
+	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
+	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
+	.create_policy_rules = flow_dv_create_policy_rules,
+	.destroy_policy_rules = flow_dv_destroy_policy_rules,
+	.create_def_policy = flow_dv_create_def_policy,
+	.destroy_def_policy = flow_dv_destroy_def_policy,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index af0a1c18cb..8b004efd7d 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -38,6 +38,12 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
 	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
 	uint32_t val;
+	enum mlx5_meter_domain domain =
+		fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+			fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
+				MLX5_MTR_DOMAIN_INGRESS;
+	struct mlx5_flow_meter_def_policy *def_policy =
+		priv->sh->mtrmng->def_policy[domain];
 
 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
@@ -57,10 +63,7 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
-	mtr_init.next_table =
-		fm->transfer ? fm->mfts->transfer.tbl->obj :
-			fm->egress ? fm->mfts->egress.tbl->obj :
-				fm->mfts->ingress.tbl->obj;
+	mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
 	mtr_init.flow_meter_parameter = fmp;
 	mtr_init.flow_meter_parameter_sz =
@@ -317,7 +320,7 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
 					  "Meter is not supported");
 	memset(cap, 0, sizeof(*cap));
 	if (priv->sh->meter_aso_en)
-	    /* 2 meters per one ASO cache line. */
+		/* 2 meters per one ASO cache line. */
 		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
 	else
 		cap->n_max = 1 << qattr->log_max_flow_meter;
@@ -435,6 +438,347 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * Find policy by id.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param policy_id
+ *   Policy id.
+ *
+ * @return
+ *   Pointer to the policy found on success, NULL otherwise.
+ */
+struct mlx5_flow_meter_policy *
+mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
+			    uint32_t policy_id,
+			    uint32_t *policy_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+	union mlx5_l3t_data data;
+
+	if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM ||
+		!priv->sh->mtrmng->policy_idx_tbl)
+		return NULL;
+	if (mlx5_l3t_get_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data) ||
+				!data.dword)
+		return NULL;
+	if (policy_idx)
+		*policy_idx = data.dword;
+	sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					data.dword);
+	/* Remove reference taken by the mlx5_l3t_get_entry. */
+	mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id);
+	if (sub_policy)
+		if (sub_policy->main_policy_id)
+			return sub_policy->main_policy;
+	return NULL;
+}
+
+/**
+ * Callback to check MTR policy action validate
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_validate(struct rte_eth_dev *dev,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint8_t domain_bitmap;
+	int ret;
+
+	if (!priv->mtr_en || !priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "meter policy unsupported.");
+	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+static int
+__mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint32_t i, j;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	if (mtr_policy->ref_cnt) {
+		rte_spinlock_unlock(&mtr_policy->sl);
+		return -rte_mtr_error_set(error, EBUSY,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				 NULL,
+				"Meter policy object is being used.");
+	}
+	mlx5_flow_destroy_policy_rules(dev, mtr_policy);
+	mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (sub_policy_num) {
+			for (j = 0; j < sub_policy_num; j++) {
+				sub_policy = mtr_policy->sub_policys[i][j];
+				if (sub_policy)
+					mlx5_ipool_free
+					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+			}
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl) {
+		if (mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+					policy_id)) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Fail to delete policy in index table.");
+		}
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return 0;
+}
+
+/**
+ * Callback to add MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] policy_id
+ *   Pointer to policy id
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_create(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct rte_mtr_meter_policy_params *policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	uint32_t sub_policy_idx = 0;
+	uint32_t policy_idx = 0;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint32_t i;
+	int ret;
+	uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
+	uint16_t sub_policy_num;
+	uint8_t domain_bitmap = 0;
+	union mlx5_l3t_data data;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "meter policy unsupported.");
+	if (policy_id == MLX5_INVALID_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID is invalid. ");
+	if (policy_id == priv->sh->mtrmng->def_policy_id)
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID exists. ");
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id,
+				&policy_idx);
+	if (mtr_policy)
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID exists. ");
+	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	if (!domain_bitmap)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "fail to find policy domain.");
+	if (is_def_policy) {
+		if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID)
+			return -rte_mtr_error_set(error, EEXIST,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "a policy with similar actions "
+				"is already configured");
+		if (mlx5_flow_create_def_policy(dev))
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"fail to create non-terminated policy.");
+		priv->sh->mtrmng->def_policy_id = policy_id;
+		return 0;
+	}
+	if (!priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+			"no ASO capability to support the policy ");
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		if (is_rss) {
+			policy_size +=
+			sizeof(struct mlx5_flow_meter_sub_policy *) *
+			MLX5_MTR_RSS_MAX_SUB_POLICY;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
+	}
+	mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
+			 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+				"Memory alloc failed for meter policy.");
+	policy_size = sizeof(struct mlx5_flow_meter_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
+		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy)
+			goto policy_add_err;
+		if (sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto policy_add_err;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+		if (!policy_idx) {
+			policy_idx = sub_policy_idx;
+			sub_policy->main_policy_id = 1;
+		}
+		mtr_policy->sub_policys[i] =
+		(struct mlx5_flow_meter_sub_policy **)
+			((uint8_t *)mtr_policy + policy_size);
+		mtr_policy->sub_policys[i][0] = sub_policy;
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		sub_policy_num++;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
+		mtr_policy->sub_policy_num |=
+			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
+		if (is_rss) {
+			mtr_policy->is_rss = 1;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
+	}
+	rte_spinlock_init(&mtr_policy->sl);
+	ret = mlx5_flow_create_mtr_acts(dev, mtr_policy,
+					policy->actions, error);
+	if (ret)
+		goto policy_add_err;
+	if (!is_rss) {
+		/* Create policy rules in HW. */
+		ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
+		if (ret)
+			goto policy_add_err;
+	}
+	data.dword = policy_idx;
+	if (!priv->sh->mtrmng->policy_idx_tbl) {
+		priv->sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		if (!priv->sh->mtrmng->policy_idx_tbl)
+			goto policy_add_err;
+	}
+	if (mlx5_l3t_set_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data))
+		goto policy_add_err;
+	return 0;
+policy_add_err:
+	if (mtr_policy) {
+		ret = __mlx5_flow_meter_policy_delete(dev, policy_id,
+			mtr_policy, error);
+		mlx5_free(mtr_policy);
+		if (ret)
+			return ret;
+	}
+	return -rte_mtr_error_set(error, ENOTSUP,
+				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+				  NULL, "Failed to create devx policy.");
+}
+
+/**
+ * Callback to delete MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Meter policy 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_policy_delete(struct rte_eth_dev *dev,
+			  uint32_t policy_id,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	uint32_t policy_idx;
+	int ret;
+
+	if (policy_id == priv->sh->mtrmng->def_policy_id) {
+		if (priv->sh->mtrmng->def_policy_ref_cnt > 0)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy object is being used.");
+		priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
+		return 0;
+	}
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"Meter policy id is invalid. ");
+	ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
+						error);
+	if (ret)
+		return ret;
+	mlx5_free(mtr_policy);
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -942,6 +1286,9 @@ 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,
+	.meter_policy_validate = mlx5_flow_meter_policy_validate,
+	.meter_policy_create = mlx5_flow_meter_policy_create,
+	.meter_policy_delete = mlx5_flow_meter_policy_delete,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -989,22 +1336,32 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_aso_mtr *aso_mtr;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	union mlx5_l3t_data data;
 
 	if (priv->sh->meter_aso_en) {
-		rte_spinlock_lock(&mtrmng->mtrsl);
-		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
-			!data.dword) {
-			rte_spinlock_unlock(&mtrmng->mtrsl);
-			return NULL;
+		rte_spinlock_lock(&pools_mng->mtrsl);
+		if (priv->mtr_idx_tbl) {
+			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
+				meter_id, &data) ||
+				!data.dword) {
+				rte_spinlock_unlock(&pools_mng->mtrsl);
+				return NULL;
+			}
+			if (mtr_idx)
+				*mtr_idx = data.dword;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+			/* Remove reference taken by the mlx5_l3t_get_entry. */
+			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
+		} else {
+			if (mtr_idx)
+				*mtr_idx = meter_id;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
 		}
-		if (mtr_idx)
-			*mtr_idx = data.dword;
-		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-		/* Remove reference taken by the mlx5_l3t_get_entry. */
-		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
+		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
+			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
@@ -1169,30 +1526,31 @@ 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_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
 	struct mlx5_aso_mtr_pool *mtr_pool;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
 	void *tmp;
-	uint32_t i, offset, mtr_idx;
+	uint32_t i, offset, mtr_idx, policy_idx;
+	void *entry;
 
+	if (!priv->mtr_en)
+		return 0;
 	if (priv->sh->meter_aso_en) {
-		i = mtrmng->n_valid;
+		i = pools_mng->n_valid;
 		while (i--) {
-			mtr_pool = mtrmng->pools[i];
+			mtr_pool = pools_mng->pools[i];
 			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
 				offset++) {
 				fm = &mtr_pool->mtrs[offset].fm;
 				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				if (mlx5_flow_meter_params_flush(dev,
-						fm, mtr_idx))
-					return -rte_mtr_error_set
-					(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				(void)mlx5_flow_meter_params_flush(dev,
+						fm, mtr_idx);
 			}
 		}
 	} else {
@@ -1200,9 +1558,35 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 			fm = &legacy_fm->fm;
 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
 				return -rte_mtr_error_set(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+				NULL, "MTR object meter profile invalid.");
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl) {
+		MLX5_L3T_FOREACH(priv->sh->mtrmng->policy_idx_tbl,
+					i, entry) {
+			policy_idx = *(uint32_t *)entry;
+			sub_policy = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				policy_idx);
+			if (!sub_policy)
+				return -rte_mtr_error_set(error,
+						EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+			if (__mlx5_flow_meter_policy_delete(dev, i,
+						sub_policy->main_policy,
+						error))
+				return -rte_mtr_error_set(error,
+						EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+			mlx5_free(sub_policy->main_policy);
 		}
+		mlx5_l3t_destroy(priv->sh->mtrmng->policy_idx_tbl);
+		priv->sh->mtrmng->policy_idx_tbl = NULL;
 	}
 	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
 		/* Check unused. */
@@ -1211,5 +1595,8 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
 		mlx5_free(fmp);
 	}
+	/* Delete default policy table. */
+	mlx5_flow_destroy_def_policy(dev);
+	mlx5_flow_destroy_mtr_drop_tbls(dev);
 	return 0;
 }
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index 94dd56709e..90d918849a 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -1179,6 +1179,7 @@ mlx5_dev_stop(struct rte_eth_dev *dev)
 	mlx5_traffic_disable(dev);
 	/* All RX queue flags will be cleared in the flush interface. */
 	mlx5_flow_list_flush(dev, &priv->flows, true);
+	mlx5_flow_meter_flush(dev, NULL);
 	mlx5_rx_intr_vec_disable(dev);
 	priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
 	priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
-- 
2.27.0


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

* [dpdk-dev] [PATCH v3 2/4] net/mlx5: support meter creation with policy
  2021-04-13  0:19 ` [dpdk-dev] [PATCH v3 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 1/4] " Li Zhang
@ 2021-04-13  0:19   ` Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-13  0:19 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

Create a meter with the new pre-defined policy.

The following cases to be considered:
1.Add entry match with meter_id in global drop table.
2.For non-termination policy (policy id 0),
  add jump rule to suffix table for green and
  jump rule to drop table for red.
3.Allocate counter per meter in drop table.
4.Allocate meter resource per domain per color.
5.It can work with both ASO and legacy meter HW objects.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |  13 +-
 drivers/net/mlx5/mlx5.h            |  62 ++---
 drivers/net/mlx5/mlx5_flow.c       |  26 +-
 drivers/net/mlx5/mlx5_flow.h       |  32 +--
 drivers/net/mlx5/mlx5_flow_dv.c    | 367 ++++++++++++++++++++---------
 drivers/net/mlx5/mlx5_flow_meter.c | 337 ++++++++++++++++++++++----
 6 files changed, 607 insertions(+), 230 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 276283d492..c1d4e2a0dc 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1297,13 +1297,14 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			if (log_obj_size >=
 			config->hca_attr.qos.log_meter_aso_granularity &&
 			log_obj_size <=
-			config->hca_attr.qos.log_meter_aso_max_alloc) {
+			config->hca_attr.qos.log_meter_aso_max_alloc)
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
-				if (err) {
-					err = -err;
-					goto error;
-				}
+		}
+		if (priv->mtr_en) {
+			err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
+			if (err) {
+				err = -err;
+				goto error;
 			}
 		}
 #endif
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index cb7c75aa2e..a8745df3e4 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -702,44 +702,12 @@ struct mlx5_flow_meter_def_policy {
 	/* Jump action per color. */
 };
 
-/* Meter table structure. */
-struct mlx5_meter_domain_info {
-	struct mlx5_flow_tbl_resource *tbl;
-	/**< Meter table. */
-	struct mlx5_flow_tbl_resource *sfx_tbl;
-	/**< Meter suffix table. */
-	struct mlx5_flow_dv_matcher *drop_matcher;
-	/**< Matcher for Drop. */
-	struct mlx5_flow_dv_matcher *color_matcher;
-	/**< Matcher for Color. */
-	void *jump_actn;
-	/**< Meter match action. */
-	void *green_rule;
-	/**< Meter green rule. */
-	void *drop_rule;
-	/**< Meter drop rule. */
-};
-
-/* 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. */
-	void *green_count;
-	/**< Counters for green rule. */
-	void *drop_count;
-	/**< Counters for green rule. */
-};
-
 /* Meter parameter structure. */
 struct mlx5_flow_meter_info {
+	uint32_t meter_id;
+	/**< Meter id. */
+	uint32_t policy_id;
+	/* Policy id, the first sub_policy idx. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
 	rte_spinlock_t sl; /**< Meter action spinlock. */
@@ -778,8 +746,10 @@ struct mlx5_flow_meter_info {
 	 * received by the application.
 	 */
 	uint32_t transfer:1;
-	struct mlx5_meter_domains_infos *mfts;
-	/**< Flow table created for this meter. */
+	uint32_t def_policy:1;
+	/* Meter points to default policy. */
+	void *drop_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop rule in drop table. */
 	uint32_t drop_cnt;
 	/**< Color counter for drop. */
 	uint32_t ref_cnt;
@@ -790,6 +760,11 @@ struct mlx5_flow_meter_info {
 	/**< Flow meter action. */
 };
 
+/* PPS(packets per second) map to BPS(Bytes per second).
+ * HW treat packet as 128bytes in PPS mode
+ */
+#define MLX5_MTRS_PPS_MAP_BPS_SHIFT 7
+
 /* RFC2697 parameter structure. */
 struct mlx5_flow_meter_srtcm_rfc2697_prm {
 	rte_be32_t cbs_cir;
@@ -878,12 +853,17 @@ struct mlx5_flow_mtr_mng {
 	/* Policy index lookup table. */
 	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
 	/* Meter drop table. */
-	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	struct mlx5_flow_dv_matcher *
+			drop_matcher[MLX5_MTR_DOMAIN_MAX][MLX5_REG_BITS];
 	/* Matcher meter in drop table. */
 	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
 	/* Default matcher in drop table. */
 	void *def_rule[MLX5_MTR_DOMAIN_MAX];
 	/* Default rule in drop table. */
+	uint8_t max_mtr_bits;
+	/* Indicate how many bits are used by meter id at the most. */
+	uint8_t max_mtr_flow_bits;
+	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 /* Table key of the hash organization. */
@@ -1322,10 +1302,6 @@ struct mlx5_priv {
 	uint32_t rss_shared_actions; /* RSS shared actions. */
 	struct mlx5_devx_obj *q_counters; /* DevX queue counter object. */
 	uint32_t counter_set_id; /* Queue counter ID to set in DevX objects. */
-	uint8_t max_mtr_bits;
-	/* Indicate how many bits are used by meter id at the most. */
-	uint8_t max_mtr_flow_bits;
-	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 #define PORT_ID(priv) ((priv)->dev_data->port_id)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 81e0e3b7a9..77590bbbed 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4496,14 +4496,14 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	flow_id = tag_id - 1;
 	flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
 	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->max_mtr_bits) > mtr_reg_bits) {
+	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
 		mlx5_ipool_free(fm->flow_ipool, tag_id);
 		return rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				"Meter flow id exceeds max limit.");
 	}
-	if (flow_id_bits > priv->max_mtr_flow_bits)
-		priv->max_mtr_flow_bits = flow_id_bits;
+	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -6778,15 +6778,18 @@ mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  *
  * @return
- *   Pointer to table set on success, NULL otherwise.
+ *   0 on success, -1 otherwise.
  */
-struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+int
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
 	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, mtr_idx, domain_bitmap);
 }
 
 /**
@@ -6796,18 +6799,15 @@ mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  * @param[in] tbl
  *   Pointer to the meter table set.
- *
- * @return
- *   0 on success.
  */
-int
+void
 mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *tbls)
+			   struct mlx5_flow_meter_info *fm)
 {
 	const struct mlx5_flow_driver_ops *fops;
 
 	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->destroy_mtr_tbls(dev, tbls);
+	fops->destroy_mtr_tbls(dev, fm);
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 51d040c4d2..89e43f2de6 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -222,16 +222,17 @@ enum mlx5_feature_name {
 #define MLX5_FLOW_ACTION_TUNNEL_SET (1ull << 37)
 #define MLX5_FLOW_ACTION_TUNNEL_MATCH (1ull << 38)
 #define MLX5_FLOW_ACTION_MODIFY_FIELD (1ull << 39)
+#define MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY (1ull << 40)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \
 	 MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_JUMP | \
-	 MLX5_FLOW_ACTION_DEFAULT_MISS)
+	 MLX5_FLOW_ACTION_DEFAULT_MISS | \
+	 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_FATE_ESWITCH_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \
-	 MLX5_FLOW_ACTION_JUMP)
-
+	 MLX5_FLOW_ACTION_JUMP | MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_MODIFY_HDR_ACTIONS (MLX5_FLOW_ACTION_SET_IPV4_SRC | \
 				      MLX5_FLOW_ACTION_SET_IPV4_DST | \
@@ -832,9 +833,8 @@ struct mlx5_legacy_flow_meter {
 	/* Must be the first in struct. */
 	TAILQ_ENTRY(mlx5_legacy_flow_meter) next;
 	/**< Pointer to the next flow meter structure. */
-	uint32_t meter_id;
-	/**< Meter id. */
-	uint32_t idx; /* Index to meter object. */
+	uint32_t idx;
+	/* Index to meter object. */
 };
 
 #define MLX5_MAX_TUNNELS 256
@@ -1088,10 +1088,12 @@ 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);
+typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
+					struct mlx5_flow_meter_info *fm,
+					uint32_t mtr_idx,
+					uint8_t domain_bitmap);
+typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm);
 typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
@@ -1409,10 +1411,12 @@ int mlx5_flow_validate_item_ecpri(const struct rte_flow_item *item,
 				  uint16_t ether_type,
 				  const struct rte_flow_item_ecpri *acc_mask,
 				  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);
+int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
+				uint32_t mtr_idx,
+				uint8_t domain_bitmap);
+void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter_info *fm);
 void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 759731333d..f789f2454e 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -4859,11 +4859,14 @@ 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,
+				bool *def_policy,
 				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_info *fm;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 
 	if (!am)
 		return rte_flow_error_set(error, EINVAL,
@@ -4894,10 +4897,40 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
 	      (!fm->ingress && !attr->ingress && attr->egress) ||
 	      (!fm->egress && !attr->egress && attr->ingress)))
 		return rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Flow attributes domain are either invalid "
+			"or have a domain conflict with current "
+			"meter attributes");
+	if (fm->def_policy) {
+		if (!((attr->transfer &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
+			(attr->egress &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
+			(attr->ingress &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
+			return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		*def_policy = true;
+	} else {
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+		if (!mtr_policy)
+			return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Invalid policy id for meter ");
+		if (!((attr->transfer && mtr_policy->transfer) ||
+			(attr->egress && mtr_policy->egress) ||
+			(attr->ingress && mtr_policy->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");
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		*def_policy = false;
+	}
 	return 0;
 }
 
@@ -6287,6 +6320,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		.fdb_def_rule = !!priv->fdb_def_rule,
 	};
 	const struct rte_eth_hairpin_conf *conf;
+	bool def_policy = false;
 
 	if (items == NULL)
 		return -1;
@@ -6628,6 +6662,12 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
 						  actions, "too many actions");
+		if (action_flags &
+			MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
+			return rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "meter action with policy "
+				"must be the last action");
 		switch (type) {
 		case RTE_FLOW_ACTION_TYPE_VOID:
 			break;
@@ -7030,10 +7070,14 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			ret = mlx5_flow_validate_action_meter(dev,
 							      action_flags,
 							      actions, attr,
+							      &def_policy,
 							      error);
 			if (ret < 0)
 				return ret;
 			action_flags |= MLX5_FLOW_ACTION_METER;
+			if (!def_policy)
+				action_flags |=
+				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
 			++actions_n;
 			/* Meter action will add one more TAG action. */
 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
@@ -7290,6 +7334,36 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 						 "multiple VLAN actions");
 		}
 	}
+	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
+		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
+			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
+			attr->ingress)
+			return rte_flow_error_set
+				(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "fate action not supported for "
+				"meter with policy");
+		if (attr->egress) {
+			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "modify header action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "encap action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "push vlan action in egress "
+					"cannot be done before meter action");
+		}
+	}
 	/*
 	 * Hairpin flow will add one more TAG action in TX implicit mode.
 	 * In TX explicit mode, there will be no hairpin flow ID.
@@ -14113,38 +14187,24 @@ flow_dv_query(struct rte_eth_dev *dev,
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
- * @param[in] tbl
- *   Pointer to the meter table set.
- *
- * @return
- *   Always 0.
+ * @param[in] fm
+ *   Meter information table.
  */
-static int
-flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
-			struct mlx5_meter_domains_infos *tbl)
+static void
+flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_meter_domains_infos *mtd =
-				(struct mlx5_meter_domains_infos *)tbl;
+	int i;
 
-	if (!mtd || !priv->config.dv_flow_en)
-		return 0;
-	if (mtd->egress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.tbl);
-	if (mtd->egress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.sfx_tbl);
-	if (mtd->ingress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->ingress.tbl);
-	if (mtd->ingress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->ingress.sfx_tbl);
-	if (mtd->transfer.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->transfer.tbl);
-	if (mtd->transfer.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->transfer.sfx_tbl);
-	mlx5_free(mtd);
-	return 0;
+	if (!fm || !priv->config.dv_flow_en)
+		return;
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
+		}
+	}
 }
 
 static void
@@ -14153,7 +14213,7 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct mlx5_flow_tbl_data_entry *tbl;
-	int i;
+	int i, j;
 
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (mtrmng->def_rule[i]) {
@@ -14168,12 +14228,16 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 				      &mtrmng->def_matcher[i]->entry);
 			mtrmng->def_matcher[i] = NULL;
 		}
-		if (mtrmng->drop_matcher[i]) {
-			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
-				struct mlx5_flow_tbl_data_entry, tbl);
-			mlx5_cache_unregister(&tbl->matchers,
-				      &mtrmng->drop_matcher[i]->entry);
-			mtrmng->drop_matcher[i] = NULL;
+		for (j = 0; j < MLX5_REG_BITS; j++) {
+			if (mtrmng->drop_matcher[i][j]) {
+				tbl =
+				container_of(mtrmng->drop_matcher[i][j]->tbl,
+					     struct mlx5_flow_tbl_data_entry,
+					     tbl);
+				mlx5_cache_unregister(&tbl->matchers,
+					&mtrmng->drop_matcher[i][j]->entry);
+				mtrmng->drop_matcher[i][j] = NULL;
+			}
 		}
 		if (mtrmng->drop_tbl[i]) {
 			flow_dv_tbl_resource_release(MLX5_SH(dev),
@@ -14626,96 +14690,171 @@ flow_dv_create_def_policy(struct rte_eth_dev *dev)
 }
 
 /**
- * Create specify domain meter table and suffix table.
+ * Create the needed meter tables.
+ * Lock free, (mutex should be acquired by caller).
  *
  * @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] fm
+ *   Meter information table.
+ * @param[in] mtr_idx
+ *   Meter index.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] domain_bitmap
+ *   Domain bitmap.
  * @return
  *   0 on success, -1 otherwise.
  */
 static int
-flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *mtb,
-			   uint8_t egress, uint8_t transfer)
+flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct rte_flow_error error;
-	struct mlx5_meter_domain_info *dtb;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	void *actions[METER_ACTIONS];
+	int domain, ret, i;
+	struct mlx5_flow_counter *cnt;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher_para = {
+		.size = sizeof(matcher_para.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
+						     0, &error);
+	uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
+	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+	};
+	struct mlx5_flow_dv_matcher *drop_matcher;
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = &error,
+		.data = &matcher,
+	};
 
-	if (transfer)
-		dtb = &mtb->transfer;
-	else if (egress)
-		dtb = &mtb->egress;
-	else
-		dtb = &mtb->ingress;
-	/* Create the meter suffix table with SUFFIX level. */
-	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
+	if (!priv->mtr_en || mtr_id_reg_c < 0) {
+		rte_errno = ENOTSUP;
+		return -1;
+	}
+	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
+		if (!(domain_bitmap & (1 << domain)) ||
+			(mtrmng->def_rule[domain] && !fm->drop_cnt))
+			continue;
+		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		/* Create the drop table with METER DROP level. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
 					MLX5_FLOW_TABLE_LEVEL_METER,
 					egress, transfer, false, NULL, 0,
-					0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
-	if (!dtb->sfx_tbl) {
-		DRV_LOG(ERR, "Failed to create meter suffix table.");
-		return -1;
+					0, MLX5_MTR_TABLE_ID_DROP, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create meter drop table.");
+				goto policy_error;
+			}
+		}
+		/* Create default matcher in drop table. */
+		matcher.tbl = mtrmng->drop_tbl[domain],
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		if (!mtrmng->def_matcher[domain]) {
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+				       (enum modify_reg)mtr_id_reg_c,
+				       0, 0);
+			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR, "Failed to register meter "
+				"drop default matcher.");
+				goto policy_error;
+			}
+			mtrmng->def_matcher[domain] = container_of(entry,
+			struct mlx5_flow_dv_matcher, entry);
+		}
+		/* Create default rule in drop table. */
+		if (!mtrmng->def_rule[domain]) {
+			i = 0;
+			actions[i++] = priv->sh->dr_drop_action;
+			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c, 0, 0);
+			ret = mlx5_flow_os_create_flow
+				(mtrmng->def_matcher[domain]->matcher_object,
+				(void *)&value, i, actions,
+				&mtrmng->def_rule[domain]);
+			if (ret) {
+				DRV_LOG(ERR, "Failed to create meter "
+				"default drop rule for drop table.");
+				goto policy_error;
+			}
+		}
+		if (!fm->drop_cnt)
+			continue;
+		MLX5_ASSERT(mtrmng->max_mtr_bits);
+		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
+			/* Create matchers for Drop. */
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+					(enum modify_reg)mtr_id_reg_c, 0,
+					(mtr_id_mask << mtr_id_offset));
+			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR,
+				"Failed to register meter drop matcher.");
+				goto policy_error;
+			}
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
+				container_of(entry, struct mlx5_flow_dv_matcher,
+					     entry);
+		}
+		drop_matcher =
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
+		/* Create drop rule, matching meter_id only. */
+		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c,
+				(mtr_idx << mtr_id_offset), UINT32_MAX);
+		i = 0;
+		cnt = flow_dv_counter_get_by_idx(dev,
+					fm->drop_cnt, NULL);
+		actions[i++] = cnt->action;
+		actions[i++] = priv->sh->dr_drop_action;
+		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
+					       (void *)&value, i, actions,
+					       &fm->drop_rule[domain]);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create meter "
+				"drop rule for drop table.");
+				goto policy_error;
+		}
 	}
 	return 0;
-}
-
-/**
- * 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 = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*mtb), 0, SOCKET_ID_ANY);
-	if (!mtb) {
-		DRV_LOG(ERR, "Failed to allocate memory for meter.");
-		return NULL;
-	}
-	/* Egress meter table. */
-	ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0);
-	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);
-	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);
-		if (ret) {
-			DRV_LOG(ERR, "Failed to prepare fdb meter table.");
-			goto error_exit;
+policy_error:
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
 		}
 	}
-	return mtb;
-error_exit:
-	flow_dv_destroy_mtr_tbl(dev, mtb);
-	return NULL;
+	return -1;
 }
 
 /**
@@ -15296,8 +15435,8 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.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,
+	.create_mtr_tbls = flow_dv_create_mtr_tbls,
+	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
 	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 8b004efd7d..fe608a33ec 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -665,9 +665,12 @@ mlx5_flow_meter_policy_create(struct rte_eth_dev *dev,
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (!(domain_bitmap & (1 << i)))
 			continue;
-		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
-		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
-		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		if (i == MLX5_MTR_DOMAIN_INGRESS)
+			mtr_policy->ingress = 1;
+		if (i == MLX5_MTR_DOMAIN_EGRESS)
+			mtr_policy->egress = 1;
+		if (i == MLX5_MTR_DOMAIN_TRANSFER)
+			mtr_policy->transfer = 1;
 		sub_policy = mlx5_ipool_zmalloc
 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
 				&sub_policy_idx);
@@ -779,6 +782,56 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * 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)
+{
+	/* Meter must use global drop action. */
+	if (!priv->sh->dr_drop_action)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL,
+					  "No drop action ready for meter.");
+	/* 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.");
+	if (params->meter_policy_id == MLX5_INVALID_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+	/* Validate meter id. */
+	if (mlx5_flow_meter_find(priv, meter_id, NULL))
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+			"Meter object already exists.");
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -884,13 +937,195 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 #endif
 }
 
-static void
-mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
+static int
+mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
 				uint64_t stats_mask)
 {
 	fm->bytes_dropped =
 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
+	if (fm->bytes_dropped || fm->pkts_dropped) {
+		if (!fm->drop_cnt) {
+			/* Alloc policer counters. */
+			fm->drop_cnt = mlx5_counter_alloc(dev);
+			if (!fm->drop_cnt)
+				return -1;
+		}
+	} else {
+		if (fm->drop_cnt) {
+			mlx5_counter_free(dev, fm->drop_cnt);
+			fm->drop_cnt = 0;
+		}
+	}
+	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_legacy_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_flow_meter_info *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_indexed_pool_config flow_ipool_cfg = {
+		.size = 0,
+		.trunk_size = 64,
+		.need_lock = 1,
+		.type = "mlx5_flow_mtr_flow_id_pool",
+	};
+	struct mlx5_aso_mtr *aso_mtr;
+	uint32_t mtr_idx, policy_idx;
+	union mlx5_l3t_data data;
+	int ret;
+	uint8_t domain_bitmap;
+	uint8_t mtr_id_bits;
+	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
+				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter is not supported");
+	/* 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.");
+	/* Meter policy must exist. */
+	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
+		__atomic_add_fetch
+			(&priv->sh->mtrmng->def_policy_ref_cnt,
+			1, __ATOMIC_RELAXED);
+		domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
+		if (!priv->config.dv_esw_en)
+			domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	} else {
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+				params->meter_policy_id, &policy_idx);
+		if (!priv->sh->meter_aso_en)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Part of the policies cannot be "
+				"supported without ASO ");
+		if (!mtr_policy)
+			return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+		domain_bitmap = (mtr_policy->ingress ?
+					MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
+				(mtr_policy->egress ?
+					MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
+				(mtr_policy->transfer ?
+					MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
+	}
+	/* Allocate the flow meter memory. */
+	if (priv->sh->meter_aso_en) {
+		mtr_idx = mlx5_flow_mtr_alloc(dev);
+		if (!mtr_idx)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+		fm = &aso_mtr->fm;
+	} else {
+		legacy_fm = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
+		if (legacy_fm == NULL)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		legacy_fm->idx = mtr_idx;
+		fm = &legacy_fm->fm;
+	}
+	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
+	if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
+	    mtr_reg_bits) {
+		DRV_LOG(ERR, "Meter number exceeds max limit.");
+		goto error;
+	}
+	if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
+		priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
+	/* Fill the flow meter parameters. */
+	fm->meter_id = meter_id;
+	fm->policy_id = params->meter_policy_id;
+	fm->profile = fmp;
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
+		goto error;
+	if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
+		goto error;
+	/* Add to the flow meter list. */
+	if (!priv->sh->meter_aso_en)
+		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
+	/* Add to the flow meter list. */
+	fm->active_state = 1; /* Config meter starts as active. */
+	fm->is_enable = 1;
+	fm->shared = !!shared;
+	__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
+	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
+		fm->def_policy = 1;
+		fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
+		if (!fm->flow_ipool)
+			goto error;
+	}
+	rte_spinlock_init(&fm->sl);
+	/* If ASO meter supported, update ASO flow meter by wqe. */
+	if (priv->sh->meter_aso_en) {
+		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
+		if (ret)
+			goto error;
+		if (!priv->mtr_idx_tbl) {
+			priv->mtr_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+			if (!priv->mtr_idx_tbl)
+				goto error;
+		}
+		data.dword = mtr_idx;
+		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
+			goto error;
+	}
+	if (mtr_policy)
+		__atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
+	return 0;
+error:
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	/* Free policer counters. */
+	if (fm->drop_cnt)
+		mlx5_counter_free(dev, fm->drop_cnt);
+	if (priv->sh->meter_aso_en)
+		mlx5_flow_mtr_free(dev, mtr_idx);
+	else
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
+	return -rte_mtr_error_set(error, ENOTSUP,
+		RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+		NULL, "Failed to create devx meter.");
 }
 
 static int
@@ -902,6 +1137,7 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
+	struct mlx5_flow_meter_policy *mtr_policy;
 
 	/* Meter object must not have any owner. */
 	MLX5_ASSERT(!fm->ref_cnt);
@@ -911,23 +1147,42 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 		return -1;
 	/* Update dependencies. */
 	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
+	fm->profile = NULL;
 	/* Remove from list. */
 	if (!priv->sh->meter_aso_en) {
-		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
+		legacy_fm = container_of(fm,
+			struct mlx5_legacy_flow_meter, fm);
 		TAILQ_REMOVE(fms, legacy_fm, next);
 	}
 	/* Free drop counters. */
 	if (fm->drop_cnt)
 		mlx5_counter_free(dev, fm->drop_cnt);
 	/* Free meter flow table. */
-	if (fm->flow_ipool)
+	if (fm->flow_ipool) {
 		mlx5_ipool_destroy(fm->flow_ipool);
-	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-	if (priv->sh->meter_aso_en)
+		fm->flow_ipool = 0;
+	}
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	if (fm->def_policy)
+		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
+				1, __ATOMIC_RELAXED);
+	if (priv->sh->meter_aso_en) {
+		if (!fm->def_policy) {
+			mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+			if (mtr_policy)
+				__atomic_sub_fetch(&mtr_policy->ref_cnt,
+						1, __ATOMIC_RELAXED);
+			fm->policy_id = 0;
+		}
+		fm->def_policy = 0;
+		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
+			return -1;
 		mlx5_flow_mtr_free(dev, mtr_idx);
-	else
+	} else {
 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
 					legacy_fm->idx);
+	}
 	return 0;
 }
 
@@ -954,30 +1209,28 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
-					  NULL, "Meter object id not valid.");
+					  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.");
-	if (priv->sh->meter_aso_en) {
-		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id))
-			return -rte_mtr_error_set(error, EBUSY,
-				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Fail to delete ASO Meter in index table.");
-	}
+					  NULL,
+					  "Meter object is being used.");
 	/* Destroy the meter profile. */
 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
 		return -rte_mtr_error_set(error, EINVAL,
 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+					NULL,
+					"MTR object meter profile invalid.");
 	return 0;
 }
 
@@ -1211,7 +1464,11 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
 					  NULL, "Meter object id not valid.");
-	mlx5_flow_meter_stats_enable_update(fm, stats_mask);
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_MTR_ID,
+					  NULL, "Fail to allocate "
+					  "counter for meter.");
 	return 0;
 }
 
@@ -1289,6 +1546,7 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.meter_policy_validate = mlx5_flow_meter_policy_validate,
 	.meter_policy_create = mlx5_flow_meter_policy_create,
 	.meter_policy_delete = mlx5_flow_meter_policy_delete,
+	.create = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -1327,7 +1585,7 @@ mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
  *   Pointer to Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
@@ -1342,30 +1600,27 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 
 	if (priv->sh->meter_aso_en) {
 		rte_spinlock_lock(&pools_mng->mtrsl);
-		if (priv->mtr_idx_tbl) {
-			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
-				meter_id, &data) ||
-				!data.dword) {
-				rte_spinlock_unlock(&pools_mng->mtrsl);
-				return NULL;
-			}
-			if (mtr_idx)
-				*mtr_idx = data.dword;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-			/* Remove reference taken by the mlx5_l3t_get_entry. */
-			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		} else {
-			if (mtr_idx)
-				*mtr_idx = meter_id;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
+		if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
 		}
+		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
+			!data.dword) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
+		}
+		if (mtr_idx)
+			*mtr_idx = data.dword;
+		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+		/* Remove reference taken by the mlx5_l3t_get_entry. */
+		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
 		rte_spinlock_unlock(&pools_mng->mtrsl);
 		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
 			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
-		if (meter_id == legacy_fm->meter_id) {
+		if (meter_id == legacy_fm->fm.meter_id) {
 			if (mtr_idx)
 				*mtr_idx = legacy_fm->idx;
 			return &legacy_fm->fm;
@@ -1382,7 +1637,7 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
  *   Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
@@ -1391,6 +1646,8 @@ flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
 
 	if (priv->sh->meter_aso_en) {
 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
+		if (!aso_mtr)
+			return NULL;
 		return &aso_mtr->fm;
 	} else {
 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
-- 
2.27.0


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

* [dpdk-dev] [PATCH v3 3/4] net/mlx5: prepare sub-policy for a flow with meter
  2021-04-13  0:19 ` [dpdk-dev] [PATCH v3 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 1/4] " Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 2/4] net/mlx5: support meter creation with policy Li Zhang
@ 2021-04-13  0:19   ` Li Zhang
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-13  0:19 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

When a flow has a RSS action, the driver splits
each sub flow finally is configured with
a different HW TIR action.

Any RSS action configured in meter policy may cause
a split in the flow configuration.
To save performance, any TIR action will be configured
in different flow table, so policy can be split to
sub-policies per TIR in the flow creation time.

Create a function to prepare the policy and
its sub-policies for a configured flow with meter.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.h    |  10 +++
 drivers/net/mlx5/mlx5_flow_dv.c | 144 ++++++++++++++++++++++++++++++++
 2 files changed, 154 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 89e43f2de6..cc9b37b9eb 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1095,6 +1095,11 @@ typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
 typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 				struct mlx5_flow_meter_info *fm);
 typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
+typedef struct mlx5_flow_meter_sub_policy *
+	(*mlx5_flow_meter_sub_policy_rss_prepare_t)
+		(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1187,6 +1192,7 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
 	mlx5_flow_create_def_policy_t create_def_policy;
 	mlx5_flow_destroy_def_policy_t destroy_def_policy;
+	mlx5_flow_meter_sub_policy_rss_prepare_t meter_sub_policy_rss_prepare;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1418,6 +1424,10 @@ int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
 void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_flow_meter_info *fm);
 void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
+struct mlx5_flow_meter_sub_policy *mlx5_flow_meter_sub_policy_rss_prepare
+		(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index f789f2454e..ed17bd903f 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -14857,6 +14857,149 @@ flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
 	return -1;
 }
 
+/**
+ * Find the policy table for prefix table with RSS.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ * @return
+ *   Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+	uint32_t sub_policy_idx = 0;
+	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
+	uint32_t i, j;
+	struct mlx5_hrxq *hrxq;
+	struct mlx5_flow_handle dh;
+	struct mlx5_meter_policy_action_container *act_cnt;
+	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
+		if (!hrxq_idx[i]) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return NULL;
+		}
+	}
+	sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+	for (i = 0; i < sub_policy_num;
+		i++) {
+		for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) {
+			if (rss_desc[j] &&
+				hrxq_idx[j] !=
+			mtr_policy->sub_policys[domain][i]->rix_hrxq[j])
+				break;
+		}
+		if (j >= MLX5_MTR_RTE_COLORS) {
+			/*
+			 * Found the sub policy table with
+			 * the same queue per color
+			 */
+			rte_spinlock_unlock(&mtr_policy->sl);
+			for (j = 0; j < MLX5_MTR_RTE_COLORS; j++)
+				mlx5_hrxq_release(dev, hrxq_idx[j]);
+			return mtr_policy->sub_policys[domain][i];
+		}
+	}
+	/* Create sub policy. */
+	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
+		/* Reuse the first dummy sub_policy*/
+		sub_policy = mtr_policy->sub_policys[domain][0];
+		sub_policy_idx = sub_policy->idx;
+	} else {
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy ||
+			sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto rss_sub_policy_error;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		sub_policy->rix_hrxq[i] = hrxq_idx[i];
+		/*
+		 * Overwrite the last action from
+		 * RSS action to Queue action.
+		 */
+		hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+			      hrxq_idx[i]);
+		if (!hrxq) {
+			DRV_LOG(ERR, "Failed to create policy hrxq");
+			goto rss_sub_policy_error;
+		}
+		act_cnt = &mtr_policy->act_cnt[i];
+		if (act_cnt->rix_mark || act_cnt->modify_hdr) {
+			memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+			if (act_cnt->rix_mark)
+				dh.mark = 1;
+			dh.fate_action = MLX5_FLOW_FATE_QUEUE;
+			dh.rix_hrxq = hrxq_idx[i];
+			flow_drv_rxq_flags_set(dev, &dh);
+		}
+	}
+	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+		sub_policy, domain)) {
+		DRV_LOG(ERR, "Failed to create policy "
+			"rules per domain.");
+		goto rss_sub_policy_error;
+	}
+	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+		i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		mtr_policy->sub_policys[domain][i] = sub_policy;
+		i++;
+		if (i > MLX5_MTR_RSS_MAX_SUB_POLICY)
+			goto rss_sub_policy_error;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
+		mtr_policy->sub_policy_num |=
+			(i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return sub_policy;
+rss_sub_policy_error:
+	if (sub_policy) {
+		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
+		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+			i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+			mtr_policy->sub_policys[domain][i] = NULL;
+			mlx5_ipool_free
+			(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
+		mlx5_hrxq_release(dev, hrxq_idx[i]);
+	if (sub_policy_idx)
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+			sub_policy_idx);
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return NULL;
+}
+
 /**
  * Validate the batch counter support in root table.
  *
@@ -15447,6 +15590,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
 	.create_def_policy = flow_dv_create_def_policy,
 	.destroy_def_policy = flow_dv_destroy_def_policy,
+	.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
-- 
2.27.0


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

* [dpdk-dev] [PATCH v3 4/4] net/mlx5: connect meter policy to created flows
  2021-04-13  0:19 ` [dpdk-dev] [PATCH v3 0/4] net/mlx5: support meter policy operations Li Zhang
                     ` (2 preceding siblings ...)
  2021-04-13  0:19   ` [dpdk-dev] [PATCH v3 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
@ 2021-04-13  0:19   ` Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-13  0:19 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs
  Cc: dev, thomas, rasland, roniba, Shun Hao

From: Shun Hao <shunh@nvidia.com>

Currently ASO meter must be followed by policy table, so this adds
the support that connecting meter and policy table.

There are several cases to be considered:
1. For non-termination policy, connect meter to the default policy
table.
2. For non-RSS termination policy case, simply get the policy
table id and connect meter to it.
3. For RSS termination policy case, need to split the flow due
to RSS info in policy, and translate each sub-flow using that RSS,
then create the sub policy table to be connected.
4. In termination policy case, if there's no actions to modify the
packet before meter, no need to use set_tag to save meter id in
register. Only add a new flow in drop table using the same match
criteria as suf-flow, to save cache miss.

Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 doc/guides/nics/mlx5.rst        |  12 +
 drivers/net/mlx5/mlx5_flow.c    | 446 ++++++++++++++++++++++++++++----
 drivers/net/mlx5/mlx5_flow.h    |   4 +
 drivers/net/mlx5/mlx5_flow_dv.c |  15 ++
 4 files changed, 420 insertions(+), 57 deletions(-)

diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index d287b3aca1..1e67a91ee7 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -106,6 +106,7 @@ Features
 - E-Switch mirroring and modify.
 - 21844 flow priorities for ingress or egress flow groups greater than 0 and for any transfer
   flow group.
+- Flow metering, including meter policy API.
 
 Limitations
 -----------
@@ -400,10 +401,21 @@ Limitations
   - Hairpin in switchdev SR-IOV mode is not supported till now.
 
 - Meter:
+
   - All the meter colors with drop action will be counted only by the global drop statistics.
   - Green color is not supported with drop action.
   - Yellow detection is not supported.
   - Red color must be with drop action.
+  - Meter statistics are supported only for drop case.
+  - Meter yellow color detection is not supported.
+  - A meter action created with pre-defined policy must be the last action in the flow except single case where the policy actions are:
+     - green: NULL or END.
+     - yellow: NULL or END.
+     - RED: DROP / END.
+  - The only supported meter policy actions:
+     - green: QUEUE, RSS, PORT_ID, JUMP, MARK and SET_TAG.
+     - yellow: must be empty.
+     - RED: must be DROP.
 
 Statistics
 ----------
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 77590bbbed..71fce4a524 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -3343,18 +3343,52 @@ flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 	fops->destroy(dev, flow);
 }
 
+/**
+ * Flow driver find RSS policy tbl API. This abstracts calling driver
+ * specific functions. Parent flow (rte_flow) should have driver
+ * type (drv_type). It will find the RSS policy table that has the rss_desc.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in, out] flow
+ *   Pointer to flow structure.
+ * @param[in] policy_id
+ *   The policy id of a meter.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_drv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+		struct rte_flow *flow,
+		struct mlx5_flow_meter_policy *policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	const struct mlx5_flow_driver_ops *fops;
+	enum mlx5_flow_drv_type type = flow->drv_type;
+
+	MLX5_ASSERT(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
+	fops = flow_get_drv_ops(type);
+	return fops->meter_sub_policy_rss_prepare(dev, policy, rss_desc);
+}
+
 /**
  * Get RSS action from the action list.
  *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
+ * @param[in] flow
+ *   Parent flow structure pointer.
  *
  * @return
  *   Pointer to the RSS action if exist, else return NULL.
  */
 static const struct rte_flow_action_rss*
-flow_get_rss_action(const struct rte_flow_action actions[])
+flow_get_rss_action(struct rte_eth_dev *dev,
+		    const struct rte_flow_action actions[])
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
 	const struct rte_flow_action_rss *rss = NULL;
 
 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -3372,6 +3406,23 @@ flow_get_rss_action(const struct rte_flow_action actions[])
 					rss = act->conf;
 			break;
 		}
+		case RTE_FLOW_ACTION_TYPE_METER:
+		{
+			uint32_t mtr_idx;
+			struct mlx5_flow_meter_info *fm;
+			struct mlx5_flow_meter_policy *policy;
+			const struct rte_flow_action_meter *mtr = actions->conf;
+
+			fm = mlx5_flow_meter_find(priv, mtr->mtr_id, &mtr_idx);
+			if (fm) {
+				policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+				if (policy && policy->is_rss)
+					rss =
+				policy->act_cnt[RTE_COLOR_GREEN].rss->conf;
+			}
+			break;
+		}
 		default:
 			break;
 		}
@@ -3670,13 +3721,75 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
 	return actions_n + 1;
 }
 
+/**
+ * Check if the action will change packet.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] type
+ *   action type.
+ *
+ * @return
+ *   true if action will change packet, false otherwise.
+ */
+static bool flow_check_modify_action_type(struct rte_eth_dev *dev,
+					  enum rte_flow_action_type type)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	switch (type) {
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
+	case RTE_FLOW_ACTION_TYPE_DEC_TTL:
+	case RTE_FLOW_ACTION_TYPE_SET_TTL:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_META:
+	case RTE_FLOW_ACTION_TYPE_SET_TAG:
+	case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+	case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
+		return true;
+	case RTE_FLOW_ACTION_TYPE_FLAG:
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		if (priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
+			return true;
+		else
+			return false;
+	default:
+		return false;
+	}
+}
+
 /**
  * Check meter action from the action list.
  *
+ * @param dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
  * @param[out] has_mtr
  *   Pointer to the meter exist flag.
+ * @param[out] has_modify
+ *   Pointer to the flag showing there's packet change action.
  * @param[out] meter_id
  *   Pointer to the meter id.
  *
@@ -3684,9 +3797,9 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
  *   Total number of actions.
  */
 static int
-flow_check_meter_action(const struct rte_flow_action actions[],
-			bool *has_mtr,
-			uint32_t *meter_id)
+flow_check_meter_action(struct rte_eth_dev *dev,
+			const struct rte_flow_action actions[],
+			bool *has_mtr, bool *has_modify, uint32_t *meter_id)
 {
 	const struct rte_flow_action_meter *mtr = NULL;
 	int actions_n = 0;
@@ -3703,6 +3816,9 @@ flow_check_meter_action(const struct rte_flow_action actions[],
 		default:
 			break;
 		}
+		if (!*has_mtr)
+			*has_modify |= flow_check_modify_action_type(dev,
+								actions->type);
 		actions_n++;
 	}
 	/* Count RTE_FLOW_ACTION_TYPE_END. */
@@ -4348,6 +4464,108 @@ flow_create_split_inner(struct rte_eth_dev *dev,
 	return flow_drv_translate(dev, dev_flow, attr, items, actions, error);
 }
 
+/**
+ * Get the sub policy of a meter.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
+ * @param[in] policy_id;
+ *   Meter Policy id.
+ * @param[in] attr
+ *   Flow rule attributes.
+ * @param[in] items
+ *   Pattern specification (list terminated by the END pattern item).
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   Pointer to the meter sub policy, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+get_meter_sub_policy(struct rte_eth_dev *dev,
+		     struct rte_flow *flow,
+		     uint32_t policy_id,
+		     const struct rte_flow_attr *attr,
+		     const struct rte_flow_item items[],
+		     struct rte_flow_error *error)
+{
+	struct mlx5_flow_meter_policy *policy;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+
+	policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	if (!policy) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Failed to find Meter Policy.");
+		goto exit;
+	}
+	if (policy->is_rss) {
+		struct mlx5_flow_workspace *wks =
+				mlx5_flow_get_thread_workspace();
+		struct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};
+		uint32_t i;
+
+		MLX5_ASSERT(wks);
+		/**
+		 * This is a tmp dev_flow,
+		 * no need to register any matcher for it in translate.
+		 */
+		wks->skip_matcher_reg = 1;
+		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+			struct mlx5_flow dev_flow = {0};
+			struct mlx5_flow_handle dev_handle = { {0} };
+			const void *rss_act = policy->act_cnt[i].rss->conf;
+			struct rte_flow_action rss_actions[2] = {
+				[0] = {
+					.type = RTE_FLOW_ACTION_TYPE_RSS,
+					.conf = rss_act
+				},
+				[1] = {
+					.type = RTE_FLOW_ACTION_TYPE_END,
+					.conf = NULL
+				}
+			};
+
+			dev_flow.handle = &dev_handle;
+			dev_flow.ingress = attr->ingress;
+			dev_flow.flow = flow;
+			dev_flow.external = 0;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+			dev_flow.dv.transfer = attr->transfer;
+#endif
+			/* Translate RSS action to get rss hash fields. */
+			if (flow_drv_translate(dev, &dev_flow, attr,
+						items, rss_actions, error))
+				goto exit;
+			rss_desc_v[i] = wks->rss_desc;
+			rss_desc_v[i].key_len = MLX5_RSS_HASH_KEY_LEN;
+			rss_desc_v[i].hash_fields = dev_flow.hash_fields;
+			rss_desc_v[i].queue_num = rss_desc_v[i].hash_fields ?
+						  rss_desc_v[i].queue_num : 1;
+			rss_desc[i] = &rss_desc_v[i];
+		}
+		sub_policy = flow_drv_meter_sub_policy_rss_prepare(dev,
+						flow, policy, rss_desc);
+	} else {
+		enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+		sub_policy = policy->sub_policys[mtr_domain][0];
+	}
+	if (!sub_policy) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Failed to get meter sub-policy.");
+		goto exit;
+	}
+exit:
+	return sub_policy;
+}
+
 /**
  * Split the meter flow.
  *
@@ -4378,13 +4596,15 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *   Suffix flow actions.
  * @param[out] actions_pre
  *   Prefix flow actions.
+ * @param[out] mtr_flow_id
+ *   Pointer to meter flow id.
  * @param[out] error
  *   Perform verbose error reporting if not NULL.
  *
  * @return
- *   The flow id, 0 otherwise and rte_errno is set.
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
-static uint32_t
+static int
 flow_meter_split_prep(struct rte_eth_dev *dev,
 		      struct rte_flow *flow,
 		      struct mlx5_flow_meter_info *fm,
@@ -4394,6 +4614,7 @@ 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[],
+		      uint32_t *mtr_flow_id,
 		      struct rte_flow_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
@@ -4407,7 +4628,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	uint32_t tag_id = 0;
 	bool copy_vlan = false;
 	struct rte_flow_action *hw_mtr_action;
-	struct rte_flow_action_jump *jump_data;
 	struct rte_flow_action *action_pre_head = NULL;
 	bool mtr_first = priv->sh->meter_aso_en &&
 			(attr->egress ||
@@ -4462,7 +4682,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 			break;
 		}
 		if (!action_cur)
-			action_cur = actions_sfx++;
+			action_cur = (fm->def_policy) ?
+					actions_sfx++ : actions_pre++;
 		memcpy(action_cur, actions, sizeof(struct rte_flow_action));
 	}
 	/* Add end action to the actions. */
@@ -4472,38 +4693,61 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		 * For ASO meter, need to add an extra jump action explicitly,
 		 * to jump from meter to policer table.
 		 */
-		hw_mtr_action = actions_pre;
-		hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
-		actions_pre++;
-		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
-		actions_pre++;
-		jump_data = (struct rte_flow_action_jump *)actions_pre;
-		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_POLICY;
-		hw_mtr_action->conf = jump_data;
-		actions_pre = (struct rte_flow_action *)(jump_data + 1);
-	} else {
-		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
-		actions_pre++;
+		struct mlx5_flow_meter_sub_policy *sub_policy;
+		struct mlx5_flow_tbl_data_entry *tbl_data;
+
+		if (!fm->def_policy) {
+			sub_policy = get_meter_sub_policy(dev, flow,
+							  fm->policy_id, attr,
+							  items, error);
+			if (!sub_policy)
+				return -rte_errno;
+		} else {
+			enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+
+			sub_policy =
+			&priv->sh->mtrmng->def_policy[mtr_domain]->sub_policy;
+		}
+		tbl_data = container_of(sub_policy->tbl_rsc,
+					struct mlx5_flow_tbl_data_entry, tbl);
+		hw_mtr_action = actions_pre++;
+		hw_mtr_action->type = (enum rte_flow_action_type)
+				      MLX5_RTE_FLOW_ACTION_TYPE_JUMP;
+		hw_mtr_action->conf = tbl_data->jump.action;
 	}
-	/* Generate meter flow_id only if support multiple flows per meter. */
-	mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
-	if (!tag_id)
+	actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+	actions_pre++;
+	if (!tag_action)
 		return rte_flow_error_set(error, ENOMEM,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Failed to allocate meter flow id.");
-	flow_id = tag_id - 1;
-	flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
-	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
-		mlx5_ipool_free(fm->flow_ipool, tag_id);
-		return rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Meter flow id exceeds max limit.");
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"No tag action space.");
+	if (!mtr_flow_id) {
+		tag_action->type = RTE_FLOW_ACTION_TYPE_VOID;
+		goto exit;
+	}
+	/* Only default-policy Meter creates mtr flow id. */
+	if (fm->def_policy) {
+		mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
+		if (!tag_id)
+			return rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to allocate meter flow id.");
+		flow_id = tag_id - 1;
+		flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
+		flow_id_bits = flow_id_bits ? flow_id_bits : 1;
+		if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) >
+		    mtr_reg_bits) {
+			mlx5_ipool_free(fm->flow_ipool, tag_id);
+			return rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter flow id exceeds max limit.");
+		}
+		if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+			priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	}
-	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
-		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -4533,7 +4777,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
 	sfx_items++;
 	/* Build tag actions and items for meter_id/meter flow_id. */
-	assert(tag_action);
 	set_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;
 	tag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;
 	tag_item_mask = tag_item_spec + 1;
@@ -4551,8 +4794,9 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	 */
 	for (shift = 0; shift < flow_id_bits; shift++)
 		flow_id_reversed = (flow_id_reversed << 1) |
-			      ((flow_id >> shift) & 0x1);
-	set_tag->data |= flow_id_reversed << (mtr_reg_bits - flow_id_bits);
+				((flow_id >> shift) & 0x1);
+	set_tag->data |=
+		flow_id_reversed << (mtr_reg_bits - flow_id_bits);
 	tag_item_spec->id = set_tag->id;
 	tag_item_spec->data = set_tag->data << mtr_id_offset;
 	tag_item_mask->data = UINT32_MAX << mtr_id_offset;
@@ -4564,7 +4808,10 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	tag_item->spec = tag_item_spec;
 	tag_item->last = NULL;
 	tag_item->mask = tag_item_mask;
-	return tag_id;
+exit:
+	if (mtr_flow_id)
+		*mtr_flow_id = tag_id;
+	return 0;
 }
 
 /**
@@ -5228,6 +5475,57 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/**
+ * Create meter internal drop flow with the original pattern.
+ *
+ * @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] flow_split_info
+ *   Pointer to flow split info structure.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   0 on success, negative value otherwise
+ */
+static uint32_t
+flow_meter_create_drop_flow_with_org_pattern(struct rte_eth_dev *dev,
+			struct rte_flow *flow,
+			const struct rte_flow_attr *attr,
+			const struct rte_flow_item items[],
+			struct mlx5_flow_split_info *flow_split_info,
+			struct mlx5_flow_meter_info *fm,
+			struct rte_flow_error *error)
+{
+	struct mlx5_flow *dev_flow = NULL;
+	struct rte_flow_attr drop_attr = *attr;
+	struct rte_flow_action drop_actions[3];
+	struct mlx5_flow_split_info drop_split_info = *flow_split_info;
+
+	MLX5_ASSERT(fm->drop_cnt);
+	drop_actions[0].type =
+		(enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_COUNT;
+	drop_actions[0].conf = (void *)(uintptr_t)fm->drop_cnt;
+	drop_actions[1].type = RTE_FLOW_ACTION_TYPE_DROP;
+	drop_actions[1].conf = NULL;
+	drop_actions[2].type = RTE_FLOW_ACTION_TYPE_END;
+	drop_actions[2].conf = NULL;
+	drop_split_info.external = false;
+	drop_split_info.skip_scale |= 1 << MLX5_SCALE_FLOW_GROUP_BIT;
+	drop_split_info.table_id = MLX5_MTR_TABLE_ID_DROP;
+	drop_attr.group = MLX5_FLOW_TABLE_LEVEL_METER;
+	return flow_create_split_inner(dev, flow, &dev_flow,
+				&drop_attr, items, drop_actions,
+				&drop_split_info, error);
+}
+
 /**
  * The splitting for meter feature.
  *
@@ -5272,18 +5570,21 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 	struct mlx5_flow *dev_flow = NULL;
 	struct rte_flow_attr sfx_attr = *attr;
 	struct mlx5_flow_meter_info *fm = NULL;
+	uint8_t skip_scale_restore;
 	bool has_mtr = false;
-	uint32_t meter_id;
+	bool has_modify = false;
+	bool set_mtr_reg = true;
+	uint32_t meter_id = 0;
 	uint32_t mtr_idx = 0;
-	uint32_t mtr_tag_id = 0;
+	uint32_t mtr_flow_id = 0;
 	size_t act_size;
 	size_t item_size;
 	int actions_n = 0;
 	int ret = 0;
 
 	if (priv->mtr_en)
-		actions_n = flow_check_meter_action(actions, &has_mtr,
-						    &meter_id);
+		actions_n = flow_check_meter_action(dev, actions, &has_mtr,
+						    &has_modify, &meter_id);
 	if (has_mtr) {
 		if (flow->meter) {
 			fm = flow_dv_meter_find_by_idx(priv, flow->meter);
@@ -5303,11 +5604,20 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 				return -rte_errno;
 			flow->meter = mtr_idx;
 		}
+		MLX5_ASSERT(wks);
 		wks->fm = fm;
+		/*
+		 * If it isn't default-policy Meter, and
+		 * 1. There's no action in flow to change
+		 *    packet (modify/encap/decap etc.), OR
+		 * 2. No drop count needed for this meter.
+		 * no need to use regC to save meter id anymore.
+		 */
+		if (!fm->def_policy && (!has_modify || !fm->drop_cnt))
+			set_mtr_reg = false;
 		/* Prefix actions: meter, decap, encap, tag, jump, end. */
 		act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
-			   sizeof(struct mlx5_rte_flow_action_set_tag) +
-			   sizeof(struct rte_flow_action_jump);
+			   sizeof(struct mlx5_rte_flow_action_set_tag);
 		/* Suffix items: tag, vlan, port id, end. */
 #define METER_SUFFIX_ITEM 4
 		item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
@@ -5321,27 +5631,48 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 						  "meter flow");
 		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
 			     act_size);
-		pre_actions = sfx_actions + actions_n;
-		mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
-						   items, sfx_items, actions,
-						   sfx_actions, pre_actions,
-						   error);
-		if (!mtr_tag_id) {
+		/* There's no suffix flow for meter of non-default policy. */
+		if (!fm->def_policy)
+			pre_actions = sfx_actions + 1;
+		else
+			pre_actions = sfx_actions + actions_n;
+		ret = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+					    items, sfx_items, actions,
+					    sfx_actions, pre_actions,
+					    (set_mtr_reg ? &mtr_flow_id : NULL),
+					    error);
+		if (ret) {
 			ret = -rte_errno;
 			goto exit;
 		}
 		/* Add the prefix subflow. */
 		flow_split_info->prefix_mark = 0;
+		skip_scale_restore = flow_split_info->skip_scale;
+		flow_split_info->skip_scale |=
+			1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT;
 		ret = flow_create_split_inner(dev, flow, &dev_flow,
 					      attr, items, pre_actions,
 					      flow_split_info, error);
+		flow_split_info->skip_scale = skip_scale_restore;
 		if (ret) {
-			mlx5_ipool_free(fm->flow_ipool, mtr_tag_id);
+			if (mtr_flow_id)
+				mlx5_ipool_free(fm->flow_ipool, mtr_flow_id);
 			ret = -rte_errno;
 			goto exit;
 		}
-		dev_flow->handle->split_flow_id = mtr_tag_id;
-		dev_flow->handle->is_meter_flow_id = 1;
+		if (mtr_flow_id) {
+			dev_flow->handle->split_flow_id = mtr_flow_id;
+			dev_flow->handle->is_meter_flow_id = 1;
+		}
+		if (!fm->def_policy) {
+			if (!set_mtr_reg && fm->drop_cnt)
+				ret =
+			flow_meter_create_drop_flow_with_org_pattern(dev, flow,
+							&sfx_attr, items,
+							flow_split_info,
+							fm, error);
+			goto exit;
+		}
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
 				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
@@ -5349,6 +5680,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 		flow_split_info->prefix_layers =
 				flow_get_prefix_layer_flags(dev_flow);
 		flow_split_info->prefix_mark = dev_flow->handle->mark;
+		flow_split_info->table_id = MLX5_MTR_TABLE_ID_SUFFIX;
 	}
 	/* Add the prefix subflow. */
 	ret = flow_create_split_metadata(dev, flow,
@@ -5736,7 +6068,7 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,
 	memset(rss_desc, 0, offsetof(struct mlx5_flow_rss_desc, queue));
 	/* RSS Action only works on NIC RX domain */
 	if (attr->ingress && !attr->transfer)
-		rss = flow_get_rss_action(p_actions_rx);
+		rss = flow_get_rss_action(dev, p_actions_rx);
 	if (rss) {
 		if (flow_rss_workspace_adjust(wks, rss_desc, rss->queue_num))
 			return 0;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index cc9b37b9eb..8a0a84a604 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -37,6 +37,8 @@ enum mlx5_rte_flow_action_type {
 	MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS,
 	MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET,
 	MLX5_RTE_FLOW_ACTION_TYPE_AGE,
+	MLX5_RTE_FLOW_ACTION_TYPE_JUMP,
+	MLX5_RTE_FLOW_ACTION_TYPE_COUNT,
 };
 
 #define MLX5_SHARED_ACTION_TYPE_OFFSET 30
@@ -1048,6 +1050,8 @@ struct mlx5_flow_workspace {
 	uint32_t rssq_num; /* Allocated queue num in rss_desc. */
 	uint32_t flow_idx; /* Intermediate device flow index. */
 	struct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */
+	uint32_t skip_matcher_reg:1;
+	/* Indicates if need to skip matcher register in translate. */
 };
 
 struct mlx5_flow_split_info {
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index ed17bd903f..eedbe2e43b 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7423,6 +7423,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,
 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
 
 	MLX5_ASSERT(wks);
+	wks->skip_matcher_reg = 0;
 	/* In case of corrupting the memory. */
 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
 		rte_flow_error_set(error, ENOSPC,
@@ -11254,6 +11255,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
 		int action_type = actions->type;
 		const struct rte_flow_action *found_action = NULL;
 		uint32_t jump_group = 0;
+		struct mlx5_flow_counter *cnt;
 
 		if (!mlx5_flow_os_action_supported(action_type))
 			return rte_flow_error_set(error, ENOTSUP,
@@ -11434,6 +11436,12 @@ flow_dv_translate(struct rte_eth_dev *dev,
 				age = action->conf;
 			action_flags |= MLX5_FLOW_ACTION_COUNT;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
+			cnt = flow_dv_counter_get_by_idx(dev,
+				(uint32_t)(uintptr_t)action->conf, NULL);
+			MLX5_ASSERT(cnt != NULL);
+			dev_flow->dv.actions[actions_n++] = cnt->action;
+			break;
 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
 			dev_flow->dv.actions[actions_n++] =
 						priv->sh->pop_vlan_action;
@@ -11538,6 +11546,11 @@ flow_dv_translate(struct rte_eth_dev *dev,
 			/* If decap is followed by encap, handle it at encap. */
 			action_flags |= MLX5_FLOW_ACTION_DECAP;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
+			dev_flow->dv.actions[actions_n++] =
+				(void *)(uintptr_t)action->conf;
+			action_flags |= MLX5_FLOW_ACTION_JUMP;
+			break;
 		case RTE_FLOW_ACTION_TYPE_JUMP:
 			jump_group = ((const struct rte_flow_action_jump *)
 							action->conf)->group;
@@ -12093,6 +12106,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
 	}
 	dev_flow->dv.actions_n = actions_n;
 	dev_flow->act_flags = action_flags;
+	if (wks->skip_matcher_reg)
+		return 0;
 	/* Register matcher. */
 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
 				    matcher.mask.size);
-- 
2.27.0


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

* [dpdk-dev] [PATCH v4 0/4] net/mlx5: support meter policy operations
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (5 preceding siblings ...)
  2021-04-13  0:19 ` [dpdk-dev] [PATCH v3 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-14  6:40 ` Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 1/4] " Li Zhang
                     ` (3 more replies)
  2021-04-15  5:05 ` [dpdk-dev] [PATCH v5 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (3 subsequent siblings)
  10 siblings, 4 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-14  6:40 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Depends-on: series=16351  ("Add ASO meter support in MLX5 PMD ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16351

Depends-on: series=16357  ("Support meter policy API ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16357

V2: Add MLX5_MTR_DEFAULT_POLICY_ID in MLX5 PMD
V3: Fix comments about Depends-on
V4: Fix comments about rte_mtr_meter_policy_add.

Li Zhang (3):
  net/mlx5: support meter policy operations
  net/mlx5: support meter creation with policy
  net/mlx5: prepare sub-policy for a flow with meter

Shun Hao (1):
  net/mlx5: connect meter policy to created flows

 doc/guides/nics/mlx5.rst           |   12 +
 drivers/net/mlx5/linux/mlx5_os.c   |   13 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  216 +++-
 drivers/net/mlx5/mlx5_flow.c       |  639 ++++++++--
 drivers/net/mlx5/mlx5_flow.h       |  116 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1868 ++++++++++++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_meter.c |  740 ++++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 10 files changed, 3340 insertions(+), 352 deletions(-)

-- 
2.27.0


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

* [dpdk-dev] [PATCH v4 1/4] net/mlx5: support meter policy operations
  2021-04-14  6:40 ` [dpdk-dev] [PATCH v4 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-14  6:40   ` Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 2/4] net/mlx5: support meter creation with policy Li Zhang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-14  6:40 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

Implement the next policy operations:
validate:
The driver doesn't support to configure actions in the flow
after the meter action except one case when the meter policy
is configured to do nothing in GREEN\YELLOW and only DROP action
in RED, this special policy is called non-terminated policy
and is handed as a singleton object internally.

For all the terminated policies, the next actions are supported:
GREEN - QUEUE, RSS, PORT_ID, JUMP, DROP, MARK and SET_TAG.
YELLOW - not supported at all -> must be empty.
RED - must include DROP action.

Hence, in ingress case, for example,
QUEUE\RSS\JUMP must be configured as last action for GREEN color.

All the above limitations will be validated.

create:
Validate the policy configuration.
Prepare the related tables and actions.

destroy:
Release the created policy resources.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |    2 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  158 +++-
 drivers/net/mlx5/mlx5_flow.c       |  192 +++-
 drivers/net/mlx5/mlx5_flow.h       |   73 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1412 +++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c |  445 ++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 9 files changed, 2242 insertions(+), 128 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index bec288c840..276283d492 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1299,7 +1299,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			log_obj_size <=
 			config->hca_attr.qos.log_meter_aso_max_alloc) {
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv);
+				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
 				if (err) {
 					err = -err;
 					goto error;
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 572db1bc67..b4cdaa7131 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -350,6 +350,20 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {
 		.free = mlx5_free,
 		.type = "mlx5_shared_action_rss",
 	},
+	[MLX5_IPOOL_MTR_POLICY] = {
+		/**
+		 * The ipool index should grow continually from small to big,
+		 * for policy idx, so not set grow_trunk to avoid policy index
+		 * not jump continually.
+		 */
+		.size = sizeof(struct mlx5_flow_meter_sub_policy),
+		.trunk_size = 64,
+		.need_lock = 1,
+		.release_mem_en = 1,
+		.malloc = mlx5_malloc,
+		.free = mlx5_free,
+		.type = "mlx5_meter_policy_ipool",
+	},
 };
 
 
@@ -569,27 +583,25 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh)
  *   Pointer to mlx5_dev_ctx_shared object to free
  */
 int
-mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv)
+mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!priv->mtr_idx_tbl) {
-		priv->mtr_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
-		if (!priv->mtr_idx_tbl) {
-			DRV_LOG(ERR, "fail to create meter lookup table.");
-			rte_errno = ENOMEM;
-			return -ENOMEM;
-		}
-	}
-	if (!priv->sh->mtrmng) {
-		priv->sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
-			sizeof(*priv->sh->mtrmng),
+	if (!sh->mtrmng) {
+		sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(*sh->mtrmng),
 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
-		if (!priv->sh->mtrmng) {
-			DRV_LOG(ERR, "mlx5_aso_mtr_pools_mng allocation was failed.");
+		if (!sh->mtrmng) {
+			DRV_LOG(ERR,
+			"meter management allocation was failed.");
 			rte_errno = ENOMEM;
 			return -ENOMEM;
 		}
-		rte_spinlock_init(&priv->sh->mtrmng->mtrsl);
-		LIST_INIT(&priv->sh->mtrmng->meters);
+		if (sh->meter_aso_en) {
+			rte_spinlock_init(&sh->mtrmng->pools_mng.mtrsl);
+			LIST_INIT(&sh->mtrmng->pools_mng.meters);
+			sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		}
+		sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
 	}
 	return 0;
 }
@@ -605,31 +617,34 @@ static void
 mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
 {
 	struct mlx5_aso_mtr_pool *mtr_pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng;
+	struct mlx5_flow_mtr_mng *mtrmng = sh->mtrmng;
 	uint32_t idx;
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
 	struct mlx5_aso_mtr *aso_mtr;
 	int i;
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
 
-	mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
-	idx = mtrmng->n_valid;
-	while (idx--) {
-		mtr_pool = mtrmng->pools[idx];
+	if (sh->meter_aso_en) {
+		mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
+		idx = mtrmng->pools_mng.n_valid;
+		while (idx--) {
+			mtr_pool = mtrmng->pools_mng.pools[idx];
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
-		for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
-			aso_mtr = &mtr_pool->mtrs[i];
-			if (aso_mtr->fm.meter_action)
-				claim_zero(mlx5_glue->destroy_flow_action
-						(aso_mtr->fm.meter_action));
-		}
+			for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
+				aso_mtr = &mtr_pool->mtrs[i];
+				if (aso_mtr->fm.meter_action)
+					claim_zero
+					(mlx5_glue->destroy_flow_action
+					(aso_mtr->fm.meter_action));
+			}
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
-		claim_zero(mlx5_devx_cmd_destroy
+			claim_zero(mlx5_devx_cmd_destroy
 						(mtr_pool->devx_obj));
-		mtrmng->n_valid--;
-		mlx5_free(mtr_pool);
+			mtrmng->pools_mng.n_valid--;
+			mlx5_free(mtr_pool);
+		}
+		mlx5_free(sh->mtrmng->pools_mng.pools);
 	}
-	mlx5_free(sh->mtrmng->pools);
 	mlx5_free(sh->mtrmng);
 	sh->mtrmng = NULL;
 }
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index a8e11023cc..cb7c75aa2e 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -56,6 +56,7 @@ enum mlx5_ipool_index {
 	MLX5_IPOOL_RTE_FLOW, /* Pool for rte_flow. */
 	MLX5_IPOOL_RSS_EXPANTION_FLOW_ID, /* Pool for Queue/RSS flow ID. */
 	MLX5_IPOOL_RSS_SHARED_ACTIONS, /* Pool for RSS shared actions. */
+	MLX5_IPOOL_MTR_POLICY, /* Pool for meter policy resource. */
 	MLX5_IPOOL_MAX,
 };
 
@@ -580,9 +581,126 @@ struct mlx5_dev_shared_port {
 	/* Aging information for per port. */
 };
 
+/*
+ * Max number of actions per DV flow.
+ * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
+ * in rdma-core file providers/mlx5/verbs.c.
+ */
+#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
+
 /*ASO flow meter structures*/
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
+/* Yellow is not supported. */
+#define MLX5_MTR_RTE_COLORS (RTE_COLOR_GREEN + 1)
+/* table_id 22 bits in mlx5_flow_tbl_key so limit policy number. */
+#define MLX5_MAX_SUB_POLICY_TBL_NUM 0x3FFFFF
+#define MLX5_INVALID_POLICY_ID UINT32_MAX
+/* Suffix table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_SUFFIX 1
+/* Drop table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_DROP 2
+
+enum mlx5_meter_domain {
+	MLX5_MTR_DOMAIN_INGRESS,
+	MLX5_MTR_DOMAIN_EGRESS,
+	MLX5_MTR_DOMAIN_TRANSFER,
+	MLX5_MTR_DOMAIN_MAX,
+};
+#define MLX5_MTR_DOMAIN_INGRESS_BIT  (1 << MLX5_MTR_DOMAIN_INGRESS)
+#define MLX5_MTR_DOMAIN_EGRESS_BIT   (1 << MLX5_MTR_DOMAIN_EGRESS)
+#define MLX5_MTR_DOMAIN_TRANSFER_BIT (1 << MLX5_MTR_DOMAIN_TRANSFER)
+#define MLX5_MTR_ALL_DOMAIN_BIT      (MLX5_MTR_DOMAIN_INGRESS_BIT | \
+					MLX5_MTR_DOMAIN_EGRESS_BIT | \
+					MLX5_MTR_DOMAIN_TRANSFER_BIT)
+
+/*
+ * Meter sub-policy structure.
+ * Each RSS TIR in meter policy need its own sub-policy resource.
+ */
+struct mlx5_flow_meter_sub_policy {
+	uint32_t main_policy_id:1;
+	/* Main policy id is same as this sub_policy id. */
+	uint32_t idx:31;
+	/* Index to sub_policy ipool entity. */
+	void *main_policy;
+	/* Point to struct mlx5_flow_meter_policy. */
+	struct mlx5_flow_tbl_resource *tbl_rsc;
+	/* The sub-policy table resource. */
+	uint32_t rix_hrxq[MLX5_MTR_RTE_COLORS];
+	/* Index to TIR resource. */
+	struct mlx5_flow_tbl_resource *jump_tbl[MLX5_MTR_RTE_COLORS];
+	/* Meter jump/drop table. */
+	struct mlx5_flow_dv_matcher *color_matcher[RTE_COLORS];
+	/* Matcher for Color. */
+	void *color_rule[RTE_COLORS];
+	/* Meter green/yellow/drop rule. */
+};
+
+struct mlx5_meter_policy_acts {
+	uint8_t actions_n;
+	/* Number of actions. */
+	void *dv_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS];
+	/* Action list. */
+};
+
+struct mlx5_meter_policy_action_container {
+	uint32_t rix_mark;
+	/* Index to the mark action. */
+	struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
+	/* Pointer to modify header resource in cache. */
+	uint8_t fate_action;
+	/* Fate action type. */
+	union {
+		struct rte_flow_action *rss;
+		/* Rss action configuration. */
+		uint32_t rix_port_id_action;
+		/* Index to port ID action resource. */
+		void *dr_jump_action[MLX5_MTR_DOMAIN_MAX];
+		/* Jump/drop action per color. */
+	};
+};
+
+/* Flow meter policy parameter structure. */
+struct mlx5_flow_meter_policy {
+	uint32_t is_rss:1;
+	/* Is RSS policy table. */
+	uint32_t ingress:1;
+	/* Rule applies to ingress domain. */
+	uint32_t egress:1;
+	/* Rule applies to egress domain. */
+	uint32_t transfer:1;
+	/* Rule applies to transfer domain. */
+	rte_spinlock_t sl;
+	uint32_t ref_cnt;
+	/* Use count. */
+	struct mlx5_meter_policy_action_container act_cnt[MLX5_MTR_RTE_COLORS];
+	/* Policy actions container. */
+	void *dr_drop_action[MLX5_MTR_DOMAIN_MAX];
+	/* drop action for red color. */
+	uint16_t sub_policy_num;
+	/* Count sub policy tables, 3 bits per domain. */
+	struct mlx5_flow_meter_sub_policy **sub_policys[MLX5_MTR_DOMAIN_MAX];
+	/* Sub policy table array must be the end of struct. */
+};
+
+/* The maximum sub policy is relate to struct mlx5_rss_hash_fields[]. */
+#define MLX5_MTR_RSS_MAX_SUB_POLICY 7
+#define MLX5_MTR_SUB_POLICY_NUM_SHIFT  3
+#define MLX5_MTR_SUB_POLICY_NUM_MASK  0x7
+#define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
+
+/* Flow meter default policy parameter structure.
+ * Policy index 0 is reserved by default policy table.
+ * Action per color as below:
+ * green - do nothing, yellow - do nothing, red - drop
+ */
+struct mlx5_flow_meter_def_policy {
+	struct mlx5_flow_meter_sub_policy sub_policy;
+	/* Policy rules jump to other tables. */
+	void *dr_jump_action[RTE_COLORS];
+	/* Jump action per color. */
+};
 
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
@@ -746,6 +864,28 @@ struct mlx5_aso_mtr_pools_mng {
 	struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */
 };
 
+/* Meter management structure for global flow meter resource. */
+struct mlx5_flow_mtr_mng {
+	struct mlx5_aso_mtr_pools_mng pools_mng;
+	/* Pools management structure for ASO flow meter pools. */
+	struct mlx5_flow_meter_def_policy *def_policy[MLX5_MTR_DOMAIN_MAX];
+	/* Default policy table. */
+	uint32_t def_policy_id;
+	/* Default policy id. */
+	uint32_t def_policy_ref_cnt;
+	/** def_policy meter use count. */
+	struct mlx5_l3t_tbl *policy_idx_tbl;
+	/* Policy index lookup table. */
+	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop table. */
+	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Matcher meter in drop table. */
+	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Default matcher in drop table. */
+	void *def_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Default rule in drop table. */
+};
+
 /* Table key of the hash organization. */
 union mlx5_flow_tbl_key {
 	struct {
@@ -772,9 +912,9 @@ struct mlx5_flow_tbl_resource {
 #define MLX5_FLOW_MREG_ACT_TABLE_GROUP (MLX5_MAX_TABLES - 1)
 #define MLX5_FLOW_MREG_CP_TABLE_GROUP (MLX5_MAX_TABLES - 2)
 /* Tables for metering splits should be added here. */
-#define MLX5_FLOW_TABLE_LEVEL_SUFFIX (MLX5_MAX_TABLES - 3)
-#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 4)
-#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_METER
+#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 3)
+#define MLX5_FLOW_TABLE_LEVEL_POLICY (MLX5_MAX_TABLES - 4)
+#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_POLICY
 #define MLX5_MAX_TABLES_FDB UINT16_MAX
 #define MLX5_FLOW_TABLE_FACTOR 10
 
@@ -935,8 +1075,8 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_geneve_tlv_option_resource *geneve_tlv_option_resource;
 	/* Management structure for geneve tlv option */
 	rte_spinlock_t geneve_tlv_opt_sl; /* Lock for geneve tlv resource */
-	struct mlx5_aso_mtr_pools_mng *mtrmng;
-	/* Meter pools management structure. */
+	struct mlx5_flow_mtr_mng *mtrmng;
+	/* Meter management structure. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
 
@@ -1237,7 +1377,7 @@ int mlx5_hairpin_cap_get(struct rte_eth_dev *dev,
 bool mlx5_flex_parser_ecpri_exist(struct rte_eth_dev *dev);
 int mlx5_flex_parser_ecpri_alloc(struct rte_eth_dev *dev);
 int mlx5_flow_aso_age_mng_init(struct mlx5_dev_ctx_shared *sh);
-int mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv);
+int mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh);
 
 /* mlx5_ethdev.c */
 
@@ -1463,6 +1603,12 @@ int mlx5_flow_meter_attach(struct mlx5_priv *priv,
 			   struct rte_flow_error *error);
 void mlx5_flow_meter_detach(struct mlx5_priv *priv,
 			    struct mlx5_flow_meter_info *fm);
+struct mlx5_flow_meter_policy *mlx5_flow_meter_policy_find
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		uint32_t *policy_idx);
+int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
+			  struct rte_mtr_error *error);
 
 /* mlx5_os.c */
 struct rte_pci_driver;
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ee2c351649..81e0e3b7a9 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1028,7 +1028,7 @@ flow_rxq_tunnel_ptype_update(struct mlx5_rxq_ctrl *rxq_ctrl)
  * @param[in] dev_handle
  *   Pointer to device flow handle structure.
  */
-static void
+void
 flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
 		       struct mlx5_flow_handle *dev_handle)
 {
@@ -4479,8 +4479,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		actions_pre++;
 		jump_data = (struct rte_flow_action_jump *)actions_pre;
 		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_METER;
+				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_POLICY;
 		hw_mtr_action->conf = jump_data;
 		actions_pre = (struct rte_flow_action *)(jump_data + 1);
 	} else {
@@ -5079,8 +5079,8 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	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);
+			  (MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+			  MLX5_FLOW_TABLE_LEVEL_METER);
 		/*
 		 * 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
@@ -5344,8 +5344,8 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 		dev_flow->handle->is_meter_flow_id = 1;
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_SUFFIX;
+				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_METER;
 		flow_split_info->prefix_layers =
 				flow_get_prefix_layer_flags(dev_flow);
 		flow_split_info->prefix_mark = dev_flow->handle->mark;
@@ -6608,6 +6608,169 @@ mlx5_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
 	return 0;
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] is_rss
+ *   Is RSS or not.
+ * @param[out] domain_bitmap
+ *   Domain bitmap.
+ * @param[out] is_def_policy
+ *   Is default policy or not.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->validate_mtr_acts(dev, actions, attr,
+			is_rss, domain_bitmap, is_def_policy, error);
+}
+
+/**
+ * Destroy the meter table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_acts(dev, mtr_policy);
+}
+
+/**
+ * Create policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_mtr_acts(dev, mtr_policy, actions, error);
+}
+
+/**
+ * Create policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_def_policy(dev);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_def_policy(dev);
+}
+
 /**
  * Create the needed meter and suffix tables.
  *
@@ -6647,6 +6810,21 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
+/**
+ * Destroy the global meter drop table.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_drop_tbls(dev);
+}
+
 /**
  * Allocate the needed aso flow meter id.
  *
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 7fa15eef7b..51d040c4d2 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -691,13 +691,6 @@ struct mlx5_flow_handle {
 #define MLX5_FLOW_HANDLE_VERBS_SIZE (sizeof(struct mlx5_flow_handle))
 #endif
 
-/*
- * Max number of actions per DV flow.
- * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
- * in rdma-core file providers/mlx5/verbs.c.
- */
-#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
-
 /** Device flow structure only for DV flow creation. */
 struct mlx5_flow_dv_workspace {
 	uint32_t group; /**< The group index. */
@@ -1099,6 +1092,7 @@ 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);
+typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1144,6 +1138,32 @@ typedef int (*mlx5_flow_sync_domain_t)
 			(struct rte_eth_dev *dev,
 			 uint32_t domains,
 			 uint32_t flags);
+typedef int (*mlx5_flow_validate_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+			 const struct rte_flow_action *actions[RTE_COLORS],
+			 struct rte_flow_attr *attr,
+			 bool *is_rss,
+			 uint8_t *domain_bitmap,
+			 bool *is_def_policy,
+			 struct rte_mtr_error *error);
+typedef int (*mlx5_flow_create_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+typedef void (*mlx5_flow_destroy_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef void (*mlx5_flow_destroy_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_def_policy_t)
+			(struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_destroy_def_policy_t)
+			(struct rte_eth_dev *dev);
 
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
@@ -1155,8 +1175,16 @@ 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_destroy_mtr_drop_tbls_t destroy_mtr_drop_tbls;
 	mlx5_flow_mtr_alloc_t create_meter;
 	mlx5_flow_mtr_free_t free_meter;
+	mlx5_flow_validate_mtr_acts_t validate_mtr_acts;
+	mlx5_flow_create_mtr_acts_t create_mtr_acts;
+	mlx5_flow_destroy_mtr_acts_t destroy_mtr_acts;
+	mlx5_flow_create_policy_rules_t create_policy_rules;
+	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
+	mlx5_flow_create_def_policy_t create_def_policy;
+	mlx5_flow_destroy_def_policy_t destroy_def_policy;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1233,12 +1261,13 @@ static inline struct mlx5_aso_mtr *
 mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)
 {
 	struct mlx5_aso_mtr_pool *pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 
 	/* Decrease to original index. */
 	idx--;
-	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < mtrmng->n);
-	pool = mtrmng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
+	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n);
+	pool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
 	return &pool->mtrs[idx % MLX5_ASO_MTRS_PER_POOL];
 }
 
@@ -1384,8 +1413,7 @@ 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_meter_flush(struct rte_eth_dev *dev,
-			  struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
@@ -1486,4 +1514,25 @@ int mlx5_flow_os_set_specific_workspace(struct mlx5_flow_workspace *data);
 void mlx5_flow_os_release_workspace(void);
 uint32_t mlx5_flow_mtr_alloc(struct rte_eth_dev *dev);
 void mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx);
+int mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+int mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+void mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_def_policy(struct rte_eth_dev *dev);
+void mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev);
+void flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
+		       struct mlx5_flow_handle *dev_handle);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c
index 62d2df054b..20cd4fe18c 100644
--- a/drivers/net/mlx5/mlx5_flow_aso.c
+++ b/drivers/net/mlx5/mlx5_flow_aso.c
@@ -311,11 +311,11 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh,
 		mlx5_aso_age_init_sq(&sh->aso_age_mng->aso_sq);
 		break;
 	case ASO_OPC_MOD_POLICER:
-		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->sq, 0,
+		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->pools_mng.sq, 0,
 				  sh->tx_uar, sh->pdn, MLX5_ASO_QUEUE_LOG_DESC,
 				  sh->sq_ts_format))
 			return -1;
-		mlx5_aso_mtr_init_sq(&sh->mtrmng->sq);
+		mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq);
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -342,7 +342,7 @@ mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh,
 		sq = &sh->aso_age_mng->aso_sq;
 		break;
 	case ASO_OPC_MOD_POLICER:
-		sq = &sh->mtrmng->sq;
+		sq = &sh->mtrmng->pools_mng.sq;
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -798,7 +798,7 @@ int
 mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	do {
@@ -830,7 +830,7 @@ int
 mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) ==
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index af3397fb55..759731333d 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -21,6 +21,8 @@
 #include <rte_gtp.h>
 #include <rte_eal_paging.h>
 #include <rte_mpls.h>
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -184,6 +186,31 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
 	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. */
@@ -4695,10 +4722,6 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev,
 					  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,
@@ -5928,9 +5951,10 @@ static int
 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
-	void *old_pools = mtrmng->pools;
-	uint32_t resize = mtrmng->n + MLX5_MTRS_CONTAINER_RESIZE;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
+	void *old_pools = pools_mng->pools;
+	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
 
@@ -5938,16 +5962,16 @@ flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 		rte_errno = ENOMEM;
 		return -ENOMEM;
 	}
-	if (!mtrmng->n)
+	if (!pools_mng->n)
 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
 			mlx5_free(pools);
 			return -ENOMEM;
 		}
 	if (old_pools)
-		memcpy(pools, old_pools, mtrmng->n *
+		memcpy(pools, old_pools, pools_mng->n *
 				       sizeof(struct mlx5_aso_mtr_pool *));
-	mtrmng->n = resize;
-	mtrmng->pools = pools;
+	pools_mng->n = resize;
+	pools_mng->pools = pools;
 	if (old_pools)
 		mlx5_free(old_pools);
 	return 0;
@@ -5970,7 +5994,8 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 			     struct mlx5_aso_mtr **mtr_free)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool = NULL;
 	struct mlx5_devx_obj *dcs = NULL;
 	uint32_t i;
@@ -5990,17 +6015,17 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 		return NULL;
 	}
 	pool->devx_obj = dcs;
-	pool->index = mtrmng->n_valid;
-	if (pool->index == mtrmng->n && flow_dv_mtr_container_resize(dev)) {
+	pool->index = pools_mng->n_valid;
+	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
 		mlx5_free(pool);
 		claim_zero(mlx5_devx_cmd_destroy(dcs));
 		return NULL;
 	}
-	mtrmng->pools[pool->index] = pool;
-	mtrmng->n_valid++;
+	pools_mng->pools[pool->index] = pool;
+	pools_mng->n_valid++;
 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
 		pool->mtrs[i].offset = i;
-		LIST_INSERT_HEAD(&mtrmng->meters,
+		LIST_INSERT_HEAD(&pools_mng->meters,
 						&pool->mtrs[i], next);
 	}
 	pool->mtrs[0].offset = 0;
@@ -6020,15 +6045,16 @@ static void
 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
 
 	MLX5_ASSERT(aso_mtr);
-	rte_spinlock_lock(&mtrmng->mtrsl);
+	rte_spinlock_lock(&pools_mng->mtrsl);
 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
 	aso_mtr->state = ASO_METER_FREE;
-	LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 }
 
 /**
@@ -6045,7 +6071,8 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_aso_mtr *mtr_free = NULL;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool;
 	uint32_t mtr_idx = 0;
 
@@ -6055,16 +6082,16 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 	}
 	/* Allocate the flow meter memory. */
 	/* Get free meters from management. */
-	rte_spinlock_lock(&mtrmng->mtrsl);
-	mtr_free = LIST_FIRST(&mtrmng->meters);
+	rte_spinlock_lock(&pools_mng->mtrsl);
+	mtr_free = LIST_FIRST(&pools_mng->meters);
 	if (mtr_free)
 		LIST_REMOVE(mtr_free, next);
 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
 		return 0;
 	}
 	mtr_free->state = ASO_METER_WAIT;
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 	pool = container_of(mtr_free,
 			struct mlx5_aso_mtr_pool,
 			mtrs[mtr_free->offset]);
@@ -13390,6 +13417,556 @@ flow_dv_action_query(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Destroy the meter sub policy table rules.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *   Pointer to meter sub policy table.
+ */
+static void
+__flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_sub_policy *sub_policy)
+{
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (sub_policy->color_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(sub_policy->color_rule[i]));
+			sub_policy->color_rule[i] = NULL;
+		}
+		if (sub_policy->color_matcher[i]) {
+			tbl = container_of(sub_policy->color_matcher[i]->tbl,
+				typeof(*tbl), tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &sub_policy->color_matcher[i]->entry);
+			sub_policy->color_matcher[i] = NULL;
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (sub_policy->rix_hrxq[i]) {
+			mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+			sub_policy->rix_hrxq[i] = 0;
+		}
+		if (sub_policy->jump_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->jump_tbl[i]);
+			sub_policy->jump_tbl[i] = NULL;
+		}
+	}
+	if (sub_policy->tbl_rsc) {
+		flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->tbl_rsc);
+		sub_policy->tbl_rsc = NULL;
+	}
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	uint32_t i, j;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		for (j = 0; j < sub_policy_num; j++) {
+			sub_policy = mtr_policy->sub_policys[i][j];
+			if (sub_policy)
+				__flow_dv_destroy_sub_policy_rules
+						(dev, sub_policy);
+		}
+	}
+}
+
+/**
+ * Destroy policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	struct rte_flow_action *rss_action;
+	struct mlx5_flow_handle dev_handle;
+	uint32_t i, j;
+
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			flow_dv_tag_release(dev,
+				mtr_policy->act_cnt[i].rix_mark);
+			mtr_policy->act_cnt[i].rix_mark = 0;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			dev_handle.dvh.modify_hdr =
+				mtr_policy->act_cnt[i].modify_hdr;
+			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
+		}
+		switch (mtr_policy->act_cnt[i].fate_action) {
+		case MLX5_FLOW_FATE_SHARED_RSS:
+			rss_action = mtr_policy->act_cnt[i].rss;
+			mlx5_free(rss_action);
+			break;
+		case MLX5_FLOW_FATE_PORT_ID:
+			if (mtr_policy->act_cnt[i].rix_port_id_action) {
+				flow_dv_port_id_action_resource_release(dev,
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				mtr_policy->act_cnt[i].rix_port_id_action = 0;
+			}
+			break;
+		case MLX5_FLOW_FATE_DROP:
+		case MLX5_FLOW_FATE_JUMP:
+			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+				mtr_policy->act_cnt[i].dr_jump_action[j] =
+						NULL;
+			break;
+		default:
+			/*Queue action do nothing*/
+			break;
+		}
+	}
+	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+		mtr_policy->dr_drop_action[j] = NULL;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+__flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			enum mlx5_meter_domain domain,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_error flow_err;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	struct mlx5_flow_handle dh;
+	struct mlx5_flow dev_flow;
+	struct mlx5_flow_dv_port_id_action_resource port_id_action;
+	int i, ret;
+	uint8_t egress, transfer;
+	struct mlx5_meter_policy_action_container *act_cnt = NULL;
+	union {
+		struct mlx5_flow_dv_modify_hdr_resource res;
+		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
+			    sizeof(struct mlx5_modification_cmd) *
+			    (MLX5_MAX_MODIFY_NUM + 1)];
+	} mhdr_dummy;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
+	memset(&port_id_action, 0,
+		sizeof(struct mlx5_flow_dv_port_id_action_resource));
+	dev_flow.handle = &dh;
+	dev_flow.dv.port_id_action = &port_id_action;
+	dev_flow.external = true;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i < MLX5_MTR_RTE_COLORS)
+			act_cnt = &mtr_policy->act_cnt[i];
+		for (act = actions[i];
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_MARK:
+			{
+				uint32_t tag_be = mlx5_flow_mark_set
+					(((const struct rte_flow_action_mark *)
+					(act->conf))->id);
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "mark action for this color");
+				dev_flow.handle->mark = 1;
+				if (flow_dv_tag_resource_register(dev, tag_be,
+						  &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot setup policy mark action");
+				MLX5_ASSERT(dev_flow.dv.tag_resource);
+				act_cnt->rix_mark =
+					dev_flow.handle->dvh.rix_tag;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+			mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+			{
+				struct mlx5_flow_dv_modify_hdr_resource
+					*mhdr_res = &mhdr_dummy.res;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "set tag action for this color");
+				memset(mhdr_res, 0, sizeof(*mhdr_res));
+				mhdr_res->ft_type = transfer ?
+					MLX5DV_FLOW_TABLE_TYPE_FDB :
+					egress ?
+					MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+					MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+				if (flow_dv_convert_action_set_tag
+				(dev, mhdr_res,
+				(const struct rte_flow_action_set_tag *)
+				act->conf,  &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot convert policy "
+					"set tag action");
+				if (!mhdr_res->actions_num)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot find policy "
+					"set tag action");
+				/* create modify action if needed. */
+				dev_flow.dv.group = 1;
+				if (flow_dv_modify_hdr_resource_register
+					(dev, mhdr_res, &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot register policy "
+					"set tag action");
+				act_cnt->modify_hdr =
+				dev_flow.handle->dvh.modify_hdr;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+				mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_DROP:
+			{
+				struct mlx5_flow_mtr_mng *mtrmng =
+						priv->sh->mtrmng;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+
+				/*
+				 * Create the drop table with
+				 * METER DROP level.
+				 */
+				if (!mtrmng->drop_tbl[domain]) {
+					mtrmng->drop_tbl[domain] =
+					flow_dv_tbl_resource_get(dev,
+					MLX5_FLOW_TABLE_LEVEL_METER,
+					egress, transfer, false, NULL, 0,
+					0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
+					if (!mtrmng->drop_tbl[domain])
+						return -rte_mtr_error_set
+					(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Failed to create meter drop table");
+				}
+				tbl_data = container_of
+				(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				if (i < MLX5_MTR_RTE_COLORS) {
+					act_cnt->dr_jump_action[domain] =
+						tbl_data->jump.action;
+					act_cnt->fate_action =
+						MLX5_FLOW_FATE_DROP;
+				}
+				if (i == RTE_COLOR_RED)
+					mtr_policy->dr_drop_action[domain] =
+						tbl_data->jump.action;
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+			{
+				struct mlx5_hrxq *hrxq;
+				uint32_t hrxq_idx;
+				struct mlx5_flow_rss_desc rss_desc;
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"fate queue for this color");
+				memset(&rss_desc, 0,
+					sizeof(struct mlx5_flow_rss_desc));
+				rss_desc.queue_num = 1;
+				rss_desc.const_q = act->conf;
+				hrxq = flow_dv_hrxq_prepare(dev, &dev_flow,
+						    &rss_desc, &hrxq_idx);
+				if (!hrxq)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot create policy fate queue");
+				sub_policy->rix_hrxq[i] = hrxq_idx;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				dev_flow.handle->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				if (action_flags & MLX5_FLOW_ACTION_MARK ||
+				    action_flags & MLX5_FLOW_ACTION_SET_TAG) {
+					dev_flow.handle->rix_hrxq = hrxq_idx;
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_RSS:
+			{
+				int rss_size;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "rss action for this color");
+				/*
+				 * Save RSS conf into policy struct
+				 * for translate stage.
+				 */
+				rss_size = (int)rte_flow_conv
+					(RTE_FLOW_CONV_OP_ACTION,
+					NULL, 0, act, &flow_err);
+				if (rss_size <= 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Get the wrong "
+					  "rss action struct size");
+				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
+						rss_size, 0, SOCKET_ID_ANY);
+				if (!act_cnt->rss)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "Fail to malloc rss action memory");
+				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
+					act_cnt->rss, rss_size,
+					act, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Fail to save "
+					  "rss action into policy struct");
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_SHARED_RSS;
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+			{
+				struct mlx5_flow_dv_port_id_action_resource
+					port_id_resource;
+				uint32_t port_id = 0;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"port action for this color");
+				memset(&port_id_resource, 0,
+					sizeof(port_id_resource));
+				if (flow_dv_translate_action_port_id(dev, act,
+						&port_id, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot translate "
+					"policy port action");
+				port_id_resource.port_id = port_id;
+				if (flow_dv_port_id_action_resource_register
+					(dev, &port_id_resource,
+					&dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy port action");
+				act_cnt->rix_port_id_action =
+					dev_flow.handle->rix_port_id_action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_PORT_ID;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+			{
+				uint32_t jump_group = 0;
+				uint32_t table = 0;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+				struct flow_grp_info grp_info = {
+					.external = !!dev_flow.external,
+					.transfer = !!transfer,
+					.fdb_def_rule = !!priv->fdb_def_rule,
+					.std_tbl_fix = 0,
+					.skip_scale = dev_flow.skip_scale &
+					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
+				};
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "jump action for this color");
+				jump_group =
+				((const struct rte_flow_action_jump *)
+							act->conf)->group;
+				if (mlx5_flow_group_to_table(dev, NULL,
+						       jump_group,
+						       &table,
+						       &grp_info, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy jump action");
+				sub_policy->jump_tbl[i] =
+				flow_dv_tbl_resource_get(dev,
+					table, egress,
+					transfer,
+					!!dev_flow.external,
+					NULL, jump_group, 0,
+					0, &flow_err);
+				if
+				(!sub_policy->jump_tbl[i])
+					return  -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create jump action.");
+				tbl_data = container_of
+				(sub_policy->jump_tbl[i],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				act_cnt->dr_jump_action[domain] =
+					tbl_data->jump.action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_JUMP;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			}
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "action type not supported");
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	int ret, i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (sub_policy_num) {
+			ret = __flow_dv_create_domain_policy_acts(dev,
+				mtr_policy, actions,
+				(enum mlx5_meter_domain)i, error);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
 /**
  * Query a dv flow  rule for its statistics via devx.
  *
@@ -13570,9 +14147,484 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void
+flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (mtrmng->def_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+					(mtrmng->def_rule[i]));
+			mtrmng->def_rule[i] = NULL;
+		}
+		if (mtrmng->def_matcher[i]) {
+			tbl = container_of(mtrmng->def_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->def_matcher[i]->entry);
+			mtrmng->def_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_matcher[i]) {
+			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->drop_matcher[i]->entry);
+			mtrmng->drop_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+				mtrmng->drop_tbl[i]);
+			mtrmng->drop_tbl[i] = NULL;
+		}
+	}
+}
+
 /* Number of meter flow actions, count and jump or count and drop. */
 #define METER_ACTIONS 2
 
+static void
+__flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
+			      enum mlx5_meter_domain domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_def_policy *def_policy =
+			priv->sh->mtrmng->def_policy[domain];
+
+	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
+	mlx5_free(def_policy);
+	priv->sh->mtrmng->def_policy[domain] = NULL;
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+static void
+flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
+		if (priv->sh->mtrmng->def_policy[i])
+			__flow_dv_destroy_domain_def_policy(dev,
+					(enum mlx5_meter_domain)i);
+	priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
+}
+
+static int
+__flow_dv_create_policy_flow(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			enum rte_color color, void *matcher_object,
+			int actions_n, void *actions,
+			bool is_default_policy, void **rule,
+			const struct rte_flow_attr *attr)
+{
+	int ret;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to create meter policy flow with port.");
+			return -1;
+		}
+	}
+	flow_dv_match_meta_reg(matcher.buf, value.buf,
+				(enum modify_reg)color_reg_c_idx,
+				rte_col_2_mlx5_col(color),
+				UINT32_MAX);
+	ret = mlx5_flow_os_create_flow(matcher_object,
+			(void *)&value, actions_n, actions, rule);
+	if (ret) {
+		DRV_LOG(ERR, "Failed to create meter policy flow.");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			uint16_t priority,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			const struct rte_flow_attr *attr,
+			bool is_default_policy,
+			struct rte_flow_error *error)
+{
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+				MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+		.tbl = tbl_rsc,
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = error,
+		.data = &matcher,
+	};
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	struct mlx5_priv *priv = dev->data->dev_private;
+	uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to register meter drop matcher with port.");
+			return -1;
+		}
+	}
+	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
+	if (priority < RTE_COLOR_RED)
+		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+			(enum modify_reg)color_reg_c_idx, 0, color_mask);
+	matcher.priority = priority;
+	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
+					matcher.mask.size);
+	entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+	if (!entry) {
+		DRV_LOG(ERR, "Failed to register meter drop matcher.");
+		return -1;
+	}
+	sub_policy->color_matcher[priority] =
+		container_of(entry, struct mlx5_flow_dv_matcher, entry);
+	return 0;
+}
+
+/**
+ * Create the policy rules per domain.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *    Pointer to sub policy table..
+ * @param[in] egress
+ *   Direction of the table.
+ * @param[in] transfer
+ *   E-Switch or NIC flow.
+ * @param[in] acts
+ *   Pointer to policy action list per color.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+__flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_sub_policy *sub_policy,
+		uint8_t egress, uint8_t transfer, bool is_default_policy,
+		struct mlx5_meter_policy_acts acts[RTE_COLORS])
+{
+	struct rte_flow_error flow_err;
+	uint32_t color_reg_c_idx;
+	struct rte_flow_attr attr = {
+		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
+		.priority = 0,
+		.ingress = 0,
+		.egress = !!egress,
+		.transfer = !!transfer,
+		.reserved = 0,
+	};
+	int i;
+	int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
+
+	if (ret < 0)
+		return -1;
+	/* Create policy table with POLICY level. */
+	if (!sub_policy->tbl_rsc)
+		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_POLICY,
+				egress, transfer, false, NULL, 0, 0,
+				sub_policy->idx, &flow_err);
+	if (!sub_policy->tbl_rsc) {
+		DRV_LOG(ERR,
+			"Failed to create meter sub policy table.");
+		return -1;
+	}
+	/* Prepare matchers. */
+	color_reg_c_idx = ret;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i == RTE_COLOR_YELLOW || !acts[i].actions_n)
+			continue;
+		attr.priority = i;
+		if (!sub_policy->color_matcher[i]) {
+			/* Create matchers for Color. */
+			if (__flow_dv_create_policy_matcher(dev,
+				color_reg_c_idx, i, sub_policy,
+				&attr, is_default_policy, &flow_err))
+				return -1;
+		}
+		/* Create flow, matching color. */
+		if (acts[i].actions_n)
+			if (__flow_dv_create_policy_flow(dev,
+				color_reg_c_idx, (enum rte_color)i,
+				sub_policy->color_matcher[i]->matcher_object,
+				acts[i].actions_n,
+				acts[i].dv_actions,
+				is_default_policy,
+				&sub_policy->color_rule[i],
+				&attr))
+				return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	struct mlx5_flow_dv_tag_resource *tag;
+	struct mlx5_flow_dv_port_id_action_resource *port_action;
+	struct mlx5_hrxq *hrxq;
+	uint8_t egress, transfer;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		acts[i].actions_n = 0;
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (i == RTE_COLOR_RED) {
+			/* Only support drop on red. */
+			acts[i].dv_actions[0] =
+			mtr_policy->dr_drop_action[domain];
+			acts[i].actions_n = 1;
+			continue;
+		}
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
+					mtr_policy->act_cnt[i].rix_mark);
+			if (!tag) {
+				DRV_LOG(ERR, "Failed to find "
+				"mark action for policy.");
+				return -1;
+			}
+			acts[i].dv_actions[acts[i].actions_n] =
+						tag->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			acts[i].dv_actions[acts[i].actions_n] =
+			mtr_policy->act_cnt[i].modify_hdr->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].fate_action) {
+			switch (mtr_policy->act_cnt[i].fate_action) {
+			case MLX5_FLOW_FATE_PORT_ID:
+				port_action = mlx5_ipool_get
+					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				if (!port_action) {
+					DRV_LOG(ERR, "Failed to find "
+						"port action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				port_action->action;
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_DROP:
+			case MLX5_FLOW_FATE_JUMP:
+				acts[i].dv_actions[acts[i].actions_n] =
+				mtr_policy->act_cnt[i].dr_jump_action[domain];
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_SHARED_RSS:
+			case MLX5_FLOW_FATE_QUEUE:
+				hrxq = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+				sub_policy->rix_hrxq[i]);
+				if (!hrxq) {
+					DRV_LOG(ERR, "Failed to find "
+						"queue action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				hrxq->action;
+				acts[i].actions_n++;
+				break;
+			default:
+				/*Queue action do nothing*/
+				break;
+			}
+		}
+	}
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
+				egress, transfer, false, acts)) {
+		DRV_LOG(ERR,
+		"Failed to create policy rules per domain.");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Create the policy rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in,out] mtr_policy
+ *   Pointer to meter policy table.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	int i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (!sub_policy_num)
+			continue;
+		/* Prepare actions list and create policy rules. */
+		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+			mtr_policy->sub_policys[i][0], i)) {
+			DRV_LOG(ERR,
+			"Failed to create policy action list per domain.");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_meter_def_policy *def_policy;
+	struct mlx5_flow_tbl_resource *jump_tbl;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	struct rte_flow_error error;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	int ret;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	def_policy = mtrmng->def_policy[domain];
+	if (!def_policy) {
+		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(struct mlx5_flow_meter_def_policy),
+			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+		if (!def_policy) {
+			DRV_LOG(ERR, "Failed to alloc "
+					"default policy table.");
+			goto def_policy_error;
+		}
+		mtrmng->def_policy[domain] = def_policy;
+		/* Create the meter suffix table with SUFFIX level. */
+		jump_tbl = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_METER,
+				egress, transfer, false, NULL, 0,
+				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
+		if (!jump_tbl) {
+			DRV_LOG(ERR,
+				"Failed to create meter suffix table.");
+			goto def_policy_error;
+		}
+		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
+		tbl_data = container_of(jump_tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].dv_actions[0] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].actions_n = 1;
+		/* Create jump action to the drop table. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
+				(dev, MLX5_FLOW_TABLE_LEVEL_METER,
+				egress, transfer, false, NULL, 0,
+				0, MLX5_MTR_TABLE_ID_DROP, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create "
+				"meter drop table for default policy.");
+				goto def_policy_error;
+			}
+		}
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_RED] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
+		acts[RTE_COLOR_RED].actions_n = 1;
+		/* Create default policy rules. */
+		ret = __flow_dv_create_domain_policy_rules(dev,
+					&def_policy->sub_policy,
+					egress, transfer, true, acts);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create "
+				"default policy rules.");
+				goto def_policy_error;
+		}
+	}
+	return 0;
+def_policy_error:
+	__flow_dv_destroy_domain_def_policy(dev,
+			(enum mlx5_meter_domain)domain);
+	return -1;
+}
+
+/**
+ * Create the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	/* Non-termination policy table. */
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
+			continue;
+		if (__flow_dv_create_domain_def_policy(dev, i)) {
+			DRV_LOG(ERR,
+			"Failed to create default policy");
+			return -1;
+		}
+	}
+	return 0;
+}
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -13602,19 +14654,11 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
 		dtb = &mtb->egress;
 	else
 		dtb = &mtb->ingress;
-	/* Create the meter table with METER level. */
-	dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
-	if (!dtb->tbl) {
-		DRV_LOG(ERR, "Failed to create meter policer table.");
-		return -1;
-	}
 	/* Create the meter suffix table with SUFFIX level. */
 	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
-					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
+					MLX5_FLOW_TABLE_LEVEL_METER,
+					egress, transfer, false, NULL, 0,
+					0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
 	if (!dtb->sfx_tbl) {
 		DRV_LOG(ERR, "Failed to create meter suffix table.");
 		return -1;
@@ -13933,6 +14977,292 @@ flow_dv_action_validate(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_dev_config *dev_conf = &priv->config;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	int actions_n;
+	int i, ret;
+	struct rte_flow_error flow_err;
+	uint8_t domain_color[RTE_COLORS] = {0};
+	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
+
+	if (!priv->config.dv_esw_en)
+		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	*domain_bitmap = def_domain;
+	if (actions[RTE_COLOR_YELLOW] &&
+		actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_END)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"Yellow color does not support any action.");
+	if (actions[RTE_COLOR_YELLOW] &&
+		actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_DROP)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Red color only supports drop action.");
+	/*
+	 * Check default policy actions:
+	 * Green/Yellow: no action, Red: drop action
+	 */
+	if ((!actions[RTE_COLOR_GREEN] ||
+		actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)) {
+		*is_def_policy = true;
+		return 0;
+	}
+	flow_err.message = NULL;
+	for (i = 0; i < RTE_COLORS; i++) {
+		act = actions[i];
+		for (action_flags = 0, actions_n = 0;
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "too many actions");
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+				if (!priv->config.dv_esw_en)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "PORT action validate check"
+					" fail for ESW disable");
+				ret = flow_dv_validate_action_port_id(dev,
+						action_flags,
+						act, attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"PORT action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			case RTE_FLOW_ACTION_TYPE_MARK:
+				ret = flow_dv_validate_action_mark(dev, act,
+							   action_flags,
+							   attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Mark action validate check fail");
+				if (dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "Extend MARK action is "
+					"not supported. Please try use "
+					"default policy for meter.");
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+				ret = flow_dv_validate_action_set_tag(dev,
+							act, action_flags,
+							attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Set tag action validate check fail");
+				/*
+				 * Count all modify-header actions
+				 * as one action.
+				 */
+				if (!(action_flags &
+					MLX5_FLOW_MODIFY_HDR_ACTIONS))
+					++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			case RTE_FLOW_ACTION_TYPE_DROP:
+				ret = mlx5_flow_validate_action_drop
+					(action_flags,
+					attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Drop action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+				/*
+				 * Check whether extensive
+				 * metadata feature is engaged.
+				 */
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Queue action with meta "
+					  "is not supported. Please try use "
+					  "default policy for meter.");
+				ret = mlx5_flow_validate_action_queue(act,
+							action_flags, dev,
+							attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Queue action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_RSS:
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "RSS action with meta "
+					  "is not supported. Please try use "
+					  "default policy for meter.");
+				ret = mlx5_validate_action_rss(dev, act,
+						&flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "RSS action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				++actions_n;
+				*is_rss = true;
+				break;
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+				ret = flow_dv_validate_action_jump(dev,
+					NULL, act, action_flags,
+					attr, true, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Jump action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Doesn't support optional action");
+			}
+		}
+		/* Yellow is not supported, just skip. */
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
+		else if ((action_flags &
+			(MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
+			(action_flags & MLX5_FLOW_ACTION_MARK))
+			/*
+			 * Only support MLX5_XMETA_MODE_LEGACY
+			 * so MARK action only in ingress domain.
+			 */
+			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
+		else
+			domain_color[i] = def_domain;
+		/*
+		 * Validate the drop action mutual exclusion
+		 * with other actions. Drop action is mutually-exclusive
+		 * with any other action, except for Count action.
+		 */
+		if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
+			(action_flags & ~MLX5_FLOW_ACTION_DROP)) {
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Drop action is mutually-exclusive "
+				"with any other action");
+		}
+		/* Eswitch has few restrictions on using items and actions */
+		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
+			if (!mlx5_flow_ext_mreg_supported(dev) &&
+				action_flags & MLX5_FLOW_ACTION_MARK)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action MARK");
+			if (action_flags & MLX5_FLOW_ACTION_QUEUE)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action QUEUE");
+			if (action_flags & MLX5_FLOW_ACTION_RSS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action RSS");
+			if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+		} else {
+			if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) &&
+				(domain_color[i] &
+				MLX5_MTR_DOMAIN_INGRESS_BIT)) {
+				if ((domain_color[i] &
+					MLX5_MTR_DOMAIN_EGRESS_BIT))
+					domain_color[i] =
+					MLX5_MTR_DOMAIN_EGRESS_BIT;
+				else
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+			}
+		}
+		if (domain_color[i] != def_domain)
+			*domain_bitmap = domain_color[i];
+	}
+	return 0;
+}
+
 static int
 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
 {
@@ -13968,8 +15298,16 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.query = flow_dv_query,
 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
+	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
+	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
+	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
+	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
+	.create_policy_rules = flow_dv_create_policy_rules,
+	.destroy_policy_rules = flow_dv_destroy_policy_rules,
+	.create_def_policy = flow_dv_create_def_policy,
+	.destroy_def_policy = flow_dv_destroy_def_policy,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index af0a1c18cb..b38ff77210 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -38,6 +38,12 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
 	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
 	uint32_t val;
+	enum mlx5_meter_domain domain =
+		fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+			fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
+				MLX5_MTR_DOMAIN_INGRESS;
+	struct mlx5_flow_meter_def_policy *def_policy =
+		priv->sh->mtrmng->def_policy[domain];
 
 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
@@ -57,10 +63,7 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
-	mtr_init.next_table =
-		fm->transfer ? fm->mfts->transfer.tbl->obj :
-			fm->egress ? fm->mfts->egress.tbl->obj :
-				fm->mfts->ingress.tbl->obj;
+	mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
 	mtr_init.flow_meter_parameter = fmp;
 	mtr_init.flow_meter_parameter_sz =
@@ -317,7 +320,7 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
 					  "Meter is not supported");
 	memset(cap, 0, sizeof(*cap));
 	if (priv->sh->meter_aso_en)
-	    /* 2 meters per one ASO cache line. */
+		/* 2 meters per one ASO cache line. */
 		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
 	else
 		cap->n_max = 1 << qattr->log_max_flow_meter;
@@ -435,6 +438,347 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * Find policy by id.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param policy_id
+ *   Policy id.
+ *
+ * @return
+ *   Pointer to the policy found on success, NULL otherwise.
+ */
+struct mlx5_flow_meter_policy *
+mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
+			    uint32_t policy_id,
+			    uint32_t *policy_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+	union mlx5_l3t_data data;
+
+	if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM ||
+		!priv->sh->mtrmng->policy_idx_tbl)
+		return NULL;
+	if (mlx5_l3t_get_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data) ||
+				!data.dword)
+		return NULL;
+	if (policy_idx)
+		*policy_idx = data.dword;
+	sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					data.dword);
+	/* Remove reference taken by the mlx5_l3t_get_entry. */
+	mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id);
+	if (sub_policy)
+		if (sub_policy->main_policy_id)
+			return sub_policy->main_policy;
+	return NULL;
+}
+
+/**
+ * Callback to check MTR policy action validate
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_validate(struct rte_eth_dev *dev,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint8_t domain_bitmap;
+	int ret;
+
+	if (!priv->mtr_en || !priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "meter policy unsupported.");
+	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+static int
+__mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint32_t i, j;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	if (mtr_policy->ref_cnt) {
+		rte_spinlock_unlock(&mtr_policy->sl);
+		return -rte_mtr_error_set(error, EBUSY,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				 NULL,
+				"Meter policy object is being used.");
+	}
+	mlx5_flow_destroy_policy_rules(dev, mtr_policy);
+	mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (sub_policy_num) {
+			for (j = 0; j < sub_policy_num; j++) {
+				sub_policy = mtr_policy->sub_policys[i][j];
+				if (sub_policy)
+					mlx5_ipool_free
+					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+			}
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl) {
+		if (mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+					policy_id)) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Fail to delete policy in index table.");
+		}
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return 0;
+}
+
+/**
+ * Callback to add MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] policy_id
+ *   Pointer to policy id
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_add(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct rte_mtr_meter_policy_params *policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	uint32_t sub_policy_idx = 0;
+	uint32_t policy_idx = 0;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint32_t i;
+	int ret;
+	uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
+	uint16_t sub_policy_num;
+	uint8_t domain_bitmap = 0;
+	union mlx5_l3t_data data;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "meter policy unsupported.");
+	if (policy_id == MLX5_INVALID_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID is invalid. ");
+	if (policy_id == priv->sh->mtrmng->def_policy_id)
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID exists. ");
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id,
+				&policy_idx);
+	if (mtr_policy)
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID exists. ");
+	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	if (!domain_bitmap)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "fail to find policy domain.");
+	if (is_def_policy) {
+		if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID)
+			return -rte_mtr_error_set(error, EEXIST,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "a policy with similar actions "
+				"is already configured");
+		if (mlx5_flow_create_def_policy(dev))
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"fail to create non-terminated policy.");
+		priv->sh->mtrmng->def_policy_id = policy_id;
+		return 0;
+	}
+	if (!priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+			"no ASO capability to support the policy ");
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		if (is_rss) {
+			policy_size +=
+			sizeof(struct mlx5_flow_meter_sub_policy *) *
+			MLX5_MTR_RSS_MAX_SUB_POLICY;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
+	}
+	mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
+			 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+				"Memory alloc failed for meter policy.");
+	policy_size = sizeof(struct mlx5_flow_meter_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
+		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy)
+			goto policy_add_err;
+		if (sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto policy_add_err;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+		if (!policy_idx) {
+			policy_idx = sub_policy_idx;
+			sub_policy->main_policy_id = 1;
+		}
+		mtr_policy->sub_policys[i] =
+		(struct mlx5_flow_meter_sub_policy **)
+			((uint8_t *)mtr_policy + policy_size);
+		mtr_policy->sub_policys[i][0] = sub_policy;
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		sub_policy_num++;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
+		mtr_policy->sub_policy_num |=
+			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
+		if (is_rss) {
+			mtr_policy->is_rss = 1;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
+	}
+	rte_spinlock_init(&mtr_policy->sl);
+	ret = mlx5_flow_create_mtr_acts(dev, mtr_policy,
+					policy->actions, error);
+	if (ret)
+		goto policy_add_err;
+	if (!is_rss) {
+		/* Create policy rules in HW. */
+		ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
+		if (ret)
+			goto policy_add_err;
+	}
+	data.dword = policy_idx;
+	if (!priv->sh->mtrmng->policy_idx_tbl) {
+		priv->sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		if (!priv->sh->mtrmng->policy_idx_tbl)
+			goto policy_add_err;
+	}
+	if (mlx5_l3t_set_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data))
+		goto policy_add_err;
+	return 0;
+policy_add_err:
+	if (mtr_policy) {
+		ret = __mlx5_flow_meter_policy_delete(dev, policy_id,
+			mtr_policy, error);
+		mlx5_free(mtr_policy);
+		if (ret)
+			return ret;
+	}
+	return -rte_mtr_error_set(error, ENOTSUP,
+				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+				  NULL, "Failed to create devx policy.");
+}
+
+/**
+ * Callback to delete MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Meter policy 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_policy_delete(struct rte_eth_dev *dev,
+			  uint32_t policy_id,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	uint32_t policy_idx;
+	int ret;
+
+	if (policy_id == priv->sh->mtrmng->def_policy_id) {
+		if (priv->sh->mtrmng->def_policy_ref_cnt > 0)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy object is being used.");
+		priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
+		return 0;
+	}
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"Meter policy id is invalid. ");
+	ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
+						error);
+	if (ret)
+		return ret;
+	mlx5_free(mtr_policy);
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -942,6 +1286,9 @@ 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,
+	.meter_policy_validate = mlx5_flow_meter_policy_validate,
+	.meter_policy_add = mlx5_flow_meter_policy_add,
+	.meter_policy_delete = mlx5_flow_meter_policy_delete,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -989,22 +1336,32 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_aso_mtr *aso_mtr;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	union mlx5_l3t_data data;
 
 	if (priv->sh->meter_aso_en) {
-		rte_spinlock_lock(&mtrmng->mtrsl);
-		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
-			!data.dword) {
-			rte_spinlock_unlock(&mtrmng->mtrsl);
-			return NULL;
+		rte_spinlock_lock(&pools_mng->mtrsl);
+		if (priv->mtr_idx_tbl) {
+			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
+				meter_id, &data) ||
+				!data.dword) {
+				rte_spinlock_unlock(&pools_mng->mtrsl);
+				return NULL;
+			}
+			if (mtr_idx)
+				*mtr_idx = data.dword;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+			/* Remove reference taken by the mlx5_l3t_get_entry. */
+			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
+		} else {
+			if (mtr_idx)
+				*mtr_idx = meter_id;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
 		}
-		if (mtr_idx)
-			*mtr_idx = data.dword;
-		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-		/* Remove reference taken by the mlx5_l3t_get_entry. */
-		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
+		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
+			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
@@ -1169,30 +1526,31 @@ 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_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
 	struct mlx5_aso_mtr_pool *mtr_pool;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
 	void *tmp;
-	uint32_t i, offset, mtr_idx;
+	uint32_t i, offset, mtr_idx, policy_idx;
+	void *entry;
 
+	if (!priv->mtr_en)
+		return 0;
 	if (priv->sh->meter_aso_en) {
-		i = mtrmng->n_valid;
+		i = pools_mng->n_valid;
 		while (i--) {
-			mtr_pool = mtrmng->pools[i];
+			mtr_pool = pools_mng->pools[i];
 			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
 				offset++) {
 				fm = &mtr_pool->mtrs[offset].fm;
 				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				if (mlx5_flow_meter_params_flush(dev,
-						fm, mtr_idx))
-					return -rte_mtr_error_set
-					(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				(void)mlx5_flow_meter_params_flush(dev,
+						fm, mtr_idx);
 			}
 		}
 	} else {
@@ -1200,9 +1558,35 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 			fm = &legacy_fm->fm;
 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
 				return -rte_mtr_error_set(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+				NULL, "MTR object meter profile invalid.");
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl) {
+		MLX5_L3T_FOREACH(priv->sh->mtrmng->policy_idx_tbl,
+					i, entry) {
+			policy_idx = *(uint32_t *)entry;
+			sub_policy = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				policy_idx);
+			if (!sub_policy)
+				return -rte_mtr_error_set(error,
+						EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+			if (__mlx5_flow_meter_policy_delete(dev, i,
+						sub_policy->main_policy,
+						error))
+				return -rte_mtr_error_set(error,
+						EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+			mlx5_free(sub_policy->main_policy);
 		}
+		mlx5_l3t_destroy(priv->sh->mtrmng->policy_idx_tbl);
+		priv->sh->mtrmng->policy_idx_tbl = NULL;
 	}
 	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
 		/* Check unused. */
@@ -1211,5 +1595,8 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
 		mlx5_free(fmp);
 	}
+	/* Delete default policy table. */
+	mlx5_flow_destroy_def_policy(dev);
+	mlx5_flow_destroy_mtr_drop_tbls(dev);
 	return 0;
 }
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index 94dd56709e..90d918849a 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -1179,6 +1179,7 @@ mlx5_dev_stop(struct rte_eth_dev *dev)
 	mlx5_traffic_disable(dev);
 	/* All RX queue flags will be cleared in the flush interface. */
 	mlx5_flow_list_flush(dev, &priv->flows, true);
+	mlx5_flow_meter_flush(dev, NULL);
 	mlx5_rx_intr_vec_disable(dev);
 	priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
 	priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
-- 
2.27.0


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

* [dpdk-dev] [PATCH v4 2/4] net/mlx5: support meter creation with policy
  2021-04-14  6:40 ` [dpdk-dev] [PATCH v4 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 1/4] " Li Zhang
@ 2021-04-14  6:40   ` Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-14  6:40 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

Create a meter with the new pre-defined policy.

The following cases to be considered:
1.Add entry match with meter_id in global drop table.
2.For non-termination policy (policy id 0),
  add jump rule to suffix table for green and
  jump rule to drop table for red.
3.Allocate counter per meter in drop table.
4.Allocate meter resource per domain per color.
5.It can work with both ASO and legacy meter HW objects.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |  13 +-
 drivers/net/mlx5/mlx5.h            |  66 ++---
 drivers/net/mlx5/mlx5_flow.c       |  41 +--
 drivers/net/mlx5/mlx5_flow.h       |  35 +--
 drivers/net/mlx5/mlx5_flow_dv.c    | 395 +++++++++++++++++++----------
 drivers/net/mlx5/mlx5_flow_meter.c | 363 ++++++++++++++++++++++----
 6 files changed, 635 insertions(+), 278 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 276283d492..c1d4e2a0dc 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1297,13 +1297,14 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			if (log_obj_size >=
 			config->hca_attr.qos.log_meter_aso_granularity &&
 			log_obj_size <=
-			config->hca_attr.qos.log_meter_aso_max_alloc) {
+			config->hca_attr.qos.log_meter_aso_max_alloc)
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
-				if (err) {
-					err = -err;
-					goto error;
-				}
+		}
+		if (priv->mtr_en) {
+			err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
+			if (err) {
+				err = -err;
+				goto error;
 			}
 		}
 #endif
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index cb7c75aa2e..436028f759 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -702,44 +702,12 @@ struct mlx5_flow_meter_def_policy {
 	/* Jump action per color. */
 };
 
-/* Meter table structure. */
-struct mlx5_meter_domain_info {
-	struct mlx5_flow_tbl_resource *tbl;
-	/**< Meter table. */
-	struct mlx5_flow_tbl_resource *sfx_tbl;
-	/**< Meter suffix table. */
-	struct mlx5_flow_dv_matcher *drop_matcher;
-	/**< Matcher for Drop. */
-	struct mlx5_flow_dv_matcher *color_matcher;
-	/**< Matcher for Color. */
-	void *jump_actn;
-	/**< Meter match action. */
-	void *green_rule;
-	/**< Meter green rule. */
-	void *drop_rule;
-	/**< Meter drop rule. */
-};
-
-/* 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. */
-	void *green_count;
-	/**< Counters for green rule. */
-	void *drop_count;
-	/**< Counters for green rule. */
-};
-
 /* Meter parameter structure. */
 struct mlx5_flow_meter_info {
+	uint32_t meter_id;
+	/**< Meter id. */
+	uint32_t policy_id;
+	/* Policy id, the first sub_policy idx. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
 	rte_spinlock_t sl; /**< Meter action spinlock. */
@@ -778,8 +746,12 @@ struct mlx5_flow_meter_info {
 	 * received by the application.
 	 */
 	uint32_t transfer:1;
-	struct mlx5_meter_domains_infos *mfts;
-	/**< Flow table created for this meter. */
+	uint32_t def_policy:1;
+	/* Meter points to default policy. */
+	uint32_t drop_matcher_idx:5;
+	/* Index drop_matcher. */
+	void *drop_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop rule in drop table. */
 	uint32_t drop_cnt;
 	/**< Color counter for drop. */
 	uint32_t ref_cnt;
@@ -790,6 +762,11 @@ struct mlx5_flow_meter_info {
 	/**< Flow meter action. */
 };
 
+/* PPS(packets per second) map to BPS(Bytes per second).
+ * HW treat packet as 128bytes in PPS mode
+ */
+#define MLX5_MTRS_PPS_MAP_BPS_SHIFT 7
+
 /* RFC2697 parameter structure. */
 struct mlx5_flow_meter_srtcm_rfc2697_prm {
 	rte_be32_t cbs_cir;
@@ -878,12 +855,19 @@ struct mlx5_flow_mtr_mng {
 	/* Policy index lookup table. */
 	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
 	/* Meter drop table. */
-	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	struct mlx5_flow_dv_matcher *
+			drop_matcher[MLX5_MTR_DOMAIN_MAX][MLX5_REG_BITS];
 	/* Matcher meter in drop table. */
 	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
 	/* Default matcher in drop table. */
 	void *def_rule[MLX5_MTR_DOMAIN_MAX];
 	/* Default rule in drop table. */
+	uint32_t def_rule_ref_cnt[MLX5_MTR_DOMAIN_MAX];
+	/* Default rule and drop table use count. */
+	uint8_t max_mtr_bits;
+	/* Indicate how many bits are used by meter id at the most. */
+	uint8_t max_mtr_flow_bits;
+	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 /* Table key of the hash organization. */
@@ -1322,10 +1306,6 @@ struct mlx5_priv {
 	uint32_t rss_shared_actions; /* RSS shared actions. */
 	struct mlx5_devx_obj *q_counters; /* DevX queue counter object. */
 	uint32_t counter_set_id; /* Queue counter ID to set in DevX objects. */
-	uint8_t max_mtr_bits;
-	/* Indicate how many bits are used by meter id at the most. */
-	uint8_t max_mtr_flow_bits;
-	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 #define PORT_ID(priv) ((priv)->dev_data->port_id)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 81e0e3b7a9..a8aaf1ed8e 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4496,14 +4496,14 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	flow_id = tag_id - 1;
 	flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
 	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->max_mtr_bits) > mtr_reg_bits) {
+	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
 		mlx5_ipool_free(fm->flow_ipool, tag_id);
 		return rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				"Meter flow id exceeds max limit.");
 	}
-	if (flow_id_bits > priv->max_mtr_flow_bits)
-		priv->max_mtr_flow_bits = flow_id_bits;
+	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -6778,15 +6778,18 @@ mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  *
  * @return
- *   Pointer to table set on success, NULL otherwise.
+ *   0 on success, -1 otherwise.
  */
-struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+int
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
 	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, mtr_idx, domain_bitmap);
 }
 
 /**
@@ -6796,33 +6799,15 @@ mlx5_flow_create_mtr_tbls(struct rte_eth_dev *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);
-}
-
-/**
- * Destroy the global meter drop table.
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
  */
 void
-mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			   struct mlx5_flow_meter_info *fm)
 {
 	const struct mlx5_flow_driver_ops *fops;
 
 	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	fops->destroy_mtr_drop_tbls(dev);
+	fops->destroy_mtr_tbls(dev, fm);
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 51d040c4d2..7d1684d02d 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -222,16 +222,17 @@ enum mlx5_feature_name {
 #define MLX5_FLOW_ACTION_TUNNEL_SET (1ull << 37)
 #define MLX5_FLOW_ACTION_TUNNEL_MATCH (1ull << 38)
 #define MLX5_FLOW_ACTION_MODIFY_FIELD (1ull << 39)
+#define MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY (1ull << 40)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \
 	 MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_JUMP | \
-	 MLX5_FLOW_ACTION_DEFAULT_MISS)
+	 MLX5_FLOW_ACTION_DEFAULT_MISS | \
+	 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_FATE_ESWITCH_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \
-	 MLX5_FLOW_ACTION_JUMP)
-
+	 MLX5_FLOW_ACTION_JUMP | MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_MODIFY_HDR_ACTIONS (MLX5_FLOW_ACTION_SET_IPV4_SRC | \
 				      MLX5_FLOW_ACTION_SET_IPV4_DST | \
@@ -832,9 +833,8 @@ struct mlx5_legacy_flow_meter {
 	/* Must be the first in struct. */
 	TAILQ_ENTRY(mlx5_legacy_flow_meter) next;
 	/**< Pointer to the next flow meter structure. */
-	uint32_t meter_id;
-	/**< Meter id. */
-	uint32_t idx; /* Index to meter object. */
+	uint32_t idx;
+	/* Index to meter object. */
 };
 
 #define MLX5_MAX_TUNNELS 256
@@ -1088,11 +1088,12 @@ 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);
-typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
+typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
+					struct mlx5_flow_meter_info *fm,
+					uint32_t mtr_idx,
+					uint8_t domain_bitmap);
+typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1175,7 +1176,6 @@ 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_destroy_mtr_drop_tbls_t destroy_mtr_drop_tbls;
 	mlx5_flow_mtr_alloc_t create_meter;
 	mlx5_flow_mtr_free_t free_meter;
 	mlx5_flow_validate_mtr_acts_t validate_mtr_acts;
@@ -1409,11 +1409,12 @@ int mlx5_flow_validate_item_ecpri(const struct rte_flow_item *item,
 				  uint16_t ether_type,
 				  const struct rte_flow_item_ecpri *acc_mask,
 				  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);
-void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
+int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
+				uint32_t mtr_idx,
+				uint8_t domain_bitmap);
+void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter_info *fm);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 759731333d..7c2811c815 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -4859,11 +4859,14 @@ 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,
+				bool *def_policy,
 				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_info *fm;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 
 	if (!am)
 		return rte_flow_error_set(error, EINVAL,
@@ -4894,10 +4897,40 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
 	      (!fm->ingress && !attr->ingress && attr->egress) ||
 	      (!fm->egress && !attr->egress && attr->ingress)))
 		return rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Flow attributes domain are either invalid "
+			"or have a domain conflict with current "
+			"meter attributes");
+	if (fm->def_policy) {
+		if (!((attr->transfer &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
+			(attr->egress &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
+			(attr->ingress &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
+			return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		*def_policy = true;
+	} else {
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+		if (!mtr_policy)
+			return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Invalid policy id for meter ");
+		if (!((attr->transfer && mtr_policy->transfer) ||
+			(attr->egress && mtr_policy->egress) ||
+			(attr->ingress && mtr_policy->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");
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		*def_policy = false;
+	}
 	return 0;
 }
 
@@ -6287,6 +6320,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		.fdb_def_rule = !!priv->fdb_def_rule,
 	};
 	const struct rte_eth_hairpin_conf *conf;
+	bool def_policy = false;
 
 	if (items == NULL)
 		return -1;
@@ -6628,6 +6662,12 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
 						  actions, "too many actions");
+		if (action_flags &
+			MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
+			return rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "meter action with policy "
+				"must be the last action");
 		switch (type) {
 		case RTE_FLOW_ACTION_TYPE_VOID:
 			break;
@@ -7030,10 +7070,14 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			ret = mlx5_flow_validate_action_meter(dev,
 							      action_flags,
 							      actions, attr,
+							      &def_policy,
 							      error);
 			if (ret < 0)
 				return ret;
 			action_flags |= MLX5_FLOW_ACTION_METER;
+			if (!def_policy)
+				action_flags |=
+				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
 			++actions_n;
 			/* Meter action will add one more TAG action. */
 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
@@ -7290,6 +7334,36 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 						 "multiple VLAN actions");
 		}
 	}
+	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
+		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
+			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
+			attr->ingress)
+			return rte_flow_error_set
+				(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "fate action not supported for "
+				"meter with policy");
+		if (attr->egress) {
+			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "modify header action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "encap action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "push vlan action in egress "
+					"cannot be done before meter action");
+		}
+	}
 	/*
 	 * Hairpin flow will add one more TAG action in TX implicit mode.
 	 * In TX explicit mode, there will be no hairpin flow ID.
@@ -14113,71 +14187,55 @@ flow_dv_query(struct rte_eth_dev *dev,
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
- * @param[in] tbl
- *   Pointer to the meter table set.
- *
- * @return
- *   Always 0.
+ * @param[in] fm
+ *   Meter information table.
  */
-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->egress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.tbl);
-	if (mtd->egress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.sfx_tbl);
-	if (mtd->ingress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->ingress.tbl);
-	if (mtd->ingress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->ingress.sfx_tbl);
-	if (mtd->transfer.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->transfer.tbl);
-	if (mtd->transfer.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->transfer.sfx_tbl);
-	mlx5_free(mtd);
-	return 0;
-}
-
 static void
-flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct mlx5_flow_tbl_data_entry *tbl;
-	int i;
+	int i, ret;
 
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero
+			(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
+		}
+		if (mtrmng->drop_matcher[i][fm->drop_matcher_idx]) {
+			tbl = container_of
+			(mtrmng->drop_matcher[i][fm->drop_matcher_idx]->tbl,
+					     struct mlx5_flow_tbl_data_entry,
+					     tbl);
+			ret = mlx5_cache_unregister(&tbl->matchers,
+			&mtrmng->drop_matcher[i][fm->drop_matcher_idx]->entry);
+			if (!ret)
+				mtrmng->drop_matcher[i][fm->drop_matcher_idx] =
+						NULL;
+		}
 		if (mtrmng->def_rule[i]) {
-			claim_zero(mlx5_flow_os_destroy_flow
-					(mtrmng->def_rule[i]));
-			mtrmng->def_rule[i] = NULL;
+			__atomic_sub_fetch(&mtrmng->def_rule_ref_cnt[i],
+				1, __ATOMIC_RELAXED);
+			if (!mtrmng->def_rule_ref_cnt[i]) {
+				claim_zero(mlx5_flow_os_destroy_flow
+						(mtrmng->def_rule[i]));
+				mtrmng->def_rule[i] = NULL;
+			}
 		}
 		if (mtrmng->def_matcher[i]) {
 			tbl = container_of(mtrmng->def_matcher[i]->tbl,
-				struct mlx5_flow_tbl_data_entry, tbl);
-			mlx5_cache_unregister(&tbl->matchers,
-				      &mtrmng->def_matcher[i]->entry);
-			mtrmng->def_matcher[i] = NULL;
+					struct mlx5_flow_tbl_data_entry, tbl);
+			ret = mlx5_cache_unregister(&tbl->matchers,
+				&mtrmng->def_matcher[i]->entry);
+			if (!ret)
+				mtrmng->def_matcher[i] = NULL;
 		}
-		if (mtrmng->drop_matcher[i]) {
-			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
-				struct mlx5_flow_tbl_data_entry, tbl);
-			mlx5_cache_unregister(&tbl->matchers,
-				      &mtrmng->drop_matcher[i]->entry);
-			mtrmng->drop_matcher[i] = NULL;
-		}
-		if (mtrmng->drop_tbl[i]) {
+		if (!mtrmng->def_rule_ref_cnt[i] && mtrmng->drop_tbl[i]) {
 			flow_dv_tbl_resource_release(MLX5_SH(dev),
-				mtrmng->drop_tbl[i]);
+						mtrmng->drop_tbl[i]);
 			mtrmng->drop_tbl[i] = NULL;
 		}
 	}
@@ -14626,96 +14684,172 @@ flow_dv_create_def_policy(struct rte_eth_dev *dev)
 }
 
 /**
- * Create specify domain meter table and suffix table.
+ * Create the needed meter tables.
+ * Lock free, (mutex should be acquired by caller).
  *
  * @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] fm
+ *   Meter information table.
+ * @param[in] mtr_idx
+ *   Meter index.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] domain_bitmap
+ *   Domain bitmap.
  * @return
  *   0 on success, -1 otherwise.
  */
 static int
-flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *mtb,
-			   uint8_t egress, uint8_t transfer)
+flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct rte_flow_error error;
-	struct mlx5_meter_domain_info *dtb;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	void *actions[METER_ACTIONS];
+	int domain, ret, i;
+	struct mlx5_flow_counter *cnt;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher_para = {
+		.size = sizeof(matcher_para.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
+						     0, &error);
+	uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
+	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+	};
+	struct mlx5_flow_dv_matcher *drop_matcher;
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = &error,
+		.data = &matcher,
+	};
 
-	if (transfer)
-		dtb = &mtb->transfer;
-	else if (egress)
-		dtb = &mtb->egress;
-	else
-		dtb = &mtb->ingress;
-	/* Create the meter suffix table with SUFFIX level. */
-	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
+	if (!priv->mtr_en || mtr_id_reg_c < 0) {
+		rte_errno = ENOTSUP;
+		return -1;
+	}
+	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
+		if (!(domain_bitmap & (1 << domain)) ||
+			(mtrmng->def_rule[domain] && !fm->drop_cnt))
+			continue;
+		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		/* Create the drop table with METER DROP level. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] =
+				flow_dv_tbl_resource_get(dev,
 					MLX5_FLOW_TABLE_LEVEL_METER,
 					egress, transfer, false, NULL, 0,
-					0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
-	if (!dtb->sfx_tbl) {
-		DRV_LOG(ERR, "Failed to create meter suffix table.");
-		return -1;
+					0, MLX5_MTR_TABLE_ID_DROP, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR,
+					"Failed to create meter drop table.");
+				goto policy_error;
+			}
+		}
+		/* Create default matcher in drop table. */
+		matcher.tbl = mtrmng->drop_tbl[domain],
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+				       (enum modify_reg)mtr_id_reg_c,
+				       0, 0);
+		matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
+		matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+		entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+		if (!entry) {
+			DRV_LOG(ERR, "Failed to register meter "
+				"drop default matcher.");
+			goto policy_error;
+		}
+		mtrmng->def_matcher[domain] = container_of(entry,
+			struct mlx5_flow_dv_matcher, entry);
+		/* Create default rule in drop table. */
+		if (!mtrmng->def_rule[domain]) {
+			i = 0;
+			actions[i++] = priv->sh->dr_drop_action;
+			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c, 0, 0);
+			ret = mlx5_flow_os_create_flow
+				(mtrmng->def_matcher[domain]->matcher_object,
+				(void *)&value, i, actions,
+				&mtrmng->def_rule[domain]);
+			if (ret) {
+				DRV_LOG(ERR, "Failed to create meter "
+				"default drop rule for drop table.");
+				goto policy_error;
+			}
+		}
+		__atomic_add_fetch(&mtrmng->def_rule_ref_cnt[domain], 1,
+					__ATOMIC_RELAXED);
+		if (!fm->drop_cnt)
+			continue;
+		MLX5_ASSERT(mtrmng->max_mtr_bits);
+		/* Create matchers for Drop. */
+		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+					(enum modify_reg)mtr_id_reg_c, 0,
+					(mtr_id_mask << mtr_id_offset));
+		matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
+		matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+		entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+		if (!entry) {
+			DRV_LOG(ERR,
+			"Failed to register meter drop matcher.");
+			goto policy_error;
+		}
+		fm->drop_matcher_idx = mtrmng->max_mtr_bits - 1;
+		mtrmng->drop_matcher[domain][fm->drop_matcher_idx] =
+				container_of(entry, struct mlx5_flow_dv_matcher,
+					     entry);
+		drop_matcher =
+			mtrmng->drop_matcher[domain][fm->drop_matcher_idx];
+		/* Create drop rule, matching meter_id only. */
+		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c,
+				(mtr_idx << mtr_id_offset), UINT32_MAX);
+		i = 0;
+		cnt = flow_dv_counter_get_by_idx(dev,
+					fm->drop_cnt, NULL);
+		actions[i++] = cnt->action;
+		actions[i++] = priv->sh->dr_drop_action;
+		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
+					       (void *)&value, i, actions,
+					       &fm->drop_rule[domain]);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create meter "
+				"drop rule for drop table.");
+				goto policy_error;
+		}
 	}
 	return 0;
-}
-
-/**
- * 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 = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*mtb), 0, SOCKET_ID_ANY);
-	if (!mtb) {
-		DRV_LOG(ERR, "Failed to allocate memory for meter.");
-		return NULL;
-	}
-	/* Egress meter table. */
-	ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0);
-	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);
-	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);
-		if (ret) {
-			DRV_LOG(ERR, "Failed to prepare fdb meter table.");
-			goto error_exit;
+policy_error:
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
 		}
 	}
-	return mtb;
-error_exit:
-	flow_dv_destroy_mtr_tbl(dev, mtb);
-	return NULL;
+	return -1;
 }
 
 /**
@@ -15296,9 +15430,8 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.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,
-	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
+	.create_mtr_tbls = flow_dv_create_mtr_tbls,
+	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
 	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index b38ff77210..6efcab0c6e 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -665,9 +665,12 @@ mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (!(domain_bitmap & (1 << i)))
 			continue;
-		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
-		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
-		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		if (i == MLX5_MTR_DOMAIN_INGRESS)
+			mtr_policy->ingress = 1;
+		if (i == MLX5_MTR_DOMAIN_EGRESS)
+			mtr_policy->egress = 1;
+		if (i == MLX5_MTR_DOMAIN_TRANSFER)
+			mtr_policy->transfer = 1;
 		sub_policy = mlx5_ipool_zmalloc
 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
 				&sub_policy_idx);
@@ -779,6 +782,56 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * 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)
+{
+	/* Meter must use global drop action. */
+	if (!priv->sh->dr_drop_action)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL,
+					  "No drop action ready for meter.");
+	/* 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.");
+	if (params->meter_policy_id == MLX5_INVALID_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+	/* Validate meter id. */
+	if (mlx5_flow_meter_find(priv, meter_id, NULL))
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+			"Meter object already exists.");
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -884,13 +937,195 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 #endif
 }
 
-static void
-mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
+static int
+mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
 				uint64_t stats_mask)
 {
 	fm->bytes_dropped =
 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
+	if (fm->bytes_dropped || fm->pkts_dropped) {
+		if (!fm->drop_cnt) {
+			/* Alloc policer counters. */
+			fm->drop_cnt = mlx5_counter_alloc(dev);
+			if (!fm->drop_cnt)
+				return -1;
+		}
+	} else {
+		if (fm->drop_cnt) {
+			mlx5_counter_free(dev, fm->drop_cnt);
+			fm->drop_cnt = 0;
+		}
+	}
+	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_legacy_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_flow_meter_info *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_indexed_pool_config flow_ipool_cfg = {
+		.size = 0,
+		.trunk_size = 64,
+		.need_lock = 1,
+		.type = "mlx5_flow_mtr_flow_id_pool",
+	};
+	struct mlx5_aso_mtr *aso_mtr;
+	uint32_t mtr_idx, policy_idx;
+	union mlx5_l3t_data data;
+	int ret;
+	uint8_t domain_bitmap;
+	uint8_t mtr_id_bits;
+	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
+				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter is not supported");
+	/* 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.");
+	/* Meter policy must exist. */
+	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
+		__atomic_add_fetch
+			(&priv->sh->mtrmng->def_policy_ref_cnt,
+			1, __ATOMIC_RELAXED);
+		domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
+		if (!priv->config.dv_esw_en)
+			domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	} else {
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+				params->meter_policy_id, &policy_idx);
+		if (!priv->sh->meter_aso_en)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Part of the policies cannot be "
+				"supported without ASO ");
+		if (!mtr_policy)
+			return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+		domain_bitmap = (mtr_policy->ingress ?
+					MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
+				(mtr_policy->egress ?
+					MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
+				(mtr_policy->transfer ?
+					MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
+	}
+	/* Allocate the flow meter memory. */
+	if (priv->sh->meter_aso_en) {
+		mtr_idx = mlx5_flow_mtr_alloc(dev);
+		if (!mtr_idx)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+		fm = &aso_mtr->fm;
+	} else {
+		legacy_fm = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
+		if (legacy_fm == NULL)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		legacy_fm->idx = mtr_idx;
+		fm = &legacy_fm->fm;
+	}
+	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
+	if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
+	    mtr_reg_bits) {
+		DRV_LOG(ERR, "Meter number exceeds max limit.");
+		goto error;
+	}
+	if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
+		priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
+	/* Fill the flow meter parameters. */
+	fm->meter_id = meter_id;
+	fm->policy_id = params->meter_policy_id;
+	fm->profile = fmp;
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
+		goto error;
+	if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
+		goto error;
+	/* Add to the flow meter list. */
+	if (!priv->sh->meter_aso_en)
+		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
+	/* Add to the flow meter list. */
+	fm->active_state = 1; /* Config meter starts as active. */
+	fm->is_enable = 1;
+	fm->shared = !!shared;
+	__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
+	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
+		fm->def_policy = 1;
+		fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
+		if (!fm->flow_ipool)
+			goto error;
+	}
+	rte_spinlock_init(&fm->sl);
+	/* If ASO meter supported, update ASO flow meter by wqe. */
+	if (priv->sh->meter_aso_en) {
+		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
+		if (ret)
+			goto error;
+		if (!priv->mtr_idx_tbl) {
+			priv->mtr_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+			if (!priv->mtr_idx_tbl)
+				goto error;
+		}
+		data.dword = mtr_idx;
+		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
+			goto error;
+	}
+	if (mtr_policy)
+		__atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
+	return 0;
+error:
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	/* Free policer counters. */
+	if (fm->drop_cnt)
+		mlx5_counter_free(dev, fm->drop_cnt);
+	if (priv->sh->meter_aso_en)
+		mlx5_flow_mtr_free(dev, mtr_idx);
+	else
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
+	return -rte_mtr_error_set(error, ENOTSUP,
+		RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+		NULL, "Failed to create devx meter.");
 }
 
 static int
@@ -902,6 +1137,7 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
+	struct mlx5_flow_meter_policy *mtr_policy;
 
 	/* Meter object must not have any owner. */
 	MLX5_ASSERT(!fm->ref_cnt);
@@ -911,23 +1147,42 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 		return -1;
 	/* Update dependencies. */
 	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
+	fm->profile = NULL;
 	/* Remove from list. */
 	if (!priv->sh->meter_aso_en) {
-		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
+		legacy_fm = container_of(fm,
+			struct mlx5_legacy_flow_meter, fm);
 		TAILQ_REMOVE(fms, legacy_fm, next);
 	}
 	/* Free drop counters. */
 	if (fm->drop_cnt)
 		mlx5_counter_free(dev, fm->drop_cnt);
 	/* Free meter flow table. */
-	if (fm->flow_ipool)
+	if (fm->flow_ipool) {
 		mlx5_ipool_destroy(fm->flow_ipool);
-	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-	if (priv->sh->meter_aso_en)
+		fm->flow_ipool = 0;
+	}
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	if (fm->def_policy)
+		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
+				1, __ATOMIC_RELAXED);
+	if (priv->sh->meter_aso_en) {
+		if (!fm->def_policy) {
+			mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+			if (mtr_policy)
+				__atomic_sub_fetch(&mtr_policy->ref_cnt,
+						1, __ATOMIC_RELAXED);
+			fm->policy_id = 0;
+		}
+		fm->def_policy = 0;
+		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
+			return -1;
 		mlx5_flow_mtr_free(dev, mtr_idx);
-	else
+	} else {
 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
 					legacy_fm->idx);
+	}
 	return 0;
 }
 
@@ -954,30 +1209,28 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
-					  NULL, "Meter object id not valid.");
+					  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.");
-	if (priv->sh->meter_aso_en) {
-		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id))
-			return -rte_mtr_error_set(error, EBUSY,
-				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Fail to delete ASO Meter in index table.");
-	}
+					  NULL,
+					  "Meter object is being used.");
 	/* Destroy the meter profile. */
 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
 		return -rte_mtr_error_set(error, EINVAL,
 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+					NULL,
+					"MTR object meter profile invalid.");
 	return 0;
 }
 
@@ -1211,7 +1464,11 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
 					  NULL, "Meter object id not valid.");
-	mlx5_flow_meter_stats_enable_update(fm, stats_mask);
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_MTR_ID,
+					  NULL, "Fail to allocate "
+					  "counter for meter.");
 	return 0;
 }
 
@@ -1289,6 +1546,7 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.meter_policy_validate = mlx5_flow_meter_policy_validate,
 	.meter_policy_add = mlx5_flow_meter_policy_add,
 	.meter_policy_delete = mlx5_flow_meter_policy_delete,
+	.create = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -1327,7 +1585,7 @@ mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
  *   Pointer to Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
@@ -1342,30 +1600,27 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 
 	if (priv->sh->meter_aso_en) {
 		rte_spinlock_lock(&pools_mng->mtrsl);
-		if (priv->mtr_idx_tbl) {
-			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
-				meter_id, &data) ||
-				!data.dword) {
-				rte_spinlock_unlock(&pools_mng->mtrsl);
-				return NULL;
-			}
-			if (mtr_idx)
-				*mtr_idx = data.dword;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-			/* Remove reference taken by the mlx5_l3t_get_entry. */
-			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		} else {
-			if (mtr_idx)
-				*mtr_idx = meter_id;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
+		if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
 		}
+		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
+			!data.dword) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
+		}
+		if (mtr_idx)
+			*mtr_idx = data.dword;
+		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+		/* Remove reference taken by the mlx5_l3t_get_entry. */
+		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
 		rte_spinlock_unlock(&pools_mng->mtrsl);
 		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
 			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
-		if (meter_id == legacy_fm->meter_id) {
+		if (meter_id == legacy_fm->fm.meter_id) {
 			if (mtr_idx)
 				*mtr_idx = legacy_fm->idx;
 			return &legacy_fm->fm;
@@ -1382,7 +1637,7 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
  *   Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
@@ -1391,6 +1646,8 @@ flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
 
 	if (priv->sh->meter_aso_en) {
 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
+		if (!aso_mtr)
+			return NULL;
 		return &aso_mtr->fm;
 	} else {
 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
@@ -1526,32 +1783,33 @@ 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_aso_mtr_pools_mng *pools_mng =
-				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
-	struct mlx5_aso_mtr_pool *mtr_pool;
 	struct mlx5_flow_meter_sub_policy *sub_policy;
 	void *tmp;
-	uint32_t i, offset, mtr_idx, policy_idx;
+	uint32_t i, mtr_idx, policy_idx;
 	void *entry;
+	struct mlx5_aso_mtr *aso_mtr;
 
 	if (!priv->mtr_en)
 		return 0;
 	if (priv->sh->meter_aso_en) {
-		i = pools_mng->n_valid;
-		while (i--) {
-			mtr_pool = pools_mng->pools[i];
-			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
-				offset++) {
-				fm = &mtr_pool->mtrs[offset].fm;
-				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				(void)mlx5_flow_meter_params_flush(dev,
+		if (priv->mtr_idx_tbl) {
+			MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
+				mtr_idx = *(uint32_t *)entry;
+				if (mtr_idx) {
+					aso_mtr =
+					mlx5_aso_meter_by_idx(priv, mtr_idx);
+					fm = &aso_mtr->fm;
+					(void)mlx5_flow_meter_params_flush(dev,
 						fm, mtr_idx);
+				}
 			}
+			mlx5_l3t_destroy(priv->mtr_idx_tbl);
+			priv->mtr_idx_tbl = NULL;
 		}
 	} else {
 		TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
@@ -1597,6 +1855,5 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 	}
 	/* Delete default policy table. */
 	mlx5_flow_destroy_def_policy(dev);
-	mlx5_flow_destroy_mtr_drop_tbls(dev);
 	return 0;
 }
-- 
2.27.0


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

* [dpdk-dev] [PATCH v4 3/4] net/mlx5: prepare sub-policy for a flow with meter
  2021-04-14  6:40 ` [dpdk-dev] [PATCH v4 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 1/4] " Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 2/4] net/mlx5: support meter creation with policy Li Zhang
@ 2021-04-14  6:40   ` Li Zhang
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-14  6:40 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

When a flow has a RSS action, the driver splits
each sub flow finally is configured with
a different HW TIR action.

Any RSS action configured in meter policy may cause
a split in the flow configuration.
To save performance, any TIR action will be configured
in different flow table, so policy can be split to
sub-policies per TIR in the flow creation time.

Create a function to prepare the policy and
its sub-policies for a configured flow with meter.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.h    |  10 +++
 drivers/net/mlx5/mlx5_flow_dv.c | 144 ++++++++++++++++++++++++++++++++
 2 files changed, 154 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 7d1684d02d..ddfab494b8 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1094,6 +1094,11 @@ typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
 					uint8_t domain_bitmap);
 typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 				struct mlx5_flow_meter_info *fm);
+typedef struct mlx5_flow_meter_sub_policy *
+	(*mlx5_flow_meter_sub_policy_rss_prepare_t)
+		(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1185,6 +1190,7 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
 	mlx5_flow_create_def_policy_t create_def_policy;
 	mlx5_flow_destroy_def_policy_t destroy_def_policy;
+	mlx5_flow_meter_sub_policy_rss_prepare_t meter_sub_policy_rss_prepare;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1415,6 +1421,10 @@ int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
 				uint8_t domain_bitmap);
 void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_flow_meter_info *fm);
+struct mlx5_flow_meter_sub_policy *mlx5_flow_meter_sub_policy_rss_prepare
+		(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 7c2811c815..96adf3f9cb 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -14852,6 +14852,149 @@ flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
 	return -1;
 }
 
+/**
+ * Find the policy table for prefix table with RSS.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ * @return
+ *   Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+	uint32_t sub_policy_idx = 0;
+	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
+	uint32_t i, j;
+	struct mlx5_hrxq *hrxq;
+	struct mlx5_flow_handle dh;
+	struct mlx5_meter_policy_action_container *act_cnt;
+	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
+		if (!hrxq_idx[i]) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return NULL;
+		}
+	}
+	sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+	for (i = 0; i < sub_policy_num;
+		i++) {
+		for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) {
+			if (rss_desc[j] &&
+				hrxq_idx[j] !=
+			mtr_policy->sub_policys[domain][i]->rix_hrxq[j])
+				break;
+		}
+		if (j >= MLX5_MTR_RTE_COLORS) {
+			/*
+			 * Found the sub policy table with
+			 * the same queue per color
+			 */
+			rte_spinlock_unlock(&mtr_policy->sl);
+			for (j = 0; j < MLX5_MTR_RTE_COLORS; j++)
+				mlx5_hrxq_release(dev, hrxq_idx[j]);
+			return mtr_policy->sub_policys[domain][i];
+		}
+	}
+	/* Create sub policy. */
+	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
+		/* Reuse the first dummy sub_policy*/
+		sub_policy = mtr_policy->sub_policys[domain][0];
+		sub_policy_idx = sub_policy->idx;
+	} else {
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy ||
+			sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto rss_sub_policy_error;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		sub_policy->rix_hrxq[i] = hrxq_idx[i];
+		/*
+		 * Overwrite the last action from
+		 * RSS action to Queue action.
+		 */
+		hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+			      hrxq_idx[i]);
+		if (!hrxq) {
+			DRV_LOG(ERR, "Failed to create policy hrxq");
+			goto rss_sub_policy_error;
+		}
+		act_cnt = &mtr_policy->act_cnt[i];
+		if (act_cnt->rix_mark || act_cnt->modify_hdr) {
+			memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+			if (act_cnt->rix_mark)
+				dh.mark = 1;
+			dh.fate_action = MLX5_FLOW_FATE_QUEUE;
+			dh.rix_hrxq = hrxq_idx[i];
+			flow_drv_rxq_flags_set(dev, &dh);
+		}
+	}
+	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+		sub_policy, domain)) {
+		DRV_LOG(ERR, "Failed to create policy "
+			"rules per domain.");
+		goto rss_sub_policy_error;
+	}
+	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+		i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		mtr_policy->sub_policys[domain][i] = sub_policy;
+		i++;
+		if (i > MLX5_MTR_RSS_MAX_SUB_POLICY)
+			goto rss_sub_policy_error;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
+		mtr_policy->sub_policy_num |=
+			(i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return sub_policy;
+rss_sub_policy_error:
+	if (sub_policy) {
+		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
+		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+			i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+			mtr_policy->sub_policys[domain][i] = NULL;
+			mlx5_ipool_free
+			(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
+		mlx5_hrxq_release(dev, hrxq_idx[i]);
+	if (sub_policy_idx)
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+			sub_policy_idx);
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return NULL;
+}
+
 /**
  * Validate the batch counter support in root table.
  *
@@ -15441,6 +15584,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
 	.create_def_policy = flow_dv_create_def_policy,
 	.destroy_def_policy = flow_dv_destroy_def_policy,
+	.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
-- 
2.27.0


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

* [dpdk-dev] [PATCH v4 4/4] net/mlx5: connect meter policy to created flows
  2021-04-14  6:40 ` [dpdk-dev] [PATCH v4 0/4] net/mlx5: support meter policy operations Li Zhang
                     ` (2 preceding siblings ...)
  2021-04-14  6:40   ` [dpdk-dev] [PATCH v4 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
@ 2021-04-14  6:40   ` Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-14  6:40 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs
  Cc: dev, thomas, rasland, roniba, Shun Hao

From: Shun Hao <shunh@nvidia.com>

Currently ASO meter must be followed by policy table, so this adds
the support that connecting meter and policy table.

There are several cases to be considered:
1. For non-termination policy, connect meter to the default policy
table.
2. For non-RSS termination policy case, simply get the policy
table id and connect meter to it.
3. For RSS termination policy case, need to split the flow due
to RSS info in policy, and translate each sub-flow using that RSS,
then create the sub policy table to be connected.
4. In termination policy case, if there's no actions to modify the
packet before meter, no need to use set_tag to save meter id in
register. Only add a new flow in drop table using the same match
criteria as suf-flow, to save cache miss.

Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 doc/guides/nics/mlx5.rst        |  12 +
 drivers/net/mlx5/mlx5_flow.c    | 446 ++++++++++++++++++++++++++++----
 drivers/net/mlx5/mlx5_flow.h    |   4 +
 drivers/net/mlx5/mlx5_flow_dv.c |  15 ++
 4 files changed, 420 insertions(+), 57 deletions(-)

diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index d287b3aca1..1e67a91ee7 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -106,6 +106,7 @@ Features
 - E-Switch mirroring and modify.
 - 21844 flow priorities for ingress or egress flow groups greater than 0 and for any transfer
   flow group.
+- Flow metering, including meter policy API.
 
 Limitations
 -----------
@@ -400,10 +401,21 @@ Limitations
   - Hairpin in switchdev SR-IOV mode is not supported till now.
 
 - Meter:
+
   - All the meter colors with drop action will be counted only by the global drop statistics.
   - Green color is not supported with drop action.
   - Yellow detection is not supported.
   - Red color must be with drop action.
+  - Meter statistics are supported only for drop case.
+  - Meter yellow color detection is not supported.
+  - A meter action created with pre-defined policy must be the last action in the flow except single case where the policy actions are:
+     - green: NULL or END.
+     - yellow: NULL or END.
+     - RED: DROP / END.
+  - The only supported meter policy actions:
+     - green: QUEUE, RSS, PORT_ID, JUMP, MARK and SET_TAG.
+     - yellow: must be empty.
+     - RED: must be DROP.
 
 Statistics
 ----------
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index a8aaf1ed8e..d1b4087866 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -3343,18 +3343,52 @@ flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 	fops->destroy(dev, flow);
 }
 
+/**
+ * Flow driver find RSS policy tbl API. This abstracts calling driver
+ * specific functions. Parent flow (rte_flow) should have driver
+ * type (drv_type). It will find the RSS policy table that has the rss_desc.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in, out] flow
+ *   Pointer to flow structure.
+ * @param[in] policy_id
+ *   The policy id of a meter.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_drv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+		struct rte_flow *flow,
+		struct mlx5_flow_meter_policy *policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	const struct mlx5_flow_driver_ops *fops;
+	enum mlx5_flow_drv_type type = flow->drv_type;
+
+	MLX5_ASSERT(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
+	fops = flow_get_drv_ops(type);
+	return fops->meter_sub_policy_rss_prepare(dev, policy, rss_desc);
+}
+
 /**
  * Get RSS action from the action list.
  *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
+ * @param[in] flow
+ *   Parent flow structure pointer.
  *
  * @return
  *   Pointer to the RSS action if exist, else return NULL.
  */
 static const struct rte_flow_action_rss*
-flow_get_rss_action(const struct rte_flow_action actions[])
+flow_get_rss_action(struct rte_eth_dev *dev,
+		    const struct rte_flow_action actions[])
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
 	const struct rte_flow_action_rss *rss = NULL;
 
 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -3372,6 +3406,23 @@ flow_get_rss_action(const struct rte_flow_action actions[])
 					rss = act->conf;
 			break;
 		}
+		case RTE_FLOW_ACTION_TYPE_METER:
+		{
+			uint32_t mtr_idx;
+			struct mlx5_flow_meter_info *fm;
+			struct mlx5_flow_meter_policy *policy;
+			const struct rte_flow_action_meter *mtr = actions->conf;
+
+			fm = mlx5_flow_meter_find(priv, mtr->mtr_id, &mtr_idx);
+			if (fm) {
+				policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+				if (policy && policy->is_rss)
+					rss =
+				policy->act_cnt[RTE_COLOR_GREEN].rss->conf;
+			}
+			break;
+		}
 		default:
 			break;
 		}
@@ -3670,13 +3721,75 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
 	return actions_n + 1;
 }
 
+/**
+ * Check if the action will change packet.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] type
+ *   action type.
+ *
+ * @return
+ *   true if action will change packet, false otherwise.
+ */
+static bool flow_check_modify_action_type(struct rte_eth_dev *dev,
+					  enum rte_flow_action_type type)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	switch (type) {
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
+	case RTE_FLOW_ACTION_TYPE_DEC_TTL:
+	case RTE_FLOW_ACTION_TYPE_SET_TTL:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_META:
+	case RTE_FLOW_ACTION_TYPE_SET_TAG:
+	case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+	case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
+		return true;
+	case RTE_FLOW_ACTION_TYPE_FLAG:
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		if (priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
+			return true;
+		else
+			return false;
+	default:
+		return false;
+	}
+}
+
 /**
  * Check meter action from the action list.
  *
+ * @param dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
  * @param[out] has_mtr
  *   Pointer to the meter exist flag.
+ * @param[out] has_modify
+ *   Pointer to the flag showing there's packet change action.
  * @param[out] meter_id
  *   Pointer to the meter id.
  *
@@ -3684,9 +3797,9 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
  *   Total number of actions.
  */
 static int
-flow_check_meter_action(const struct rte_flow_action actions[],
-			bool *has_mtr,
-			uint32_t *meter_id)
+flow_check_meter_action(struct rte_eth_dev *dev,
+			const struct rte_flow_action actions[],
+			bool *has_mtr, bool *has_modify, uint32_t *meter_id)
 {
 	const struct rte_flow_action_meter *mtr = NULL;
 	int actions_n = 0;
@@ -3703,6 +3816,9 @@ flow_check_meter_action(const struct rte_flow_action actions[],
 		default:
 			break;
 		}
+		if (!*has_mtr)
+			*has_modify |= flow_check_modify_action_type(dev,
+								actions->type);
 		actions_n++;
 	}
 	/* Count RTE_FLOW_ACTION_TYPE_END. */
@@ -4348,6 +4464,108 @@ flow_create_split_inner(struct rte_eth_dev *dev,
 	return flow_drv_translate(dev, dev_flow, attr, items, actions, error);
 }
 
+/**
+ * Get the sub policy of a meter.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
+ * @param[in] policy_id;
+ *   Meter Policy id.
+ * @param[in] attr
+ *   Flow rule attributes.
+ * @param[in] items
+ *   Pattern specification (list terminated by the END pattern item).
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   Pointer to the meter sub policy, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+get_meter_sub_policy(struct rte_eth_dev *dev,
+		     struct rte_flow *flow,
+		     uint32_t policy_id,
+		     const struct rte_flow_attr *attr,
+		     const struct rte_flow_item items[],
+		     struct rte_flow_error *error)
+{
+	struct mlx5_flow_meter_policy *policy;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+
+	policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	if (!policy) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Failed to find Meter Policy.");
+		goto exit;
+	}
+	if (policy->is_rss) {
+		struct mlx5_flow_workspace *wks =
+				mlx5_flow_get_thread_workspace();
+		struct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};
+		uint32_t i;
+
+		MLX5_ASSERT(wks);
+		/**
+		 * This is a tmp dev_flow,
+		 * no need to register any matcher for it in translate.
+		 */
+		wks->skip_matcher_reg = 1;
+		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+			struct mlx5_flow dev_flow = {0};
+			struct mlx5_flow_handle dev_handle = { {0} };
+			const void *rss_act = policy->act_cnt[i].rss->conf;
+			struct rte_flow_action rss_actions[2] = {
+				[0] = {
+					.type = RTE_FLOW_ACTION_TYPE_RSS,
+					.conf = rss_act
+				},
+				[1] = {
+					.type = RTE_FLOW_ACTION_TYPE_END,
+					.conf = NULL
+				}
+			};
+
+			dev_flow.handle = &dev_handle;
+			dev_flow.ingress = attr->ingress;
+			dev_flow.flow = flow;
+			dev_flow.external = 0;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+			dev_flow.dv.transfer = attr->transfer;
+#endif
+			/* Translate RSS action to get rss hash fields. */
+			if (flow_drv_translate(dev, &dev_flow, attr,
+						items, rss_actions, error))
+				goto exit;
+			rss_desc_v[i] = wks->rss_desc;
+			rss_desc_v[i].key_len = MLX5_RSS_HASH_KEY_LEN;
+			rss_desc_v[i].hash_fields = dev_flow.hash_fields;
+			rss_desc_v[i].queue_num = rss_desc_v[i].hash_fields ?
+						  rss_desc_v[i].queue_num : 1;
+			rss_desc[i] = &rss_desc_v[i];
+		}
+		sub_policy = flow_drv_meter_sub_policy_rss_prepare(dev,
+						flow, policy, rss_desc);
+	} else {
+		enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+		sub_policy = policy->sub_policys[mtr_domain][0];
+	}
+	if (!sub_policy) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Failed to get meter sub-policy.");
+		goto exit;
+	}
+exit:
+	return sub_policy;
+}
+
 /**
  * Split the meter flow.
  *
@@ -4378,13 +4596,15 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *   Suffix flow actions.
  * @param[out] actions_pre
  *   Prefix flow actions.
+ * @param[out] mtr_flow_id
+ *   Pointer to meter flow id.
  * @param[out] error
  *   Perform verbose error reporting if not NULL.
  *
  * @return
- *   The flow id, 0 otherwise and rte_errno is set.
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
-static uint32_t
+static int
 flow_meter_split_prep(struct rte_eth_dev *dev,
 		      struct rte_flow *flow,
 		      struct mlx5_flow_meter_info *fm,
@@ -4394,6 +4614,7 @@ 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[],
+		      uint32_t *mtr_flow_id,
 		      struct rte_flow_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
@@ -4407,7 +4628,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	uint32_t tag_id = 0;
 	bool copy_vlan = false;
 	struct rte_flow_action *hw_mtr_action;
-	struct rte_flow_action_jump *jump_data;
 	struct rte_flow_action *action_pre_head = NULL;
 	bool mtr_first = priv->sh->meter_aso_en &&
 			(attr->egress ||
@@ -4462,7 +4682,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 			break;
 		}
 		if (!action_cur)
-			action_cur = actions_sfx++;
+			action_cur = (fm->def_policy) ?
+					actions_sfx++ : actions_pre++;
 		memcpy(action_cur, actions, sizeof(struct rte_flow_action));
 	}
 	/* Add end action to the actions. */
@@ -4472,38 +4693,61 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		 * For ASO meter, need to add an extra jump action explicitly,
 		 * to jump from meter to policer table.
 		 */
-		hw_mtr_action = actions_pre;
-		hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
-		actions_pre++;
-		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
-		actions_pre++;
-		jump_data = (struct rte_flow_action_jump *)actions_pre;
-		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_POLICY;
-		hw_mtr_action->conf = jump_data;
-		actions_pre = (struct rte_flow_action *)(jump_data + 1);
-	} else {
-		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
-		actions_pre++;
+		struct mlx5_flow_meter_sub_policy *sub_policy;
+		struct mlx5_flow_tbl_data_entry *tbl_data;
+
+		if (!fm->def_policy) {
+			sub_policy = get_meter_sub_policy(dev, flow,
+							  fm->policy_id, attr,
+							  items, error);
+			if (!sub_policy)
+				return -rte_errno;
+		} else {
+			enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+
+			sub_policy =
+			&priv->sh->mtrmng->def_policy[mtr_domain]->sub_policy;
+		}
+		tbl_data = container_of(sub_policy->tbl_rsc,
+					struct mlx5_flow_tbl_data_entry, tbl);
+		hw_mtr_action = actions_pre++;
+		hw_mtr_action->type = (enum rte_flow_action_type)
+				      MLX5_RTE_FLOW_ACTION_TYPE_JUMP;
+		hw_mtr_action->conf = tbl_data->jump.action;
 	}
-	/* Generate meter flow_id only if support multiple flows per meter. */
-	mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
-	if (!tag_id)
+	actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+	actions_pre++;
+	if (!tag_action)
 		return rte_flow_error_set(error, ENOMEM,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Failed to allocate meter flow id.");
-	flow_id = tag_id - 1;
-	flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
-	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
-		mlx5_ipool_free(fm->flow_ipool, tag_id);
-		return rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Meter flow id exceeds max limit.");
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"No tag action space.");
+	if (!mtr_flow_id) {
+		tag_action->type = RTE_FLOW_ACTION_TYPE_VOID;
+		goto exit;
+	}
+	/* Only default-policy Meter creates mtr flow id. */
+	if (fm->def_policy) {
+		mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
+		if (!tag_id)
+			return rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to allocate meter flow id.");
+		flow_id = tag_id - 1;
+		flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
+		flow_id_bits = flow_id_bits ? flow_id_bits : 1;
+		if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) >
+		    mtr_reg_bits) {
+			mlx5_ipool_free(fm->flow_ipool, tag_id);
+			return rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter flow id exceeds max limit.");
+		}
+		if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+			priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	}
-	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
-		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -4533,7 +4777,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
 	sfx_items++;
 	/* Build tag actions and items for meter_id/meter flow_id. */
-	assert(tag_action);
 	set_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;
 	tag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;
 	tag_item_mask = tag_item_spec + 1;
@@ -4551,8 +4794,9 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	 */
 	for (shift = 0; shift < flow_id_bits; shift++)
 		flow_id_reversed = (flow_id_reversed << 1) |
-			      ((flow_id >> shift) & 0x1);
-	set_tag->data |= flow_id_reversed << (mtr_reg_bits - flow_id_bits);
+				((flow_id >> shift) & 0x1);
+	set_tag->data |=
+		flow_id_reversed << (mtr_reg_bits - flow_id_bits);
 	tag_item_spec->id = set_tag->id;
 	tag_item_spec->data = set_tag->data << mtr_id_offset;
 	tag_item_mask->data = UINT32_MAX << mtr_id_offset;
@@ -4564,7 +4808,10 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	tag_item->spec = tag_item_spec;
 	tag_item->last = NULL;
 	tag_item->mask = tag_item_mask;
-	return tag_id;
+exit:
+	if (mtr_flow_id)
+		*mtr_flow_id = tag_id;
+	return 0;
 }
 
 /**
@@ -5228,6 +5475,57 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/**
+ * Create meter internal drop flow with the original pattern.
+ *
+ * @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] flow_split_info
+ *   Pointer to flow split info structure.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   0 on success, negative value otherwise
+ */
+static uint32_t
+flow_meter_create_drop_flow_with_org_pattern(struct rte_eth_dev *dev,
+			struct rte_flow *flow,
+			const struct rte_flow_attr *attr,
+			const struct rte_flow_item items[],
+			struct mlx5_flow_split_info *flow_split_info,
+			struct mlx5_flow_meter_info *fm,
+			struct rte_flow_error *error)
+{
+	struct mlx5_flow *dev_flow = NULL;
+	struct rte_flow_attr drop_attr = *attr;
+	struct rte_flow_action drop_actions[3];
+	struct mlx5_flow_split_info drop_split_info = *flow_split_info;
+
+	MLX5_ASSERT(fm->drop_cnt);
+	drop_actions[0].type =
+		(enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_COUNT;
+	drop_actions[0].conf = (void *)(uintptr_t)fm->drop_cnt;
+	drop_actions[1].type = RTE_FLOW_ACTION_TYPE_DROP;
+	drop_actions[1].conf = NULL;
+	drop_actions[2].type = RTE_FLOW_ACTION_TYPE_END;
+	drop_actions[2].conf = NULL;
+	drop_split_info.external = false;
+	drop_split_info.skip_scale |= 1 << MLX5_SCALE_FLOW_GROUP_BIT;
+	drop_split_info.table_id = MLX5_MTR_TABLE_ID_DROP;
+	drop_attr.group = MLX5_FLOW_TABLE_LEVEL_METER;
+	return flow_create_split_inner(dev, flow, &dev_flow,
+				&drop_attr, items, drop_actions,
+				&drop_split_info, error);
+}
+
 /**
  * The splitting for meter feature.
  *
@@ -5272,18 +5570,21 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 	struct mlx5_flow *dev_flow = NULL;
 	struct rte_flow_attr sfx_attr = *attr;
 	struct mlx5_flow_meter_info *fm = NULL;
+	uint8_t skip_scale_restore;
 	bool has_mtr = false;
-	uint32_t meter_id;
+	bool has_modify = false;
+	bool set_mtr_reg = true;
+	uint32_t meter_id = 0;
 	uint32_t mtr_idx = 0;
-	uint32_t mtr_tag_id = 0;
+	uint32_t mtr_flow_id = 0;
 	size_t act_size;
 	size_t item_size;
 	int actions_n = 0;
 	int ret = 0;
 
 	if (priv->mtr_en)
-		actions_n = flow_check_meter_action(actions, &has_mtr,
-						    &meter_id);
+		actions_n = flow_check_meter_action(dev, actions, &has_mtr,
+						    &has_modify, &meter_id);
 	if (has_mtr) {
 		if (flow->meter) {
 			fm = flow_dv_meter_find_by_idx(priv, flow->meter);
@@ -5303,11 +5604,20 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 				return -rte_errno;
 			flow->meter = mtr_idx;
 		}
+		MLX5_ASSERT(wks);
 		wks->fm = fm;
+		/*
+		 * If it isn't default-policy Meter, and
+		 * 1. There's no action in flow to change
+		 *    packet (modify/encap/decap etc.), OR
+		 * 2. No drop count needed for this meter.
+		 * no need to use regC to save meter id anymore.
+		 */
+		if (!fm->def_policy && (!has_modify || !fm->drop_cnt))
+			set_mtr_reg = false;
 		/* Prefix actions: meter, decap, encap, tag, jump, end. */
 		act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
-			   sizeof(struct mlx5_rte_flow_action_set_tag) +
-			   sizeof(struct rte_flow_action_jump);
+			   sizeof(struct mlx5_rte_flow_action_set_tag);
 		/* Suffix items: tag, vlan, port id, end. */
 #define METER_SUFFIX_ITEM 4
 		item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
@@ -5321,27 +5631,48 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 						  "meter flow");
 		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
 			     act_size);
-		pre_actions = sfx_actions + actions_n;
-		mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
-						   items, sfx_items, actions,
-						   sfx_actions, pre_actions,
-						   error);
-		if (!mtr_tag_id) {
+		/* There's no suffix flow for meter of non-default policy. */
+		if (!fm->def_policy)
+			pre_actions = sfx_actions + 1;
+		else
+			pre_actions = sfx_actions + actions_n;
+		ret = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+					    items, sfx_items, actions,
+					    sfx_actions, pre_actions,
+					    (set_mtr_reg ? &mtr_flow_id : NULL),
+					    error);
+		if (ret) {
 			ret = -rte_errno;
 			goto exit;
 		}
 		/* Add the prefix subflow. */
 		flow_split_info->prefix_mark = 0;
+		skip_scale_restore = flow_split_info->skip_scale;
+		flow_split_info->skip_scale |=
+			1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT;
 		ret = flow_create_split_inner(dev, flow, &dev_flow,
 					      attr, items, pre_actions,
 					      flow_split_info, error);
+		flow_split_info->skip_scale = skip_scale_restore;
 		if (ret) {
-			mlx5_ipool_free(fm->flow_ipool, mtr_tag_id);
+			if (mtr_flow_id)
+				mlx5_ipool_free(fm->flow_ipool, mtr_flow_id);
 			ret = -rte_errno;
 			goto exit;
 		}
-		dev_flow->handle->split_flow_id = mtr_tag_id;
-		dev_flow->handle->is_meter_flow_id = 1;
+		if (mtr_flow_id) {
+			dev_flow->handle->split_flow_id = mtr_flow_id;
+			dev_flow->handle->is_meter_flow_id = 1;
+		}
+		if (!fm->def_policy) {
+			if (!set_mtr_reg && fm->drop_cnt)
+				ret =
+			flow_meter_create_drop_flow_with_org_pattern(dev, flow,
+							&sfx_attr, items,
+							flow_split_info,
+							fm, error);
+			goto exit;
+		}
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
 				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
@@ -5349,6 +5680,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 		flow_split_info->prefix_layers =
 				flow_get_prefix_layer_flags(dev_flow);
 		flow_split_info->prefix_mark = dev_flow->handle->mark;
+		flow_split_info->table_id = MLX5_MTR_TABLE_ID_SUFFIX;
 	}
 	/* Add the prefix subflow. */
 	ret = flow_create_split_metadata(dev, flow,
@@ -5736,7 +6068,7 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,
 	memset(rss_desc, 0, offsetof(struct mlx5_flow_rss_desc, queue));
 	/* RSS Action only works on NIC RX domain */
 	if (attr->ingress && !attr->transfer)
-		rss = flow_get_rss_action(p_actions_rx);
+		rss = flow_get_rss_action(dev, p_actions_rx);
 	if (rss) {
 		if (flow_rss_workspace_adjust(wks, rss_desc, rss->queue_num))
 			return 0;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index ddfab494b8..211ebe20bb 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -37,6 +37,8 @@ enum mlx5_rte_flow_action_type {
 	MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS,
 	MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET,
 	MLX5_RTE_FLOW_ACTION_TYPE_AGE,
+	MLX5_RTE_FLOW_ACTION_TYPE_JUMP,
+	MLX5_RTE_FLOW_ACTION_TYPE_COUNT,
 };
 
 #define MLX5_SHARED_ACTION_TYPE_OFFSET 30
@@ -1048,6 +1050,8 @@ struct mlx5_flow_workspace {
 	uint32_t rssq_num; /* Allocated queue num in rss_desc. */
 	uint32_t flow_idx; /* Intermediate device flow index. */
 	struct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */
+	uint32_t skip_matcher_reg:1;
+	/* Indicates if need to skip matcher register in translate. */
 };
 
 struct mlx5_flow_split_info {
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 96adf3f9cb..f0cfa47f99 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7423,6 +7423,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,
 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
 
 	MLX5_ASSERT(wks);
+	wks->skip_matcher_reg = 0;
 	/* In case of corrupting the memory. */
 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
 		rte_flow_error_set(error, ENOSPC,
@@ -11254,6 +11255,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
 		int action_type = actions->type;
 		const struct rte_flow_action *found_action = NULL;
 		uint32_t jump_group = 0;
+		struct mlx5_flow_counter *cnt;
 
 		if (!mlx5_flow_os_action_supported(action_type))
 			return rte_flow_error_set(error, ENOTSUP,
@@ -11434,6 +11436,12 @@ flow_dv_translate(struct rte_eth_dev *dev,
 				age = action->conf;
 			action_flags |= MLX5_FLOW_ACTION_COUNT;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
+			cnt = flow_dv_counter_get_by_idx(dev,
+				(uint32_t)(uintptr_t)action->conf, NULL);
+			MLX5_ASSERT(cnt != NULL);
+			dev_flow->dv.actions[actions_n++] = cnt->action;
+			break;
 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
 			dev_flow->dv.actions[actions_n++] =
 						priv->sh->pop_vlan_action;
@@ -11538,6 +11546,11 @@ flow_dv_translate(struct rte_eth_dev *dev,
 			/* If decap is followed by encap, handle it at encap. */
 			action_flags |= MLX5_FLOW_ACTION_DECAP;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
+			dev_flow->dv.actions[actions_n++] =
+				(void *)(uintptr_t)action->conf;
+			action_flags |= MLX5_FLOW_ACTION_JUMP;
+			break;
 		case RTE_FLOW_ACTION_TYPE_JUMP:
 			jump_group = ((const struct rte_flow_action_jump *)
 							action->conf)->group;
@@ -12093,6 +12106,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
 	}
 	dev_flow->dv.actions_n = actions_n;
 	dev_flow->act_flags = action_flags;
+	if (wks->skip_matcher_reg)
+		return 0;
 	/* Register matcher. */
 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
 				    matcher.mask.size);
-- 
2.27.0


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

* [dpdk-dev] [PATCH v5 0/4] net/mlx5: support meter policy operations
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (6 preceding siblings ...)
  2021-04-14  6:40 ` [dpdk-dev] [PATCH v4 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-15  5:05 ` Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 1/4] " Li Zhang
                     ` (3 more replies)
  2021-04-15  5:09 ` [dpdk-dev] [PATCH v6 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (2 subsequent siblings)
  10 siblings, 4 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-15  5:05 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Depends-on: series=16351  ("Add ASO meter support in MLX5 PMD ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16351

Depends-on: series=16357  ("Support meter policy API ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16357

V2: Add MLX5_MTR_DEFAULT_POLICY_ID in MLX5 PMD
V3: Fix comments about Depends-on
V4: Fix comments about rte_mtr_meter_policy_add.
V5: Fix comments about destory meter on different ports.

Li Zhang (3):
  net/mlx5: support meter policy operations
  net/mlx5: support meter creation with policy
  net/mlx5: prepare sub-policy for a flow with meter

Shun Hao (1):
  net/mlx5: connect meter policy to created flows

 doc/guides/nics/mlx5.rst           |   12 +
 drivers/net/mlx5/linux/mlx5_os.c   |   13 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  212 +++-
 drivers/net/mlx5/mlx5_flow.c       |  654 ++++++++--
 drivers/net/mlx5/mlx5_flow.h       |  119 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1896 ++++++++++++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_meter.c |  742 ++++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 10 files changed, 3373 insertions(+), 363 deletions(-)

-- 
2.27.0


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

* [dpdk-dev] [PATCH v5 1/4] net/mlx5: support meter policy operations
  2021-04-15  5:05 ` [dpdk-dev] [PATCH v5 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-15  5:05   ` Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 2/4] net/mlx5: support meter creation with policy Li Zhang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-15  5:05 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

Implement the next policy operations:
validate:
The driver doesn't support to configure actions in the flow
after the meter action except one case when the meter policy
is configured to do nothing in GREEN\YELLOW and only DROP action
in RED, this special policy is called non-terminated policy
and is handed as a singleton object internally.

For all the terminated policies, the next actions are supported:
GREEN - QUEUE, RSS, PORT_ID, JUMP, DROP, MARK and SET_TAG.
YELLOW - not supported at all -> must be empty.
RED - must include DROP action.

Hence, in ingress case, for example,
QUEUE\RSS\JUMP must be configured as last action for GREEN color.

All the above limitations will be validated.

create:
Validate the policy configuration.
Prepare the related tables and actions.

destroy:
Release the created policy resources.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |    2 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  158 +++-
 drivers/net/mlx5/mlx5_flow.c       |  192 +++-
 drivers/net/mlx5/mlx5_flow.h       |   73 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1412 +++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c |  445 ++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 9 files changed, 2242 insertions(+), 128 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index bec288c840..276283d492 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1299,7 +1299,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			log_obj_size <=
 			config->hca_attr.qos.log_meter_aso_max_alloc) {
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv);
+				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
 				if (err) {
 					err = -err;
 					goto error;
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 572db1bc67..b4cdaa7131 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -350,6 +350,20 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {
 		.free = mlx5_free,
 		.type = "mlx5_shared_action_rss",
 	},
+	[MLX5_IPOOL_MTR_POLICY] = {
+		/**
+		 * The ipool index should grow continually from small to big,
+		 * for policy idx, so not set grow_trunk to avoid policy index
+		 * not jump continually.
+		 */
+		.size = sizeof(struct mlx5_flow_meter_sub_policy),
+		.trunk_size = 64,
+		.need_lock = 1,
+		.release_mem_en = 1,
+		.malloc = mlx5_malloc,
+		.free = mlx5_free,
+		.type = "mlx5_meter_policy_ipool",
+	},
 };
 
 
@@ -569,27 +583,25 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh)
  *   Pointer to mlx5_dev_ctx_shared object to free
  */
 int
-mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv)
+mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!priv->mtr_idx_tbl) {
-		priv->mtr_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
-		if (!priv->mtr_idx_tbl) {
-			DRV_LOG(ERR, "fail to create meter lookup table.");
-			rte_errno = ENOMEM;
-			return -ENOMEM;
-		}
-	}
-	if (!priv->sh->mtrmng) {
-		priv->sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
-			sizeof(*priv->sh->mtrmng),
+	if (!sh->mtrmng) {
+		sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(*sh->mtrmng),
 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
-		if (!priv->sh->mtrmng) {
-			DRV_LOG(ERR, "mlx5_aso_mtr_pools_mng allocation was failed.");
+		if (!sh->mtrmng) {
+			DRV_LOG(ERR,
+			"meter management allocation was failed.");
 			rte_errno = ENOMEM;
 			return -ENOMEM;
 		}
-		rte_spinlock_init(&priv->sh->mtrmng->mtrsl);
-		LIST_INIT(&priv->sh->mtrmng->meters);
+		if (sh->meter_aso_en) {
+			rte_spinlock_init(&sh->mtrmng->pools_mng.mtrsl);
+			LIST_INIT(&sh->mtrmng->pools_mng.meters);
+			sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		}
+		sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
 	}
 	return 0;
 }
@@ -605,31 +617,34 @@ static void
 mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
 {
 	struct mlx5_aso_mtr_pool *mtr_pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng;
+	struct mlx5_flow_mtr_mng *mtrmng = sh->mtrmng;
 	uint32_t idx;
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
 	struct mlx5_aso_mtr *aso_mtr;
 	int i;
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
 
-	mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
-	idx = mtrmng->n_valid;
-	while (idx--) {
-		mtr_pool = mtrmng->pools[idx];
+	if (sh->meter_aso_en) {
+		mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
+		idx = mtrmng->pools_mng.n_valid;
+		while (idx--) {
+			mtr_pool = mtrmng->pools_mng.pools[idx];
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
-		for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
-			aso_mtr = &mtr_pool->mtrs[i];
-			if (aso_mtr->fm.meter_action)
-				claim_zero(mlx5_glue->destroy_flow_action
-						(aso_mtr->fm.meter_action));
-		}
+			for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
+				aso_mtr = &mtr_pool->mtrs[i];
+				if (aso_mtr->fm.meter_action)
+					claim_zero
+					(mlx5_glue->destroy_flow_action
+					(aso_mtr->fm.meter_action));
+			}
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
-		claim_zero(mlx5_devx_cmd_destroy
+			claim_zero(mlx5_devx_cmd_destroy
 						(mtr_pool->devx_obj));
-		mtrmng->n_valid--;
-		mlx5_free(mtr_pool);
+			mtrmng->pools_mng.n_valid--;
+			mlx5_free(mtr_pool);
+		}
+		mlx5_free(sh->mtrmng->pools_mng.pools);
 	}
-	mlx5_free(sh->mtrmng->pools);
 	mlx5_free(sh->mtrmng);
 	sh->mtrmng = NULL;
 }
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index a8e11023cc..cb7c75aa2e 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -56,6 +56,7 @@ enum mlx5_ipool_index {
 	MLX5_IPOOL_RTE_FLOW, /* Pool for rte_flow. */
 	MLX5_IPOOL_RSS_EXPANTION_FLOW_ID, /* Pool for Queue/RSS flow ID. */
 	MLX5_IPOOL_RSS_SHARED_ACTIONS, /* Pool for RSS shared actions. */
+	MLX5_IPOOL_MTR_POLICY, /* Pool for meter policy resource. */
 	MLX5_IPOOL_MAX,
 };
 
@@ -580,9 +581,126 @@ struct mlx5_dev_shared_port {
 	/* Aging information for per port. */
 };
 
+/*
+ * Max number of actions per DV flow.
+ * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
+ * in rdma-core file providers/mlx5/verbs.c.
+ */
+#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
+
 /*ASO flow meter structures*/
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
+/* Yellow is not supported. */
+#define MLX5_MTR_RTE_COLORS (RTE_COLOR_GREEN + 1)
+/* table_id 22 bits in mlx5_flow_tbl_key so limit policy number. */
+#define MLX5_MAX_SUB_POLICY_TBL_NUM 0x3FFFFF
+#define MLX5_INVALID_POLICY_ID UINT32_MAX
+/* Suffix table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_SUFFIX 1
+/* Drop table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_DROP 2
+
+enum mlx5_meter_domain {
+	MLX5_MTR_DOMAIN_INGRESS,
+	MLX5_MTR_DOMAIN_EGRESS,
+	MLX5_MTR_DOMAIN_TRANSFER,
+	MLX5_MTR_DOMAIN_MAX,
+};
+#define MLX5_MTR_DOMAIN_INGRESS_BIT  (1 << MLX5_MTR_DOMAIN_INGRESS)
+#define MLX5_MTR_DOMAIN_EGRESS_BIT   (1 << MLX5_MTR_DOMAIN_EGRESS)
+#define MLX5_MTR_DOMAIN_TRANSFER_BIT (1 << MLX5_MTR_DOMAIN_TRANSFER)
+#define MLX5_MTR_ALL_DOMAIN_BIT      (MLX5_MTR_DOMAIN_INGRESS_BIT | \
+					MLX5_MTR_DOMAIN_EGRESS_BIT | \
+					MLX5_MTR_DOMAIN_TRANSFER_BIT)
+
+/*
+ * Meter sub-policy structure.
+ * Each RSS TIR in meter policy need its own sub-policy resource.
+ */
+struct mlx5_flow_meter_sub_policy {
+	uint32_t main_policy_id:1;
+	/* Main policy id is same as this sub_policy id. */
+	uint32_t idx:31;
+	/* Index to sub_policy ipool entity. */
+	void *main_policy;
+	/* Point to struct mlx5_flow_meter_policy. */
+	struct mlx5_flow_tbl_resource *tbl_rsc;
+	/* The sub-policy table resource. */
+	uint32_t rix_hrxq[MLX5_MTR_RTE_COLORS];
+	/* Index to TIR resource. */
+	struct mlx5_flow_tbl_resource *jump_tbl[MLX5_MTR_RTE_COLORS];
+	/* Meter jump/drop table. */
+	struct mlx5_flow_dv_matcher *color_matcher[RTE_COLORS];
+	/* Matcher for Color. */
+	void *color_rule[RTE_COLORS];
+	/* Meter green/yellow/drop rule. */
+};
+
+struct mlx5_meter_policy_acts {
+	uint8_t actions_n;
+	/* Number of actions. */
+	void *dv_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS];
+	/* Action list. */
+};
+
+struct mlx5_meter_policy_action_container {
+	uint32_t rix_mark;
+	/* Index to the mark action. */
+	struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
+	/* Pointer to modify header resource in cache. */
+	uint8_t fate_action;
+	/* Fate action type. */
+	union {
+		struct rte_flow_action *rss;
+		/* Rss action configuration. */
+		uint32_t rix_port_id_action;
+		/* Index to port ID action resource. */
+		void *dr_jump_action[MLX5_MTR_DOMAIN_MAX];
+		/* Jump/drop action per color. */
+	};
+};
+
+/* Flow meter policy parameter structure. */
+struct mlx5_flow_meter_policy {
+	uint32_t is_rss:1;
+	/* Is RSS policy table. */
+	uint32_t ingress:1;
+	/* Rule applies to ingress domain. */
+	uint32_t egress:1;
+	/* Rule applies to egress domain. */
+	uint32_t transfer:1;
+	/* Rule applies to transfer domain. */
+	rte_spinlock_t sl;
+	uint32_t ref_cnt;
+	/* Use count. */
+	struct mlx5_meter_policy_action_container act_cnt[MLX5_MTR_RTE_COLORS];
+	/* Policy actions container. */
+	void *dr_drop_action[MLX5_MTR_DOMAIN_MAX];
+	/* drop action for red color. */
+	uint16_t sub_policy_num;
+	/* Count sub policy tables, 3 bits per domain. */
+	struct mlx5_flow_meter_sub_policy **sub_policys[MLX5_MTR_DOMAIN_MAX];
+	/* Sub policy table array must be the end of struct. */
+};
+
+/* The maximum sub policy is relate to struct mlx5_rss_hash_fields[]. */
+#define MLX5_MTR_RSS_MAX_SUB_POLICY 7
+#define MLX5_MTR_SUB_POLICY_NUM_SHIFT  3
+#define MLX5_MTR_SUB_POLICY_NUM_MASK  0x7
+#define MLX5_MTRS_DEFAULT_RULE_PRIORITY 0xFFFF
+
+/* Flow meter default policy parameter structure.
+ * Policy index 0 is reserved by default policy table.
+ * Action per color as below:
+ * green - do nothing, yellow - do nothing, red - drop
+ */
+struct mlx5_flow_meter_def_policy {
+	struct mlx5_flow_meter_sub_policy sub_policy;
+	/* Policy rules jump to other tables. */
+	void *dr_jump_action[RTE_COLORS];
+	/* Jump action per color. */
+};
 
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
@@ -746,6 +864,28 @@ struct mlx5_aso_mtr_pools_mng {
 	struct mlx5_aso_mtr_pool **pools; /* ASO flow meter pool array. */
 };
 
+/* Meter management structure for global flow meter resource. */
+struct mlx5_flow_mtr_mng {
+	struct mlx5_aso_mtr_pools_mng pools_mng;
+	/* Pools management structure for ASO flow meter pools. */
+	struct mlx5_flow_meter_def_policy *def_policy[MLX5_MTR_DOMAIN_MAX];
+	/* Default policy table. */
+	uint32_t def_policy_id;
+	/* Default policy id. */
+	uint32_t def_policy_ref_cnt;
+	/** def_policy meter use count. */
+	struct mlx5_l3t_tbl *policy_idx_tbl;
+	/* Policy index lookup table. */
+	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop table. */
+	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Matcher meter in drop table. */
+	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
+	/* Default matcher in drop table. */
+	void *def_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Default rule in drop table. */
+};
+
 /* Table key of the hash organization. */
 union mlx5_flow_tbl_key {
 	struct {
@@ -772,9 +912,9 @@ struct mlx5_flow_tbl_resource {
 #define MLX5_FLOW_MREG_ACT_TABLE_GROUP (MLX5_MAX_TABLES - 1)
 #define MLX5_FLOW_MREG_CP_TABLE_GROUP (MLX5_MAX_TABLES - 2)
 /* Tables for metering splits should be added here. */
-#define MLX5_FLOW_TABLE_LEVEL_SUFFIX (MLX5_MAX_TABLES - 3)
-#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 4)
-#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_METER
+#define MLX5_FLOW_TABLE_LEVEL_METER (MLX5_MAX_TABLES - 3)
+#define MLX5_FLOW_TABLE_LEVEL_POLICY (MLX5_MAX_TABLES - 4)
+#define MLX5_MAX_TABLES_EXTERNAL MLX5_FLOW_TABLE_LEVEL_POLICY
 #define MLX5_MAX_TABLES_FDB UINT16_MAX
 #define MLX5_FLOW_TABLE_FACTOR 10
 
@@ -935,8 +1075,8 @@ struct mlx5_dev_ctx_shared {
 	struct mlx5_geneve_tlv_option_resource *geneve_tlv_option_resource;
 	/* Management structure for geneve tlv option */
 	rte_spinlock_t geneve_tlv_opt_sl; /* Lock for geneve tlv resource */
-	struct mlx5_aso_mtr_pools_mng *mtrmng;
-	/* Meter pools management structure. */
+	struct mlx5_flow_mtr_mng *mtrmng;
+	/* Meter management structure. */
 	struct mlx5_dev_shared_port port[]; /* per device port data array. */
 };
 
@@ -1237,7 +1377,7 @@ int mlx5_hairpin_cap_get(struct rte_eth_dev *dev,
 bool mlx5_flex_parser_ecpri_exist(struct rte_eth_dev *dev);
 int mlx5_flex_parser_ecpri_alloc(struct rte_eth_dev *dev);
 int mlx5_flow_aso_age_mng_init(struct mlx5_dev_ctx_shared *sh);
-int mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv);
+int mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh);
 
 /* mlx5_ethdev.c */
 
@@ -1463,6 +1603,12 @@ int mlx5_flow_meter_attach(struct mlx5_priv *priv,
 			   struct rte_flow_error *error);
 void mlx5_flow_meter_detach(struct mlx5_priv *priv,
 			    struct mlx5_flow_meter_info *fm);
+struct mlx5_flow_meter_policy *mlx5_flow_meter_policy_find
+		(struct rte_eth_dev *dev,
+		uint32_t policy_id,
+		uint32_t *policy_idx);
+int mlx5_flow_meter_flush(struct rte_eth_dev *dev,
+			  struct rte_mtr_error *error);
 
 /* mlx5_os.c */
 struct rte_pci_driver;
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index ee2c351649..81e0e3b7a9 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -1028,7 +1028,7 @@ flow_rxq_tunnel_ptype_update(struct mlx5_rxq_ctrl *rxq_ctrl)
  * @param[in] dev_handle
  *   Pointer to device flow handle structure.
  */
-static void
+void
 flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
 		       struct mlx5_flow_handle *dev_handle)
 {
@@ -4479,8 +4479,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		actions_pre++;
 		jump_data = (struct rte_flow_action_jump *)actions_pre;
 		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_METER;
+				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_POLICY;
 		hw_mtr_action->conf = jump_data;
 		actions_pre = (struct rte_flow_action *)(jump_data + 1);
 	} else {
@@ -5079,8 +5079,8 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	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);
+			  (MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+			  MLX5_FLOW_TABLE_LEVEL_METER);
 		/*
 		 * 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
@@ -5344,8 +5344,8 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 		dev_flow->handle->is_meter_flow_id = 1;
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_SUFFIX;
+				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+				 MLX5_FLOW_TABLE_LEVEL_METER;
 		flow_split_info->prefix_layers =
 				flow_get_prefix_layer_flags(dev_flow);
 		flow_split_info->prefix_mark = dev_flow->handle->mark;
@@ -6608,6 +6608,169 @@ mlx5_flow_ops_get(struct rte_eth_dev *dev __rte_unused,
 	return 0;
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] is_rss
+ *   Is RSS or not.
+ * @param[out] domain_bitmap
+ *   Domain bitmap.
+ * @param[out] is_def_policy
+ *   Is default policy or not.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->validate_mtr_acts(dev, actions, attr,
+			is_rss, domain_bitmap, is_def_policy, error);
+}
+
+/**
+ * Destroy the meter table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_acts(dev, mtr_policy);
+}
+
+/**
+ * Create policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+int
+mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_mtr_acts(dev, mtr_policy, actions, error);
+}
+
+/**
+ * Create policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+void
+mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_policy_rules(dev, mtr_policy);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_def_policy(dev);
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+int
+mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	return fops->create_def_policy(dev);
+}
+
 /**
  * Create the needed meter and suffix tables.
  *
@@ -6647,6 +6810,21 @@ mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
+/**
+ * Destroy the global meter drop table.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+void
+mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	const struct mlx5_flow_driver_ops *fops;
+
+	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+	fops->destroy_mtr_drop_tbls(dev);
+}
+
 /**
  * Allocate the needed aso flow meter id.
  *
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 7fa15eef7b..51d040c4d2 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -691,13 +691,6 @@ struct mlx5_flow_handle {
 #define MLX5_FLOW_HANDLE_VERBS_SIZE (sizeof(struct mlx5_flow_handle))
 #endif
 
-/*
- * Max number of actions per DV flow.
- * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
- * in rdma-core file providers/mlx5/verbs.c.
- */
-#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
-
 /** Device flow structure only for DV flow creation. */
 struct mlx5_flow_dv_workspace {
 	uint32_t group; /**< The group index. */
@@ -1099,6 +1092,7 @@ 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);
+typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1144,6 +1138,32 @@ typedef int (*mlx5_flow_sync_domain_t)
 			(struct rte_eth_dev *dev,
 			 uint32_t domains,
 			 uint32_t flags);
+typedef int (*mlx5_flow_validate_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+			 const struct rte_flow_action *actions[RTE_COLORS],
+			 struct rte_flow_attr *attr,
+			 bool *is_rss,
+			 uint8_t *domain_bitmap,
+			 bool *is_def_policy,
+			 struct rte_mtr_error *error);
+typedef int (*mlx5_flow_create_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+typedef void (*mlx5_flow_destroy_mtr_acts_t)
+			(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef void (*mlx5_flow_destroy_policy_rules_t)
+			(struct rte_eth_dev *dev,
+			  struct mlx5_flow_meter_policy *mtr_policy);
+typedef int (*mlx5_flow_create_def_policy_t)
+			(struct rte_eth_dev *dev);
+typedef void (*mlx5_flow_destroy_def_policy_t)
+			(struct rte_eth_dev *dev);
 
 struct mlx5_flow_driver_ops {
 	mlx5_flow_validate_t validate;
@@ -1155,8 +1175,16 @@ 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_destroy_mtr_drop_tbls_t destroy_mtr_drop_tbls;
 	mlx5_flow_mtr_alloc_t create_meter;
 	mlx5_flow_mtr_free_t free_meter;
+	mlx5_flow_validate_mtr_acts_t validate_mtr_acts;
+	mlx5_flow_create_mtr_acts_t create_mtr_acts;
+	mlx5_flow_destroy_mtr_acts_t destroy_mtr_acts;
+	mlx5_flow_create_policy_rules_t create_policy_rules;
+	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
+	mlx5_flow_create_def_policy_t create_def_policy;
+	mlx5_flow_destroy_def_policy_t destroy_def_policy;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1233,12 +1261,13 @@ static inline struct mlx5_aso_mtr *
 mlx5_aso_meter_by_idx(struct mlx5_priv *priv, uint32_t idx)
 {
 	struct mlx5_aso_mtr_pool *pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 
 	/* Decrease to original index. */
 	idx--;
-	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < mtrmng->n);
-	pool = mtrmng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
+	MLX5_ASSERT(idx / MLX5_ASO_MTRS_PER_POOL < pools_mng->n);
+	pool = pools_mng->pools[idx / MLX5_ASO_MTRS_PER_POOL];
 	return &pool->mtrs[idx % MLX5_ASO_MTRS_PER_POOL];
 }
 
@@ -1384,8 +1413,7 @@ 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_meter_flush(struct rte_eth_dev *dev,
-			  struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
@@ -1486,4 +1514,25 @@ int mlx5_flow_os_set_specific_workspace(struct mlx5_flow_workspace *data);
 void mlx5_flow_os_release_workspace(void);
 uint32_t mlx5_flow_mtr_alloc(struct rte_eth_dev *dev);
 void mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx);
+int mlx5_flow_validate_mtr_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error);
+void mlx5_flow_destroy_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_mtr_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error);
+int mlx5_flow_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+void mlx5_flow_destroy_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy);
+int mlx5_flow_create_def_policy(struct rte_eth_dev *dev);
+void mlx5_flow_destroy_def_policy(struct rte_eth_dev *dev);
+void flow_drv_rxq_flags_set(struct rte_eth_dev *dev,
+		       struct mlx5_flow_handle *dev_handle);
 #endif /* RTE_PMD_MLX5_FLOW_H_ */
diff --git a/drivers/net/mlx5/mlx5_flow_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c
index 62d2df054b..20cd4fe18c 100644
--- a/drivers/net/mlx5/mlx5_flow_aso.c
+++ b/drivers/net/mlx5/mlx5_flow_aso.c
@@ -311,11 +311,11 @@ mlx5_aso_queue_init(struct mlx5_dev_ctx_shared *sh,
 		mlx5_aso_age_init_sq(&sh->aso_age_mng->aso_sq);
 		break;
 	case ASO_OPC_MOD_POLICER:
-		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->sq, 0,
+		if (mlx5_aso_sq_create(sh->ctx, &sh->mtrmng->pools_mng.sq, 0,
 				  sh->tx_uar, sh->pdn, MLX5_ASO_QUEUE_LOG_DESC,
 				  sh->sq_ts_format))
 			return -1;
-		mlx5_aso_mtr_init_sq(&sh->mtrmng->sq);
+		mlx5_aso_mtr_init_sq(&sh->mtrmng->pools_mng.sq);
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -342,7 +342,7 @@ mlx5_aso_queue_uninit(struct mlx5_dev_ctx_shared *sh,
 		sq = &sh->aso_age_mng->aso_sq;
 		break;
 	case ASO_OPC_MOD_POLICER:
-		sq = &sh->mtrmng->sq;
+		sq = &sh->mtrmng->pools_mng.sq;
 		break;
 	default:
 		DRV_LOG(ERR, "Unknown ASO operation mode");
@@ -798,7 +798,7 @@ int
 mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_wqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	do {
@@ -830,7 +830,7 @@ int
 mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,
 			struct mlx5_aso_mtr *mtr)
 {
-	struct mlx5_aso_sq *sq = &sh->mtrmng->sq;
+	struct mlx5_aso_sq *sq = &sh->mtrmng->pools_mng.sq;
 	uint32_t poll_cqe_times = MLX5_MTR_POLL_WQE_CQE_TIMES;
 
 	if (__atomic_load_n(&mtr->state, __ATOMIC_RELAXED) ==
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index af3397fb55..759731333d 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -21,6 +21,8 @@
 #include <rte_gtp.h>
 #include <rte_eal_paging.h>
 #include <rte_mpls.h>
+#include <rte_mtr.h>
+#include <rte_mtr_driver.h>
 
 #include <mlx5_glue.h>
 #include <mlx5_devx_cmds.h>
@@ -184,6 +186,31 @@ flow_dv_attr_init(const struct rte_flow_item *item, union flow_dv_attr *attr,
 	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. */
@@ -4695,10 +4722,6 @@ flow_dv_validate_action_jump(struct rte_eth_dev *dev,
 					  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,
@@ -5928,9 +5951,10 @@ static int
 flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
-	void *old_pools = mtrmng->pools;
-	uint32_t resize = mtrmng->n + MLX5_MTRS_CONTAINER_RESIZE;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
+	void *old_pools = pools_mng->pools;
+	uint32_t resize = pools_mng->n + MLX5_MTRS_CONTAINER_RESIZE;
 	uint32_t mem_size = sizeof(struct mlx5_aso_mtr_pool *) * resize;
 	void *pools = mlx5_malloc(MLX5_MEM_ZERO, mem_size, 0, SOCKET_ID_ANY);
 
@@ -5938,16 +5962,16 @@ flow_dv_mtr_container_resize(struct rte_eth_dev *dev)
 		rte_errno = ENOMEM;
 		return -ENOMEM;
 	}
-	if (!mtrmng->n)
+	if (!pools_mng->n)
 		if (mlx5_aso_queue_init(priv->sh, ASO_OPC_MOD_POLICER)) {
 			mlx5_free(pools);
 			return -ENOMEM;
 		}
 	if (old_pools)
-		memcpy(pools, old_pools, mtrmng->n *
+		memcpy(pools, old_pools, pools_mng->n *
 				       sizeof(struct mlx5_aso_mtr_pool *));
-	mtrmng->n = resize;
-	mtrmng->pools = pools;
+	pools_mng->n = resize;
+	pools_mng->pools = pools;
 	if (old_pools)
 		mlx5_free(old_pools);
 	return 0;
@@ -5970,7 +5994,8 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 			     struct mlx5_aso_mtr **mtr_free)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool = NULL;
 	struct mlx5_devx_obj *dcs = NULL;
 	uint32_t i;
@@ -5990,17 +6015,17 @@ flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 		return NULL;
 	}
 	pool->devx_obj = dcs;
-	pool->index = mtrmng->n_valid;
-	if (pool->index == mtrmng->n && flow_dv_mtr_container_resize(dev)) {
+	pool->index = pools_mng->n_valid;
+	if (pool->index == pools_mng->n && flow_dv_mtr_container_resize(dev)) {
 		mlx5_free(pool);
 		claim_zero(mlx5_devx_cmd_destroy(dcs));
 		return NULL;
 	}
-	mtrmng->pools[pool->index] = pool;
-	mtrmng->n_valid++;
+	pools_mng->pools[pool->index] = pool;
+	pools_mng->n_valid++;
 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
 		pool->mtrs[i].offset = i;
-		LIST_INSERT_HEAD(&mtrmng->meters,
+		LIST_INSERT_HEAD(&pools_mng->meters,
 						&pool->mtrs[i], next);
 	}
 	pool->mtrs[0].offset = 0;
@@ -6020,15 +6045,16 @@ static void
 flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr *aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
 
 	MLX5_ASSERT(aso_mtr);
-	rte_spinlock_lock(&mtrmng->mtrsl);
+	rte_spinlock_lock(&pools_mng->mtrsl);
 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
 	aso_mtr->state = ASO_METER_FREE;
-	LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	LIST_INSERT_HEAD(&pools_mng->meters, aso_mtr, next);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 }
 
 /**
@@ -6045,7 +6071,8 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_aso_mtr *mtr_free = NULL;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_aso_mtr_pool *pool;
 	uint32_t mtr_idx = 0;
 
@@ -6055,16 +6082,16 @@ flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 	}
 	/* Allocate the flow meter memory. */
 	/* Get free meters from management. */
-	rte_spinlock_lock(&mtrmng->mtrsl);
-	mtr_free = LIST_FIRST(&mtrmng->meters);
+	rte_spinlock_lock(&pools_mng->mtrsl);
+	mtr_free = LIST_FIRST(&pools_mng->meters);
 	if (mtr_free)
 		LIST_REMOVE(mtr_free, next);
 	if (!mtr_free && !flow_dv_mtr_pool_create(dev, &mtr_free)) {
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
 		return 0;
 	}
 	mtr_free->state = ASO_METER_WAIT;
-	rte_spinlock_unlock(&mtrmng->mtrsl);
+	rte_spinlock_unlock(&pools_mng->mtrsl);
 	pool = container_of(mtr_free,
 			struct mlx5_aso_mtr_pool,
 			mtrs[mtr_free->offset]);
@@ -13390,6 +13417,556 @@ flow_dv_action_query(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Destroy the meter sub policy table rules.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *   Pointer to meter sub policy table.
+ */
+static void
+__flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_sub_policy *sub_policy)
+{
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (sub_policy->color_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(sub_policy->color_rule[i]));
+			sub_policy->color_rule[i] = NULL;
+		}
+		if (sub_policy->color_matcher[i]) {
+			tbl = container_of(sub_policy->color_matcher[i]->tbl,
+				typeof(*tbl), tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &sub_policy->color_matcher[i]->entry);
+			sub_policy->color_matcher[i] = NULL;
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (sub_policy->rix_hrxq[i]) {
+			mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+			sub_policy->rix_hrxq[i] = 0;
+		}
+		if (sub_policy->jump_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->jump_tbl[i]);
+			sub_policy->jump_tbl[i] = NULL;
+		}
+	}
+	if (sub_policy->tbl_rsc) {
+		flow_dv_tbl_resource_release(MLX5_SH(dev),
+			sub_policy->tbl_rsc);
+		sub_policy->tbl_rsc = NULL;
+	}
+}
+
+/**
+ * Destroy policy rules, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	uint32_t i, j;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		for (j = 0; j < sub_policy_num; j++) {
+			sub_policy = mtr_policy->sub_policys[i][j];
+			if (sub_policy)
+				__flow_dv_destroy_sub_policy_rules
+						(dev, sub_policy);
+		}
+	}
+}
+
+/**
+ * Destroy policy action, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ */
+static void
+flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy)
+{
+	struct rte_flow_action *rss_action;
+	struct mlx5_flow_handle dev_handle;
+	uint32_t i, j;
+
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			flow_dv_tag_release(dev,
+				mtr_policy->act_cnt[i].rix_mark);
+			mtr_policy->act_cnt[i].rix_mark = 0;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			dev_handle.dvh.modify_hdr =
+				mtr_policy->act_cnt[i].modify_hdr;
+			flow_dv_modify_hdr_resource_release(dev, &dev_handle);
+		}
+		switch (mtr_policy->act_cnt[i].fate_action) {
+		case MLX5_FLOW_FATE_SHARED_RSS:
+			rss_action = mtr_policy->act_cnt[i].rss;
+			mlx5_free(rss_action);
+			break;
+		case MLX5_FLOW_FATE_PORT_ID:
+			if (mtr_policy->act_cnt[i].rix_port_id_action) {
+				flow_dv_port_id_action_resource_release(dev,
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				mtr_policy->act_cnt[i].rix_port_id_action = 0;
+			}
+			break;
+		case MLX5_FLOW_FATE_DROP:
+		case MLX5_FLOW_FATE_JUMP:
+			for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+				mtr_policy->act_cnt[i].dr_jump_action[j] =
+						NULL;
+			break;
+		default:
+			/*Queue action do nothing*/
+			break;
+		}
+	}
+	for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+		mtr_policy->dr_drop_action[j] = NULL;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+__flow_dv_create_domain_policy_acts(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			enum mlx5_meter_domain domain,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_error flow_err;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	struct mlx5_flow_handle dh;
+	struct mlx5_flow dev_flow;
+	struct mlx5_flow_dv_port_id_action_resource port_id_action;
+	int i, ret;
+	uint8_t egress, transfer;
+	struct mlx5_meter_policy_action_container *act_cnt = NULL;
+	union {
+		struct mlx5_flow_dv_modify_hdr_resource res;
+		uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
+			    sizeof(struct mlx5_modification_cmd) *
+			    (MLX5_MAX_MODIFY_NUM + 1)];
+	} mhdr_dummy;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+	memset(&dev_flow, 0, sizeof(struct mlx5_flow));
+	memset(&port_id_action, 0,
+		sizeof(struct mlx5_flow_dv_port_id_action_resource));
+	dev_flow.handle = &dh;
+	dev_flow.dv.port_id_action = &port_id_action;
+	dev_flow.external = true;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i < MLX5_MTR_RTE_COLORS)
+			act_cnt = &mtr_policy->act_cnt[i];
+		for (act = actions[i];
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_MARK:
+			{
+				uint32_t tag_be = mlx5_flow_mark_set
+					(((const struct rte_flow_action_mark *)
+					(act->conf))->id);
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "mark action for this color");
+				dev_flow.handle->mark = 1;
+				if (flow_dv_tag_resource_register(dev, tag_be,
+						  &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot setup policy mark action");
+				MLX5_ASSERT(dev_flow.dv.tag_resource);
+				act_cnt->rix_mark =
+					dev_flow.handle->dvh.rix_tag;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+			mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+			{
+				struct mlx5_flow_dv_modify_hdr_resource
+					*mhdr_res = &mhdr_dummy.res;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "set tag action for this color");
+				memset(mhdr_res, 0, sizeof(*mhdr_res));
+				mhdr_res->ft_type = transfer ?
+					MLX5DV_FLOW_TABLE_TYPE_FDB :
+					egress ?
+					MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+					MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+				if (flow_dv_convert_action_set_tag
+				(dev, mhdr_res,
+				(const struct rte_flow_action_set_tag *)
+				act->conf,  &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot convert policy "
+					"set tag action");
+				if (!mhdr_res->actions_num)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot find policy "
+					"set tag action");
+				/* create modify action if needed. */
+				dev_flow.dv.group = 1;
+				if (flow_dv_modify_hdr_resource_register
+					(dev, mhdr_res, &dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot register policy "
+					"set tag action");
+				act_cnt->modify_hdr =
+				dev_flow.handle->dvh.modify_hdr;
+				if (action_flags & MLX5_FLOW_ACTION_QUEUE) {
+					dev_flow.handle->rix_hrxq =
+				mtr_policy->sub_policys[domain][0]->rix_hrxq[i];
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_DROP:
+			{
+				struct mlx5_flow_mtr_mng *mtrmng =
+						priv->sh->mtrmng;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+
+				/*
+				 * Create the drop table with
+				 * METER DROP level.
+				 */
+				if (!mtrmng->drop_tbl[domain]) {
+					mtrmng->drop_tbl[domain] =
+					flow_dv_tbl_resource_get(dev,
+					MLX5_FLOW_TABLE_LEVEL_METER,
+					egress, transfer, false, NULL, 0,
+					0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
+					if (!mtrmng->drop_tbl[domain])
+						return -rte_mtr_error_set
+					(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Failed to create meter drop table");
+				}
+				tbl_data = container_of
+				(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				if (i < MLX5_MTR_RTE_COLORS) {
+					act_cnt->dr_jump_action[domain] =
+						tbl_data->jump.action;
+					act_cnt->fate_action =
+						MLX5_FLOW_FATE_DROP;
+				}
+				if (i == RTE_COLOR_RED)
+					mtr_policy->dr_drop_action[domain] =
+						tbl_data->jump.action;
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+			{
+				struct mlx5_hrxq *hrxq;
+				uint32_t hrxq_idx;
+				struct mlx5_flow_rss_desc rss_desc;
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"fate queue for this color");
+				memset(&rss_desc, 0,
+					sizeof(struct mlx5_flow_rss_desc));
+				rss_desc.queue_num = 1;
+				rss_desc.const_q = act->conf;
+				hrxq = flow_dv_hrxq_prepare(dev, &dev_flow,
+						    &rss_desc, &hrxq_idx);
+				if (!hrxq)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"cannot create policy fate queue");
+				sub_policy->rix_hrxq[i] = hrxq_idx;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				dev_flow.handle->fate_action =
+					MLX5_FLOW_FATE_QUEUE;
+				if (action_flags & MLX5_FLOW_ACTION_MARK ||
+				    action_flags & MLX5_FLOW_ACTION_SET_TAG) {
+					dev_flow.handle->rix_hrxq = hrxq_idx;
+					flow_drv_rxq_flags_set(dev,
+						dev_flow.handle);
+				}
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_RSS:
+			{
+				int rss_size;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "rss action for this color");
+				/*
+				 * Save RSS conf into policy struct
+				 * for translate stage.
+				 */
+				rss_size = (int)rte_flow_conv
+					(RTE_FLOW_CONV_OP_ACTION,
+					NULL, 0, act, &flow_err);
+				if (rss_size <= 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Get the wrong "
+					  "rss action struct size");
+				act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
+						rss_size, 0, SOCKET_ID_ANY);
+				if (!act_cnt->rss)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "Fail to malloc rss action memory");
+				ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
+					act_cnt->rss, rss_size,
+					act, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Fail to save "
+					  "rss action into policy struct");
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_SHARED_RSS;
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+			{
+				struct mlx5_flow_dv_port_id_action_resource
+					port_id_resource;
+				uint32_t port_id = 0;
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create policy "
+					"port action for this color");
+				memset(&port_id_resource, 0,
+					sizeof(port_id_resource));
+				if (flow_dv_translate_action_port_id(dev, act,
+						&port_id, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot translate "
+					"policy port action");
+				port_id_resource.port_id = port_id;
+				if (flow_dv_port_id_action_resource_register
+					(dev, &port_id_resource,
+					&dev_flow, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy port action");
+				act_cnt->rix_port_id_action =
+					dev_flow.handle->rix_port_id_action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_PORT_ID;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			}
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+			{
+				uint32_t jump_group = 0;
+				uint32_t table = 0;
+				struct mlx5_flow_tbl_data_entry *tbl_data;
+				struct flow_grp_info grp_info = {
+					.external = !!dev_flow.external,
+					.transfer = !!transfer,
+					.fdb_def_rule = !!priv->fdb_def_rule,
+					.std_tbl_fix = 0,
+					.skip_scale = dev_flow.skip_scale &
+					(1 << MLX5_SCALE_FLOW_GROUP_BIT),
+				};
+				struct mlx5_flow_meter_sub_policy *sub_policy =
+				mtr_policy->sub_policys[domain][0];
+
+				if (i >= MLX5_MTR_RTE_COLORS)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL,
+					  "cannot create policy "
+					  "jump action for this color");
+				jump_group =
+				((const struct rte_flow_action_jump *)
+							act->conf)->group;
+				if (mlx5_flow_group_to_table(dev, NULL,
+						       jump_group,
+						       &table,
+						       &grp_info, &flow_err))
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot setup "
+					"policy jump action");
+				sub_policy->jump_tbl[i] =
+				flow_dv_tbl_resource_get(dev,
+					table, egress,
+					transfer,
+					!!dev_flow.external,
+					NULL, jump_group, 0,
+					0, &flow_err);
+				if
+				(!sub_policy->jump_tbl[i])
+					return  -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "cannot create jump action.");
+				tbl_data = container_of
+				(sub_policy->jump_tbl[i],
+				struct mlx5_flow_tbl_data_entry, tbl);
+				act_cnt->dr_jump_action[domain] =
+					tbl_data->jump.action;
+				act_cnt->fate_action =
+					MLX5_FLOW_FATE_JUMP;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			}
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "action type not supported");
+			}
+		}
+	}
+	return 0;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ *   Meter policy struct.
+ * @param[in] action
+ *   Action specification used to create meter actions.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
+		      struct mlx5_flow_meter_policy *mtr_policy,
+		      const struct rte_flow_action *actions[RTE_COLORS],
+		      struct rte_mtr_error *error)
+{
+	int ret, i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (sub_policy_num) {
+			ret = __flow_dv_create_domain_policy_acts(dev,
+				mtr_policy, actions,
+				(enum mlx5_meter_domain)i, error);
+			if (ret)
+				return ret;
+		}
+	}
+	return 0;
+}
+
 /**
  * Query a dv flow  rule for its statistics via devx.
  *
@@ -13570,9 +14147,484 @@ flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
 	return 0;
 }
 
+static void
+flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_tbl_data_entry *tbl;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (mtrmng->def_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+					(mtrmng->def_rule[i]));
+			mtrmng->def_rule[i] = NULL;
+		}
+		if (mtrmng->def_matcher[i]) {
+			tbl = container_of(mtrmng->def_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->def_matcher[i]->entry);
+			mtrmng->def_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_matcher[i]) {
+			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+			mlx5_cache_unregister(&tbl->matchers,
+				      &mtrmng->drop_matcher[i]->entry);
+			mtrmng->drop_matcher[i] = NULL;
+		}
+		if (mtrmng->drop_tbl[i]) {
+			flow_dv_tbl_resource_release(MLX5_SH(dev),
+				mtrmng->drop_tbl[i]);
+			mtrmng->drop_tbl[i] = NULL;
+		}
+	}
+}
+
 /* Number of meter flow actions, count and jump or count and drop. */
 #define METER_ACTIONS 2
 
+static void
+__flow_dv_destroy_domain_def_policy(struct rte_eth_dev *dev,
+			      enum mlx5_meter_domain domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_def_policy *def_policy =
+			priv->sh->mtrmng->def_policy[domain];
+
+	__flow_dv_destroy_sub_policy_rules(dev, &def_policy->sub_policy);
+	mlx5_free(def_policy);
+	priv->sh->mtrmng->def_policy[domain] = NULL;
+}
+
+/**
+ * Destroy the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ */
+static void
+flow_dv_destroy_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++)
+		if (priv->sh->mtrmng->def_policy[i])
+			__flow_dv_destroy_domain_def_policy(dev,
+					(enum mlx5_meter_domain)i);
+	priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
+}
+
+static int
+__flow_dv_create_policy_flow(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			enum rte_color color, void *matcher_object,
+			int actions_n, void *actions,
+			bool is_default_policy, void **rule,
+			const struct rte_flow_attr *attr)
+{
+	int ret;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher = {
+		.size = sizeof(matcher.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to create meter policy flow with port.");
+			return -1;
+		}
+	}
+	flow_dv_match_meta_reg(matcher.buf, value.buf,
+				(enum modify_reg)color_reg_c_idx,
+				rte_col_2_mlx5_col(color),
+				UINT32_MAX);
+	ret = mlx5_flow_os_create_flow(matcher_object,
+			(void *)&value, actions_n, actions, rule);
+	if (ret) {
+		DRV_LOG(ERR, "Failed to create meter policy flow.");
+		return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_matcher(struct rte_eth_dev *dev,
+			uint32_t color_reg_c_idx,
+			uint16_t priority,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			const struct rte_flow_attr *attr,
+			bool is_default_policy,
+			struct rte_flow_error *error)
+{
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_tbl_resource *tbl_rsc = sub_policy->tbl_rsc;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+				MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+		.tbl = tbl_rsc,
+	};
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = error,
+		.data = &matcher,
+	};
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	struct mlx5_priv *priv = dev->data->dev_private;
+	uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
+
+	if (!is_default_policy && (priv->representor || priv->master)) {
+		if (flow_dv_translate_item_port_id(dev, matcher.mask.buf,
+						   value.buf, NULL, attr)) {
+			DRV_LOG(ERR,
+			"Failed to register meter drop matcher with port.");
+			return -1;
+		}
+	}
+	tbl_data = container_of(tbl_rsc, struct mlx5_flow_tbl_data_entry, tbl);
+	if (priority < RTE_COLOR_RED)
+		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+			(enum modify_reg)color_reg_c_idx, 0, color_mask);
+	matcher.priority = priority;
+	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
+					matcher.mask.size);
+	entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+	if (!entry) {
+		DRV_LOG(ERR, "Failed to register meter drop matcher.");
+		return -1;
+	}
+	sub_policy->color_matcher[priority] =
+		container_of(entry, struct mlx5_flow_dv_matcher, entry);
+	return 0;
+}
+
+/**
+ * Create the policy rules per domain.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] sub_policy
+ *    Pointer to sub policy table..
+ * @param[in] egress
+ *   Direction of the table.
+ * @param[in] transfer
+ *   E-Switch or NIC flow.
+ * @param[in] acts
+ *   Pointer to policy action list per color.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+__flow_dv_create_domain_policy_rules(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_sub_policy *sub_policy,
+		uint8_t egress, uint8_t transfer, bool is_default_policy,
+		struct mlx5_meter_policy_acts acts[RTE_COLORS])
+{
+	struct rte_flow_error flow_err;
+	uint32_t color_reg_c_idx;
+	struct rte_flow_attr attr = {
+		.group = MLX5_FLOW_TABLE_LEVEL_POLICY,
+		.priority = 0,
+		.ingress = 0,
+		.egress = !!egress,
+		.transfer = !!transfer,
+		.reserved = 0,
+	};
+	int i;
+	int ret = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR, 0, &flow_err);
+
+	if (ret < 0)
+		return -1;
+	/* Create policy table with POLICY level. */
+	if (!sub_policy->tbl_rsc)
+		sub_policy->tbl_rsc = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_POLICY,
+				egress, transfer, false, NULL, 0, 0,
+				sub_policy->idx, &flow_err);
+	if (!sub_policy->tbl_rsc) {
+		DRV_LOG(ERR,
+			"Failed to create meter sub policy table.");
+		return -1;
+	}
+	/* Prepare matchers. */
+	color_reg_c_idx = ret;
+	for (i = 0; i < RTE_COLORS; i++) {
+		if (i == RTE_COLOR_YELLOW || !acts[i].actions_n)
+			continue;
+		attr.priority = i;
+		if (!sub_policy->color_matcher[i]) {
+			/* Create matchers for Color. */
+			if (__flow_dv_create_policy_matcher(dev,
+				color_reg_c_idx, i, sub_policy,
+				&attr, is_default_policy, &flow_err))
+				return -1;
+		}
+		/* Create flow, matching color. */
+		if (acts[i].actions_n)
+			if (__flow_dv_create_policy_flow(dev,
+				color_reg_c_idx, (enum rte_color)i,
+				sub_policy->color_matcher[i]->matcher_object,
+				acts[i].actions_n,
+				acts[i].dv_actions,
+				is_default_policy,
+				&sub_policy->color_rule[i],
+				&attr))
+				return -1;
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_policy_acts_rules(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct mlx5_flow_meter_sub_policy *sub_policy,
+			uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	struct mlx5_flow_dv_tag_resource *tag;
+	struct mlx5_flow_dv_port_id_action_resource *port_action;
+	struct mlx5_hrxq *hrxq;
+	uint8_t egress, transfer;
+	int i;
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		acts[i].actions_n = 0;
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (i == RTE_COLOR_RED) {
+			/* Only support drop on red. */
+			acts[i].dv_actions[0] =
+			mtr_policy->dr_drop_action[domain];
+			acts[i].actions_n = 1;
+			continue;
+		}
+		if (mtr_policy->act_cnt[i].rix_mark) {
+			tag = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_TAG],
+					mtr_policy->act_cnt[i].rix_mark);
+			if (!tag) {
+				DRV_LOG(ERR, "Failed to find "
+				"mark action for policy.");
+				return -1;
+			}
+			acts[i].dv_actions[acts[i].actions_n] =
+						tag->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].modify_hdr) {
+			acts[i].dv_actions[acts[i].actions_n] =
+			mtr_policy->act_cnt[i].modify_hdr->action;
+			acts[i].actions_n++;
+		}
+		if (mtr_policy->act_cnt[i].fate_action) {
+			switch (mtr_policy->act_cnt[i].fate_action) {
+			case MLX5_FLOW_FATE_PORT_ID:
+				port_action = mlx5_ipool_get
+					(priv->sh->ipool[MLX5_IPOOL_PORT_ID],
+				mtr_policy->act_cnt[i].rix_port_id_action);
+				if (!port_action) {
+					DRV_LOG(ERR, "Failed to find "
+						"port action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				port_action->action;
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_DROP:
+			case MLX5_FLOW_FATE_JUMP:
+				acts[i].dv_actions[acts[i].actions_n] =
+				mtr_policy->act_cnt[i].dr_jump_action[domain];
+				acts[i].actions_n++;
+				break;
+			case MLX5_FLOW_FATE_SHARED_RSS:
+			case MLX5_FLOW_FATE_QUEUE:
+				hrxq = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+				sub_policy->rix_hrxq[i]);
+				if (!hrxq) {
+					DRV_LOG(ERR, "Failed to find "
+						"queue action for policy.");
+					return -1;
+				}
+				acts[i].dv_actions[acts[i].actions_n] =
+				hrxq->action;
+				acts[i].actions_n++;
+				break;
+			default:
+				/*Queue action do nothing*/
+				break;
+			}
+		}
+	}
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	if (__flow_dv_create_domain_policy_rules(dev, sub_policy,
+				egress, transfer, false, acts)) {
+		DRV_LOG(ERR,
+		"Failed to create policy rules per domain.");
+		return -1;
+	}
+	return 0;
+}
+
+/**
+ * Create the policy rules.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in,out] mtr_policy
+ *   Pointer to meter policy table.
+ *
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_policy_rules(struct rte_eth_dev *dev,
+			     struct mlx5_flow_meter_policy *mtr_policy)
+{
+	int i;
+	uint16_t sub_policy_num;
+
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (!sub_policy_num)
+			continue;
+		/* Prepare actions list and create policy rules. */
+		if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+			mtr_policy->sub_policys[i][0], i)) {
+			DRV_LOG(ERR,
+			"Failed to create policy action list per domain.");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+__flow_dv_create_domain_def_policy(struct rte_eth_dev *dev, uint32_t domain)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_flow_meter_def_policy *def_policy;
+	struct mlx5_flow_tbl_resource *jump_tbl;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	struct rte_flow_error error;
+	struct mlx5_meter_policy_acts acts[RTE_COLORS];
+	int ret;
+
+	egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+	transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+	def_policy = mtrmng->def_policy[domain];
+	if (!def_policy) {
+		def_policy = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(struct mlx5_flow_meter_def_policy),
+			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+		if (!def_policy) {
+			DRV_LOG(ERR, "Failed to alloc "
+					"default policy table.");
+			goto def_policy_error;
+		}
+		mtrmng->def_policy[domain] = def_policy;
+		/* Create the meter suffix table with SUFFIX level. */
+		jump_tbl = flow_dv_tbl_resource_get(dev,
+				MLX5_FLOW_TABLE_LEVEL_METER,
+				egress, transfer, false, NULL, 0,
+				0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
+		if (!jump_tbl) {
+			DRV_LOG(ERR,
+				"Failed to create meter suffix table.");
+			goto def_policy_error;
+		}
+		def_policy->sub_policy.jump_tbl[RTE_COLOR_GREEN] = jump_tbl;
+		tbl_data = container_of(jump_tbl,
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_GREEN] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].dv_actions[0] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_GREEN].actions_n = 1;
+		/* Create jump action to the drop table. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get
+				(dev, MLX5_FLOW_TABLE_LEVEL_METER,
+				egress, transfer, false, NULL, 0,
+				0, MLX5_MTR_TABLE_ID_DROP, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create "
+				"meter drop table for default policy.");
+				goto def_policy_error;
+			}
+		}
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		def_policy->dr_jump_action[RTE_COLOR_RED] =
+						tbl_data->jump.action;
+		acts[RTE_COLOR_RED].dv_actions[0] = tbl_data->jump.action;
+		acts[RTE_COLOR_RED].actions_n = 1;
+		/* Create default policy rules. */
+		ret = __flow_dv_create_domain_policy_rules(dev,
+					&def_policy->sub_policy,
+					egress, transfer, true, acts);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create "
+				"default policy rules.");
+				goto def_policy_error;
+		}
+	}
+	return 0;
+def_policy_error:
+	__flow_dv_destroy_domain_def_policy(dev,
+			(enum mlx5_meter_domain)domain);
+	return -1;
+}
+
+/**
+ * Create the default policy table set.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @return
+ *   0 on success, -1 otherwise.
+ */
+static int
+flow_dv_create_def_policy(struct rte_eth_dev *dev)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	int i;
+
+	/* Non-termination policy table. */
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!priv->config.dv_esw_en && i == MLX5_MTR_DOMAIN_TRANSFER)
+			continue;
+		if (__flow_dv_create_domain_def_policy(dev, i)) {
+			DRV_LOG(ERR,
+			"Failed to create default policy");
+			return -1;
+		}
+	}
+	return 0;
+}
+
 /**
  * Create specify domain meter table and suffix table.
  *
@@ -13602,19 +14654,11 @@ flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
 		dtb = &mtb->egress;
 	else
 		dtb = &mtb->ingress;
-	/* Create the meter table with METER level. */
-	dtb->tbl = flow_dv_tbl_resource_get(dev, MLX5_FLOW_TABLE_LEVEL_METER,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
-	if (!dtb->tbl) {
-		DRV_LOG(ERR, "Failed to create meter policer table.");
-		return -1;
-	}
 	/* Create the meter suffix table with SUFFIX level. */
 	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
-					    MLX5_FLOW_TABLE_LEVEL_SUFFIX,
-					    egress, transfer, false, NULL, 0,
-					    0, 0, &error);
+					MLX5_FLOW_TABLE_LEVEL_METER,
+					egress, transfer, false, NULL, 0,
+					0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
 	if (!dtb->sfx_tbl) {
 		DRV_LOG(ERR, "Failed to create meter suffix table.");
 		return -1;
@@ -13933,6 +14977,292 @@ flow_dv_action_validate(struct rte_eth_dev *dev,
 	}
 }
 
+/**
+ * Validate meter policy actions.
+ * Dispatcher for action type specific validation.
+ *
+ * @param[in] dev
+ *   Pointer to the Ethernet device structure.
+ * @param[in] action
+ *   The meter policy action object to validate.
+ * @param[in] attr
+ *   Attributes of flow to determine steering domain.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL. Initialized in case of
+ *   error only.
+ *
+ * @return
+ *   0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_validate_mtr_policy_acts(struct rte_eth_dev *dev,
+			const struct rte_flow_action *actions[RTE_COLORS],
+			struct rte_flow_attr *attr,
+			bool *is_rss,
+			uint8_t *domain_bitmap,
+			bool *is_def_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_dev_config *dev_conf = &priv->config;
+	const struct rte_flow_action *act;
+	uint64_t action_flags = 0;
+	int actions_n;
+	int i, ret;
+	struct rte_flow_error flow_err;
+	uint8_t domain_color[RTE_COLORS] = {0};
+	uint8_t def_domain = MLX5_MTR_ALL_DOMAIN_BIT;
+
+	if (!priv->config.dv_esw_en)
+		def_domain &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	*domain_bitmap = def_domain;
+	if (actions[RTE_COLOR_YELLOW] &&
+		actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_END)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"Yellow color does not support any action.");
+	if (actions[RTE_COLOR_YELLOW] &&
+		actions[RTE_COLOR_YELLOW]->type != RTE_FLOW_ACTION_TYPE_DROP)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Red color only supports drop action.");
+	/*
+	 * Check default policy actions:
+	 * Green/Yellow: no action, Red: drop action
+	 */
+	if ((!actions[RTE_COLOR_GREEN] ||
+		actions[RTE_COLOR_GREEN]->type == RTE_FLOW_ACTION_TYPE_END)) {
+		*is_def_policy = true;
+		return 0;
+	}
+	flow_err.message = NULL;
+	for (i = 0; i < RTE_COLORS; i++) {
+		act = actions[i];
+		for (action_flags = 0, actions_n = 0;
+			act && act->type != RTE_FLOW_ACTION_TYPE_END;
+			act++) {
+			if (actions_n == MLX5_DV_MAX_NUMBER_OF_ACTIONS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "too many actions");
+			switch (act->type) {
+			case RTE_FLOW_ACTION_TYPE_PORT_ID:
+				if (!priv->config.dv_esw_en)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "PORT action validate check"
+					" fail for ESW disable");
+				ret = flow_dv_validate_action_port_id(dev,
+						action_flags,
+						act, attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"PORT action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+				break;
+			case RTE_FLOW_ACTION_TYPE_MARK:
+				ret = flow_dv_validate_action_mark(dev, act,
+							   action_flags,
+							   attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Mark action validate check fail");
+				if (dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "Extend MARK action is "
+					"not supported. Please try use "
+					"default policy for meter.");
+				action_flags |= MLX5_FLOW_ACTION_MARK;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_SET_TAG:
+				ret = flow_dv_validate_action_set_tag(dev,
+							act, action_flags,
+							attr, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Set tag action validate check fail");
+				/*
+				 * Count all modify-header actions
+				 * as one action.
+				 */
+				if (!(action_flags &
+					MLX5_FLOW_MODIFY_HDR_ACTIONS))
+					++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+				break;
+			case RTE_FLOW_ACTION_TYPE_DROP:
+				ret = mlx5_flow_validate_action_drop
+					(action_flags,
+					attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, flow_err.message ?
+					flow_err.message :
+					"Drop action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_DROP;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_QUEUE:
+				/*
+				 * Check whether extensive
+				 * metadata feature is engaged.
+				 */
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "Queue action with meta "
+					  "is not supported. Please try use "
+					  "default policy for meter.");
+				ret = mlx5_flow_validate_action_queue(act,
+							action_flags, dev,
+							attr, &flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Queue action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_QUEUE;
+				++actions_n;
+				break;
+			case RTE_FLOW_ACTION_TYPE_RSS:
+				if (dev_conf->dv_flow_en &&
+					(dev_conf->dv_xmeta_en !=
+					MLX5_XMETA_MODE_LEGACY) &&
+					mlx5_flow_ext_mreg_supported(dev))
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "RSS action with meta "
+					  "is not supported. Please try use "
+					  "default policy for meter.");
+				ret = mlx5_validate_action_rss(dev, act,
+						&flow_err);
+				if (ret < 0)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "RSS action validate check fail");
+				action_flags |= MLX5_FLOW_ACTION_RSS;
+				++actions_n;
+				*is_rss = true;
+				break;
+			case RTE_FLOW_ACTION_TYPE_JUMP:
+				ret = flow_dv_validate_action_jump(dev,
+					NULL, act, action_flags,
+					attr, true, &flow_err);
+				if (ret)
+					return -rte_mtr_error_set(error,
+					  ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, flow_err.message ?
+					  flow_err.message :
+					  "Jump action validate check fail");
+				++actions_n;
+				action_flags |= MLX5_FLOW_ACTION_JUMP;
+				break;
+			default:
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL,
+					"Doesn't support optional action");
+			}
+		}
+		/* Yellow is not supported, just skip. */
+		if (i == RTE_COLOR_YELLOW)
+			continue;
+		if (action_flags & MLX5_FLOW_ACTION_PORT_ID)
+			domain_color[i] = MLX5_MTR_DOMAIN_TRANSFER_BIT;
+		else if ((action_flags &
+			(MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_QUEUE)) ||
+			(action_flags & MLX5_FLOW_ACTION_MARK))
+			/*
+			 * Only support MLX5_XMETA_MODE_LEGACY
+			 * so MARK action only in ingress domain.
+			 */
+			domain_color[i] = MLX5_MTR_DOMAIN_INGRESS_BIT;
+		else
+			domain_color[i] = def_domain;
+		/*
+		 * Validate the drop action mutual exclusion
+		 * with other actions. Drop action is mutually-exclusive
+		 * with any other action, except for Count action.
+		 */
+		if ((action_flags & MLX5_FLOW_ACTION_DROP) &&
+			(action_flags & ~MLX5_FLOW_ACTION_DROP)) {
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "Drop action is mutually-exclusive "
+				"with any other action");
+		}
+		/* Eswitch has few restrictions on using items and actions */
+		if (domain_color[i] & MLX5_MTR_DOMAIN_TRANSFER_BIT) {
+			if (!mlx5_flow_ext_mreg_supported(dev) &&
+				action_flags & MLX5_FLOW_ACTION_MARK)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action MARK");
+			if (action_flags & MLX5_FLOW_ACTION_QUEUE)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action QUEUE");
+			if (action_flags & MLX5_FLOW_ACTION_RSS)
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "unsupported action RSS");
+			if (!(action_flags & MLX5_FLOW_FATE_ESWITCH_ACTIONS))
+				return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+		} else {
+			if (!(action_flags & MLX5_FLOW_FATE_ACTIONS) &&
+				(domain_color[i] &
+				MLX5_MTR_DOMAIN_INGRESS_BIT)) {
+				if ((domain_color[i] &
+					MLX5_MTR_DOMAIN_EGRESS_BIT))
+					domain_color[i] =
+					MLX5_MTR_DOMAIN_EGRESS_BIT;
+				else
+					return -rte_mtr_error_set(error,
+					ENOTSUP,
+					RTE_MTR_ERROR_TYPE_METER_POLICY,
+					NULL, "no fate action is found");
+			}
+		}
+		if (domain_color[i] != def_domain)
+			*domain_bitmap = domain_color[i];
+	}
+	return 0;
+}
+
 static int
 flow_dv_sync_domain(struct rte_eth_dev *dev, uint32_t domains, uint32_t flags)
 {
@@ -13968,8 +15298,16 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.query = flow_dv_query,
 	.create_mtr_tbls = flow_dv_create_mtr_tbl,
 	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbl,
+	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
+	.validate_mtr_acts = flow_dv_validate_mtr_policy_acts,
+	.create_mtr_acts = flow_dv_create_mtr_policy_acts,
+	.destroy_mtr_acts = flow_dv_destroy_mtr_policy_acts,
+	.create_policy_rules = flow_dv_create_policy_rules,
+	.destroy_policy_rules = flow_dv_destroy_policy_rules,
+	.create_def_policy = flow_dv_create_def_policy,
+	.destroy_def_policy = flow_dv_destroy_def_policy,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index af0a1c18cb..b38ff77210 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -38,6 +38,12 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	uint32_t cbs_cir = rte_be_to_cpu_32(srtcm->cbs_cir);
 	uint32_t ebs_eir = rte_be_to_cpu_32(srtcm->ebs_eir);
 	uint32_t val;
+	enum mlx5_meter_domain domain =
+		fm->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+			fm->egress ? MLX5_MTR_DOMAIN_EGRESS :
+				MLX5_MTR_DOMAIN_INGRESS;
+	struct mlx5_flow_meter_def_policy *def_policy =
+		priv->sh->mtrmng->def_policy[domain];
 
 	memset(fmp, 0, MLX5_ST_SZ_BYTES(flow_meter_parameters));
 	MLX5_SET(flow_meter_parameters, fmp, valid, 1);
@@ -57,10 +63,7 @@ mlx5_flow_meter_action_create(struct mlx5_priv *priv,
 	MLX5_SET(flow_meter_parameters, fmp, ebs_exponent, val);
 	val = (ebs_eir >> ASO_DSEG_EBS_MAN_OFFSET) & ASO_DSEG_MAN_MASK;
 	MLX5_SET(flow_meter_parameters, fmp, ebs_mantissa, val);
-	mtr_init.next_table =
-		fm->transfer ? fm->mfts->transfer.tbl->obj :
-			fm->egress ? fm->mfts->egress.tbl->obj :
-				fm->mfts->ingress.tbl->obj;
+	mtr_init.next_table = def_policy->sub_policy.tbl_rsc->obj;
 	mtr_init.reg_c_index = priv->mtr_color_reg - REG_C_0;
 	mtr_init.flow_meter_parameter = fmp;
 	mtr_init.flow_meter_parameter_sz =
@@ -317,7 +320,7 @@ mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
 					  "Meter is not supported");
 	memset(cap, 0, sizeof(*cap));
 	if (priv->sh->meter_aso_en)
-	    /* 2 meters per one ASO cache line. */
+		/* 2 meters per one ASO cache line. */
 		cap->n_max = 1 << (qattr->log_max_num_meter_aso + 1);
 	else
 		cap->n_max = 1 << qattr->log_max_flow_meter;
@@ -435,6 +438,347 @@ mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * Find policy by id.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param policy_id
+ *   Policy id.
+ *
+ * @return
+ *   Pointer to the policy found on success, NULL otherwise.
+ */
+struct mlx5_flow_meter_policy *
+mlx5_flow_meter_policy_find(struct rte_eth_dev *dev,
+			    uint32_t policy_id,
+			    uint32_t *policy_idx)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+	union mlx5_l3t_data data;
+
+	if (policy_id > MLX5_MAX_SUB_POLICY_TBL_NUM ||
+		!priv->sh->mtrmng->policy_idx_tbl)
+		return NULL;
+	if (mlx5_l3t_get_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data) ||
+				!data.dword)
+		return NULL;
+	if (policy_idx)
+		*policy_idx = data.dword;
+	sub_policy = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					data.dword);
+	/* Remove reference taken by the mlx5_l3t_get_entry. */
+	mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id);
+	if (sub_policy)
+		if (sub_policy->main_policy_id)
+			return sub_policy->main_policy;
+	return NULL;
+}
+
+/**
+ * Callback to check MTR policy action validate
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_validate(struct rte_eth_dev *dev,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint8_t domain_bitmap;
+	int ret;
+
+	if (!priv->mtr_en || !priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "meter policy unsupported.");
+	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	return 0;
+}
+
+static int
+__mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct mlx5_flow_meter_policy *mtr_policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	uint32_t i, j;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	if (mtr_policy->ref_cnt) {
+		rte_spinlock_unlock(&mtr_policy->sl);
+		return -rte_mtr_error_set(error, EBUSY,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				 NULL,
+				"Meter policy object is being used.");
+	}
+	mlx5_flow_destroy_policy_rules(dev, mtr_policy);
+	mlx5_flow_destroy_mtr_acts(dev, mtr_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		if (sub_policy_num) {
+			for (j = 0; j < sub_policy_num; j++) {
+				sub_policy = mtr_policy->sub_policys[i][j];
+				if (sub_policy)
+					mlx5_ipool_free
+					(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+			}
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl) {
+		if (mlx5_l3t_clear_entry(priv->sh->mtrmng->policy_idx_tbl,
+					policy_id)) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Fail to delete policy in index table.");
+		}
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return 0;
+}
+
+/**
+ * Callback to add MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[out] policy_id
+ *   Pointer to policy id
+ * @param[in] actions
+ *   Pointer to meter policy action 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_policy_add(struct rte_eth_dev *dev,
+			uint32_t policy_id,
+			struct rte_mtr_meter_policy_params *policy,
+			struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct rte_flow_attr attr = { .transfer =
+			priv->config.dv_esw_en ? 1 : 0};
+	uint32_t sub_policy_idx = 0;
+	uint32_t policy_idx = 0;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
+	bool is_rss = false;
+	bool is_def_policy = false;
+	uint32_t i;
+	int ret;
+	uint32_t policy_size = sizeof(struct mlx5_flow_meter_policy);
+	uint16_t sub_policy_num;
+	uint8_t domain_bitmap = 0;
+	union mlx5_l3t_data data;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_METER_POLICY,
+					  NULL, "meter policy unsupported.");
+	if (policy_id == MLX5_INVALID_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID is invalid. ");
+	if (policy_id == priv->sh->mtrmng->def_policy_id)
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID exists. ");
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id,
+				&policy_idx);
+	if (mtr_policy)
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"policy ID exists. ");
+	ret = mlx5_flow_validate_mtr_acts(dev, policy->actions, &attr,
+			&is_rss, &domain_bitmap, &is_def_policy, error);
+	if (ret)
+		return ret;
+	if (!domain_bitmap)
+		return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL, "fail to find policy domain.");
+	if (is_def_policy) {
+		if (priv->sh->mtrmng->def_policy_id != MLX5_INVALID_POLICY_ID)
+			return -rte_mtr_error_set(error, EEXIST,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "a policy with similar actions "
+				"is already configured");
+		if (mlx5_flow_create_def_policy(dev))
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"fail to create non-terminated policy.");
+		priv->sh->mtrmng->def_policy_id = policy_id;
+		return 0;
+	}
+	if (!priv->sh->meter_aso_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+			"no ASO capability to support the policy ");
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		if (is_rss) {
+			policy_size +=
+			sizeof(struct mlx5_flow_meter_sub_policy *) *
+			MLX5_MTR_RSS_MAX_SUB_POLICY;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy *);
+	}
+	mtr_policy = mlx5_malloc(MLX5_MEM_ZERO, policy_size,
+			 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_METER_POLICY, NULL,
+				"Memory alloc failed for meter policy.");
+	policy_size = sizeof(struct mlx5_flow_meter_policy);
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (!(domain_bitmap & (1 << i)))
+			continue;
+		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
+		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy)
+			goto policy_add_err;
+		if (sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto policy_add_err;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+		if (!policy_idx) {
+			policy_idx = sub_policy_idx;
+			sub_policy->main_policy_id = 1;
+		}
+		mtr_policy->sub_policys[i] =
+		(struct mlx5_flow_meter_sub_policy **)
+			((uint8_t *)mtr_policy + policy_size);
+		mtr_policy->sub_policys[i][0] = sub_policy;
+		sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		sub_policy_num++;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i));
+		mtr_policy->sub_policy_num |=
+			(sub_policy_num & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * i);
+		if (is_rss) {
+			mtr_policy->is_rss = 1;
+			break;
+		}
+		policy_size += sizeof(struct mlx5_flow_meter_sub_policy  *);
+	}
+	rte_spinlock_init(&mtr_policy->sl);
+	ret = mlx5_flow_create_mtr_acts(dev, mtr_policy,
+					policy->actions, error);
+	if (ret)
+		goto policy_add_err;
+	if (!is_rss) {
+		/* Create policy rules in HW. */
+		ret = mlx5_flow_create_policy_rules(dev, mtr_policy);
+		if (ret)
+			goto policy_add_err;
+	}
+	data.dword = policy_idx;
+	if (!priv->sh->mtrmng->policy_idx_tbl) {
+		priv->sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		if (!priv->sh->mtrmng->policy_idx_tbl)
+			goto policy_add_err;
+	}
+	if (mlx5_l3t_set_entry(priv->sh->mtrmng->policy_idx_tbl,
+				policy_id, &data))
+		goto policy_add_err;
+	return 0;
+policy_add_err:
+	if (mtr_policy) {
+		ret = __mlx5_flow_meter_policy_delete(dev, policy_id,
+			mtr_policy, error);
+		mlx5_free(mtr_policy);
+		if (ret)
+			return ret;
+	}
+	return -rte_mtr_error_set(error, ENOTSUP,
+				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+				  NULL, "Failed to create devx policy.");
+}
+
+/**
+ * Callback to delete MTR policy.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Meter policy 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_policy_delete(struct rte_eth_dev *dev,
+			  uint32_t policy_id,
+			  struct rte_mtr_error *error)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	uint32_t policy_idx;
+	int ret;
+
+	if (policy_id == priv->sh->mtrmng->def_policy_id) {
+		if (priv->sh->mtrmng->def_policy_ref_cnt > 0)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+				"Meter policy object is being used.");
+		priv->sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
+		return 0;
+	}
+	mtr_policy = mlx5_flow_meter_policy_find(dev, policy_id, &policy_idx);
+	if (!mtr_policy)
+		return -rte_mtr_error_set(error, ENOTSUP,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID, NULL,
+			"Meter policy id is invalid. ");
+	ret = __mlx5_flow_meter_policy_delete(dev, policy_id, mtr_policy,
+						error);
+	if (ret)
+		return ret;
+	mlx5_free(mtr_policy);
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -942,6 +1286,9 @@ 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,
+	.meter_policy_validate = mlx5_flow_meter_policy_validate,
+	.meter_policy_add = mlx5_flow_meter_policy_add,
+	.meter_policy_delete = mlx5_flow_meter_policy_delete,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -989,22 +1336,32 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_aso_mtr *aso_mtr;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	union mlx5_l3t_data data;
 
 	if (priv->sh->meter_aso_en) {
-		rte_spinlock_lock(&mtrmng->mtrsl);
-		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
-			!data.dword) {
-			rte_spinlock_unlock(&mtrmng->mtrsl);
-			return NULL;
+		rte_spinlock_lock(&pools_mng->mtrsl);
+		if (priv->mtr_idx_tbl) {
+			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
+				meter_id, &data) ||
+				!data.dword) {
+				rte_spinlock_unlock(&pools_mng->mtrsl);
+				return NULL;
+			}
+			if (mtr_idx)
+				*mtr_idx = data.dword;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+			/* Remove reference taken by the mlx5_l3t_get_entry. */
+			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
+		} else {
+			if (mtr_idx)
+				*mtr_idx = meter_id;
+			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
 		}
-		if (mtr_idx)
-			*mtr_idx = data.dword;
-		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-		/* Remove reference taken by the mlx5_l3t_get_entry. */
-		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		rte_spinlock_unlock(&mtrmng->mtrsl);
+		rte_spinlock_unlock(&pools_mng->mtrsl);
+		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
+			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
@@ -1169,30 +1526,31 @@ 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_aso_mtr_pools_mng *mtrmng = priv->sh->mtrmng;
+	struct mlx5_aso_mtr_pools_mng *pools_mng =
+				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
 	struct mlx5_aso_mtr_pool *mtr_pool;
+	struct mlx5_flow_meter_sub_policy *sub_policy;
 	void *tmp;
-	uint32_t i, offset, mtr_idx;
+	uint32_t i, offset, mtr_idx, policy_idx;
+	void *entry;
 
+	if (!priv->mtr_en)
+		return 0;
 	if (priv->sh->meter_aso_en) {
-		i = mtrmng->n_valid;
+		i = pools_mng->n_valid;
 		while (i--) {
-			mtr_pool = mtrmng->pools[i];
+			mtr_pool = pools_mng->pools[i];
 			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
 				offset++) {
 				fm = &mtr_pool->mtrs[offset].fm;
 				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				if (mlx5_flow_meter_params_flush(dev,
-						fm, mtr_idx))
-					return -rte_mtr_error_set
-					(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				(void)mlx5_flow_meter_params_flush(dev,
+						fm, mtr_idx);
 			}
 		}
 	} else {
@@ -1200,9 +1558,35 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 			fm = &legacy_fm->fm;
 			if (mlx5_flow_meter_params_flush(dev, fm, 0))
 				return -rte_mtr_error_set(error, EINVAL,
-					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+				RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
+				NULL, "MTR object meter profile invalid.");
+		}
+	}
+	if (priv->sh->mtrmng->policy_idx_tbl) {
+		MLX5_L3T_FOREACH(priv->sh->mtrmng->policy_idx_tbl,
+					i, entry) {
+			policy_idx = *(uint32_t *)entry;
+			sub_policy = mlx5_ipool_get
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				policy_idx);
+			if (!sub_policy)
+				return -rte_mtr_error_set(error,
+						EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+			if (__mlx5_flow_meter_policy_delete(dev, i,
+						sub_policy->main_policy,
+						error))
+				return -rte_mtr_error_set(error,
+						EINVAL,
+					RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+						NULL, "MTR object "
+						"meter policy invalid.");
+			mlx5_free(sub_policy->main_policy);
 		}
+		mlx5_l3t_destroy(priv->sh->mtrmng->policy_idx_tbl);
+		priv->sh->mtrmng->policy_idx_tbl = NULL;
 	}
 	TAILQ_FOREACH_SAFE(fmp, fmps, next, tmp) {
 		/* Check unused. */
@@ -1211,5 +1595,8 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 		TAILQ_REMOVE(&priv->flow_meter_profiles, fmp, next);
 		mlx5_free(fmp);
 	}
+	/* Delete default policy table. */
+	mlx5_flow_destroy_def_policy(dev);
+	mlx5_flow_destroy_mtr_drop_tbls(dev);
 	return 0;
 }
diff --git a/drivers/net/mlx5/mlx5_trigger.c b/drivers/net/mlx5/mlx5_trigger.c
index 94dd56709e..90d918849a 100644
--- a/drivers/net/mlx5/mlx5_trigger.c
+++ b/drivers/net/mlx5/mlx5_trigger.c
@@ -1179,6 +1179,7 @@ mlx5_dev_stop(struct rte_eth_dev *dev)
 	mlx5_traffic_disable(dev);
 	/* All RX queue flags will be cleared in the flush interface. */
 	mlx5_flow_list_flush(dev, &priv->flows, true);
+	mlx5_flow_meter_flush(dev, NULL);
 	mlx5_rx_intr_vec_disable(dev);
 	priv->sh->port[priv->dev_port - 1].ih_port_id = RTE_MAX_ETHPORTS;
 	priv->sh->port[priv->dev_port - 1].devx_ih_port_id = RTE_MAX_ETHPORTS;
-- 
2.27.0


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

* [dpdk-dev] [PATCH v5 2/4] net/mlx5: support meter creation with policy
  2021-04-15  5:05 ` [dpdk-dev] [PATCH v5 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 1/4] " Li Zhang
@ 2021-04-15  5:05   ` Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-15  5:05 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

Create a meter with the new pre-defined policy.

The following cases to be considered:
1.Add entry match with meter_id in global drop table.
2.For non-termination policy (policy id 0),
  add jump rule to suffix table for green and
  jump rule to drop table for red.
3.Allocate counter per meter in drop table.
4.Allocate meter resource per domain per color.
5.It can work with both ASO and legacy meter HW objects.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |  13 +-
 drivers/net/mlx5/mlx5.h            |  62 ++---
 drivers/net/mlx5/mlx5_flow.c       |  26 +-
 drivers/net/mlx5/mlx5_flow.h       |  32 +--
 drivers/net/mlx5/mlx5_flow_dv.c    | 367 ++++++++++++++++++++---------
 drivers/net/mlx5/mlx5_flow_meter.c | 367 ++++++++++++++++++++++++-----
 6 files changed, 623 insertions(+), 244 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index 276283d492..c1d4e2a0dc 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1297,13 +1297,14 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			if (log_obj_size >=
 			config->hca_attr.qos.log_meter_aso_granularity &&
 			log_obj_size <=
-			config->hca_attr.qos.log_meter_aso_max_alloc) {
+			config->hca_attr.qos.log_meter_aso_max_alloc)
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
-				if (err) {
-					err = -err;
-					goto error;
-				}
+		}
+		if (priv->mtr_en) {
+			err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
+			if (err) {
+				err = -err;
+				goto error;
 			}
 		}
 #endif
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index cb7c75aa2e..a8745df3e4 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -702,44 +702,12 @@ struct mlx5_flow_meter_def_policy {
 	/* Jump action per color. */
 };
 
-/* Meter table structure. */
-struct mlx5_meter_domain_info {
-	struct mlx5_flow_tbl_resource *tbl;
-	/**< Meter table. */
-	struct mlx5_flow_tbl_resource *sfx_tbl;
-	/**< Meter suffix table. */
-	struct mlx5_flow_dv_matcher *drop_matcher;
-	/**< Matcher for Drop. */
-	struct mlx5_flow_dv_matcher *color_matcher;
-	/**< Matcher for Color. */
-	void *jump_actn;
-	/**< Meter match action. */
-	void *green_rule;
-	/**< Meter green rule. */
-	void *drop_rule;
-	/**< Meter drop rule. */
-};
-
-/* 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. */
-	void *green_count;
-	/**< Counters for green rule. */
-	void *drop_count;
-	/**< Counters for green rule. */
-};
-
 /* Meter parameter structure. */
 struct mlx5_flow_meter_info {
+	uint32_t meter_id;
+	/**< Meter id. */
+	uint32_t policy_id;
+	/* Policy id, the first sub_policy idx. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
 	rte_spinlock_t sl; /**< Meter action spinlock. */
@@ -778,8 +746,10 @@ struct mlx5_flow_meter_info {
 	 * received by the application.
 	 */
 	uint32_t transfer:1;
-	struct mlx5_meter_domains_infos *mfts;
-	/**< Flow table created for this meter. */
+	uint32_t def_policy:1;
+	/* Meter points to default policy. */
+	void *drop_rule[MLX5_MTR_DOMAIN_MAX];
+	/* Meter drop rule in drop table. */
 	uint32_t drop_cnt;
 	/**< Color counter for drop. */
 	uint32_t ref_cnt;
@@ -790,6 +760,11 @@ struct mlx5_flow_meter_info {
 	/**< Flow meter action. */
 };
 
+/* PPS(packets per second) map to BPS(Bytes per second).
+ * HW treat packet as 128bytes in PPS mode
+ */
+#define MLX5_MTRS_PPS_MAP_BPS_SHIFT 7
+
 /* RFC2697 parameter structure. */
 struct mlx5_flow_meter_srtcm_rfc2697_prm {
 	rte_be32_t cbs_cir;
@@ -878,12 +853,17 @@ struct mlx5_flow_mtr_mng {
 	/* Policy index lookup table. */
 	struct mlx5_flow_tbl_resource *drop_tbl[MLX5_MTR_DOMAIN_MAX];
 	/* Meter drop table. */
-	struct mlx5_flow_dv_matcher *drop_matcher[MLX5_MTR_DOMAIN_MAX];
+	struct mlx5_flow_dv_matcher *
+			drop_matcher[MLX5_MTR_DOMAIN_MAX][MLX5_REG_BITS];
 	/* Matcher meter in drop table. */
 	struct mlx5_flow_dv_matcher *def_matcher[MLX5_MTR_DOMAIN_MAX];
 	/* Default matcher in drop table. */
 	void *def_rule[MLX5_MTR_DOMAIN_MAX];
 	/* Default rule in drop table. */
+	uint8_t max_mtr_bits;
+	/* Indicate how many bits are used by meter id at the most. */
+	uint8_t max_mtr_flow_bits;
+	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 /* Table key of the hash organization. */
@@ -1322,10 +1302,6 @@ struct mlx5_priv {
 	uint32_t rss_shared_actions; /* RSS shared actions. */
 	struct mlx5_devx_obj *q_counters; /* DevX queue counter object. */
 	uint32_t counter_set_id; /* Queue counter ID to set in DevX objects. */
-	uint8_t max_mtr_bits;
-	/* Indicate how many bits are used by meter id at the most. */
-	uint8_t max_mtr_flow_bits;
-	/* Indicate how many bits are used by meter flow id at the most. */
 };
 
 #define PORT_ID(priv) ((priv)->dev_data->port_id)
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 81e0e3b7a9..77590bbbed 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -4496,14 +4496,14 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	flow_id = tag_id - 1;
 	flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
 	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->max_mtr_bits) > mtr_reg_bits) {
+	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
 		mlx5_ipool_free(fm->flow_ipool, tag_id);
 		return rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
 				"Meter flow id exceeds max limit.");
 	}
-	if (flow_id_bits > priv->max_mtr_flow_bits)
-		priv->max_mtr_flow_bits = flow_id_bits;
+	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -6778,15 +6778,18 @@ mlx5_flow_create_def_policy(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  *
  * @return
- *   Pointer to table set on success, NULL otherwise.
+ *   0 on success, -1 otherwise.
  */
-struct mlx5_meter_domains_infos *
-mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
+int
+mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
 	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, mtr_idx, domain_bitmap);
 }
 
 /**
@@ -6796,18 +6799,15 @@ mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev)
  *   Pointer to Ethernet device.
  * @param[in] tbl
  *   Pointer to the meter table set.
- *
- * @return
- *   0 on success.
  */
-int
+void
 mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *tbls)
+			   struct mlx5_flow_meter_info *fm)
 {
 	const struct mlx5_flow_driver_ops *fops;
 
 	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->destroy_mtr_tbls(dev, tbls);
+	fops->destroy_mtr_tbls(dev, fm);
 }
 
 /**
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 51d040c4d2..89e43f2de6 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -222,16 +222,17 @@ enum mlx5_feature_name {
 #define MLX5_FLOW_ACTION_TUNNEL_SET (1ull << 37)
 #define MLX5_FLOW_ACTION_TUNNEL_MATCH (1ull << 38)
 #define MLX5_FLOW_ACTION_MODIFY_FIELD (1ull << 39)
+#define MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY (1ull << 40)
 
 #define MLX5_FLOW_FATE_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_QUEUE | \
 	 MLX5_FLOW_ACTION_RSS | MLX5_FLOW_ACTION_JUMP | \
-	 MLX5_FLOW_ACTION_DEFAULT_MISS)
+	 MLX5_FLOW_ACTION_DEFAULT_MISS | \
+	 MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_FATE_ESWITCH_ACTIONS \
 	(MLX5_FLOW_ACTION_DROP | MLX5_FLOW_ACTION_PORT_ID | \
-	 MLX5_FLOW_ACTION_JUMP)
-
+	 MLX5_FLOW_ACTION_JUMP | MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
 
 #define MLX5_FLOW_MODIFY_HDR_ACTIONS (MLX5_FLOW_ACTION_SET_IPV4_SRC | \
 				      MLX5_FLOW_ACTION_SET_IPV4_DST | \
@@ -832,9 +833,8 @@ struct mlx5_legacy_flow_meter {
 	/* Must be the first in struct. */
 	TAILQ_ENTRY(mlx5_legacy_flow_meter) next;
 	/**< Pointer to the next flow meter structure. */
-	uint32_t meter_id;
-	/**< Meter id. */
-	uint32_t idx; /* Index to meter object. */
+	uint32_t idx;
+	/* Index to meter object. */
 };
 
 #define MLX5_MAX_TUNNELS 256
@@ -1088,10 +1088,12 @@ 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);
+typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
+					struct mlx5_flow_meter_info *fm,
+					uint32_t mtr_idx,
+					uint8_t domain_bitmap);
+typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm);
 typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
@@ -1409,10 +1411,12 @@ int mlx5_flow_validate_item_ecpri(const struct rte_flow_item *item,
 				  uint16_t ether_type,
 				  const struct rte_flow_item_ecpri *acc_mask,
 				  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);
+int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
+				uint32_t mtr_idx,
+				uint8_t domain_bitmap);
+void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			       struct mlx5_flow_meter_info *fm);
 void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index 759731333d..f789f2454e 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -4859,11 +4859,14 @@ 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,
+				bool *def_policy,
 				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_info *fm;
+	struct mlx5_flow_meter_policy *mtr_policy;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 
 	if (!am)
 		return rte_flow_error_set(error, EINVAL,
@@ -4894,10 +4897,40 @@ mlx5_flow_validate_action_meter(struct rte_eth_dev *dev,
 	      (!fm->ingress && !attr->ingress && attr->egress) ||
 	      (!fm->egress && !attr->egress && attr->ingress)))
 		return rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+			"Flow attributes domain are either invalid "
+			"or have a domain conflict with current "
+			"meter attributes");
+	if (fm->def_policy) {
+		if (!((attr->transfer &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_TRANSFER]) ||
+			(attr->egress &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_EGRESS]) ||
+			(attr->ingress &&
+			mtrmng->def_policy[MLX5_MTR_DOMAIN_INGRESS])))
+			return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		*def_policy = true;
+	} else {
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+		if (!mtr_policy)
+			return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+					  "Invalid policy id for meter ");
+		if (!((attr->transfer && mtr_policy->transfer) ||
+			(attr->egress && mtr_policy->egress) ||
+			(attr->ingress && mtr_policy->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");
+					  "Flow attributes domain "
+					  "have a conflict with current "
+					  "meter domain attributes");
+		*def_policy = false;
+	}
 	return 0;
 }
 
@@ -6287,6 +6320,7 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 		.fdb_def_rule = !!priv->fdb_def_rule,
 	};
 	const struct rte_eth_hairpin_conf *conf;
+	bool def_policy = false;
 
 	if (items == NULL)
 		return -1;
@@ -6628,6 +6662,12 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			return rte_flow_error_set(error, ENOTSUP,
 						  RTE_FLOW_ERROR_TYPE_ACTION,
 						  actions, "too many actions");
+		if (action_flags &
+			MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)
+			return rte_flow_error_set(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "meter action with policy "
+				"must be the last action");
 		switch (type) {
 		case RTE_FLOW_ACTION_TYPE_VOID:
 			break;
@@ -7030,10 +7070,14 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 			ret = mlx5_flow_validate_action_meter(dev,
 							      action_flags,
 							      actions, attr,
+							      &def_policy,
 							      error);
 			if (ret < 0)
 				return ret;
 			action_flags |= MLX5_FLOW_ACTION_METER;
+			if (!def_policy)
+				action_flags |=
+				MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY;
 			++actions_n;
 			/* Meter action will add one more TAG action. */
 			rw_act_num += MLX5_ACT_NUM_SET_TAG;
@@ -7290,6 +7334,36 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 						 "multiple VLAN actions");
 		}
 	}
+	if (action_flags & MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY) {
+		if ((action_flags & (MLX5_FLOW_FATE_ACTIONS &
+			~MLX5_FLOW_ACTION_METER_WITH_TERMINATED_POLICY)) &&
+			attr->ingress)
+			return rte_flow_error_set
+				(error, ENOTSUP,
+				RTE_FLOW_ERROR_TYPE_ACTION,
+				NULL, "fate action not supported for "
+				"meter with policy");
+		if (attr->egress) {
+			if (action_flags & MLX5_FLOW_MODIFY_HDR_ACTIONS)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "modify header action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_ENCAP)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "encap action in egress "
+					"cannot be done before meter action");
+			if (action_flags & MLX5_FLOW_ACTION_OF_PUSH_VLAN)
+				return rte_flow_error_set
+					(error, ENOTSUP,
+					RTE_FLOW_ERROR_TYPE_ACTION,
+					NULL, "push vlan action in egress "
+					"cannot be done before meter action");
+		}
+	}
 	/*
 	 * Hairpin flow will add one more TAG action in TX implicit mode.
 	 * In TX explicit mode, there will be no hairpin flow ID.
@@ -14113,38 +14187,24 @@ flow_dv_query(struct rte_eth_dev *dev,
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
- * @param[in] tbl
- *   Pointer to the meter table set.
- *
- * @return
- *   Always 0.
+ * @param[in] fm
+ *   Meter information table.
  */
-static int
-flow_dv_destroy_mtr_tbl(struct rte_eth_dev *dev,
-			struct mlx5_meter_domains_infos *tbl)
+static void
+flow_dv_destroy_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_meter_domains_infos *mtd =
-				(struct mlx5_meter_domains_infos *)tbl;
+	int i;
 
-	if (!mtd || !priv->config.dv_flow_en)
-		return 0;
-	if (mtd->egress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.tbl);
-	if (mtd->egress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->egress.sfx_tbl);
-	if (mtd->ingress.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->ingress.tbl);
-	if (mtd->ingress.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->ingress.sfx_tbl);
-	if (mtd->transfer.tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev), mtd->transfer.tbl);
-	if (mtd->transfer.sfx_tbl)
-		flow_dv_tbl_resource_release(MLX5_SH(dev),
-					     mtd->transfer.sfx_tbl);
-	mlx5_free(mtd);
-	return 0;
+	if (!fm || !priv->config.dv_flow_en)
+		return;
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
+		}
+	}
 }
 
 static void
@@ -14153,7 +14213,7 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct mlx5_flow_tbl_data_entry *tbl;
-	int i;
+	int i, j;
 
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (mtrmng->def_rule[i]) {
@@ -14168,12 +14228,16 @@ flow_dv_destroy_mtr_drop_tbls(struct rte_eth_dev *dev)
 				      &mtrmng->def_matcher[i]->entry);
 			mtrmng->def_matcher[i] = NULL;
 		}
-		if (mtrmng->drop_matcher[i]) {
-			tbl = container_of(mtrmng->drop_matcher[i]->tbl,
-				struct mlx5_flow_tbl_data_entry, tbl);
-			mlx5_cache_unregister(&tbl->matchers,
-				      &mtrmng->drop_matcher[i]->entry);
-			mtrmng->drop_matcher[i] = NULL;
+		for (j = 0; j < MLX5_REG_BITS; j++) {
+			if (mtrmng->drop_matcher[i][j]) {
+				tbl =
+				container_of(mtrmng->drop_matcher[i][j]->tbl,
+					     struct mlx5_flow_tbl_data_entry,
+					     tbl);
+				mlx5_cache_unregister(&tbl->matchers,
+					&mtrmng->drop_matcher[i][j]->entry);
+				mtrmng->drop_matcher[i][j] = NULL;
+			}
 		}
 		if (mtrmng->drop_tbl[i]) {
 			flow_dv_tbl_resource_release(MLX5_SH(dev),
@@ -14626,96 +14690,171 @@ flow_dv_create_def_policy(struct rte_eth_dev *dev)
 }
 
 /**
- * Create specify domain meter table and suffix table.
+ * Create the needed meter tables.
+ * Lock free, (mutex should be acquired by caller).
  *
  * @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] fm
+ *   Meter information table.
+ * @param[in] mtr_idx
+ *   Meter index.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] domain_bitmap
+ *   Domain bitmap.
  * @return
  *   0 on success, -1 otherwise.
  */
 static int
-flow_dv_prepare_mtr_tables(struct rte_eth_dev *dev,
-			   struct mlx5_meter_domains_infos *mtb,
-			   uint8_t egress, uint8_t transfer)
+flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
+			struct mlx5_flow_meter_info *fm,
+			uint32_t mtr_idx,
+			uint8_t domain_bitmap)
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_mtr_mng *mtrmng = priv->sh->mtrmng;
 	struct rte_flow_error error;
-	struct mlx5_meter_domain_info *dtb;
+	struct mlx5_flow_tbl_data_entry *tbl_data;
+	uint8_t egress, transfer;
+	void *actions[METER_ACTIONS];
+	int domain, ret, i;
+	struct mlx5_flow_counter *cnt;
+	struct mlx5_flow_dv_match_params value = {
+		.size = sizeof(value.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	struct mlx5_flow_dv_match_params matcher_para = {
+		.size = sizeof(matcher_para.buf) -
+		MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+	};
+	int mtr_id_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_ID,
+						     0, &error);
+	uint32_t mtr_id_mask = (UINT32_C(1) << mtrmng->max_mtr_bits) - 1;
+	uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
+	struct mlx5_cache_entry *entry;
+	struct mlx5_flow_dv_matcher matcher = {
+		.mask = {
+			.size = sizeof(matcher.mask.buf) -
+			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
+		},
+	};
+	struct mlx5_flow_dv_matcher *drop_matcher;
+	struct mlx5_flow_cb_ctx ctx = {
+		.error = &error,
+		.data = &matcher,
+	};
 
-	if (transfer)
-		dtb = &mtb->transfer;
-	else if (egress)
-		dtb = &mtb->egress;
-	else
-		dtb = &mtb->ingress;
-	/* Create the meter suffix table with SUFFIX level. */
-	dtb->sfx_tbl = flow_dv_tbl_resource_get(dev,
+	if (!priv->mtr_en || mtr_id_reg_c < 0) {
+		rte_errno = ENOTSUP;
+		return -1;
+	}
+	for (domain = 0; domain < MLX5_MTR_DOMAIN_MAX; domain++) {
+		if (!(domain_bitmap & (1 << domain)) ||
+			(mtrmng->def_rule[domain] && !fm->drop_cnt))
+			continue;
+		egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+		transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		/* Create the drop table with METER DROP level. */
+		if (!mtrmng->drop_tbl[domain]) {
+			mtrmng->drop_tbl[domain] = flow_dv_tbl_resource_get(dev,
 					MLX5_FLOW_TABLE_LEVEL_METER,
 					egress, transfer, false, NULL, 0,
-					0, MLX5_MTR_TABLE_ID_SUFFIX, &error);
-	if (!dtb->sfx_tbl) {
-		DRV_LOG(ERR, "Failed to create meter suffix table.");
-		return -1;
+					0, MLX5_MTR_TABLE_ID_DROP, &error);
+			if (!mtrmng->drop_tbl[domain]) {
+				DRV_LOG(ERR, "Failed to create meter drop table.");
+				goto policy_error;
+			}
+		}
+		/* Create default matcher in drop table. */
+		matcher.tbl = mtrmng->drop_tbl[domain],
+		tbl_data = container_of(mtrmng->drop_tbl[domain],
+				struct mlx5_flow_tbl_data_entry, tbl);
+		if (!mtrmng->def_matcher[domain]) {
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+				       (enum modify_reg)mtr_id_reg_c,
+				       0, 0);
+			matcher.priority = MLX5_MTRS_DEFAULT_RULE_PRIORITY;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR, "Failed to register meter "
+				"drop default matcher.");
+				goto policy_error;
+			}
+			mtrmng->def_matcher[domain] = container_of(entry,
+			struct mlx5_flow_dv_matcher, entry);
+		}
+		/* Create default rule in drop table. */
+		if (!mtrmng->def_rule[domain]) {
+			i = 0;
+			actions[i++] = priv->sh->dr_drop_action;
+			flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c, 0, 0);
+			ret = mlx5_flow_os_create_flow
+				(mtrmng->def_matcher[domain]->matcher_object,
+				(void *)&value, i, actions,
+				&mtrmng->def_rule[domain]);
+			if (ret) {
+				DRV_LOG(ERR, "Failed to create meter "
+				"default drop rule for drop table.");
+				goto policy_error;
+			}
+		}
+		if (!fm->drop_cnt)
+			continue;
+		MLX5_ASSERT(mtrmng->max_mtr_bits);
+		if (!mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1]) {
+			/* Create matchers for Drop. */
+			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
+					(enum modify_reg)mtr_id_reg_c, 0,
+					(mtr_id_mask << mtr_id_offset));
+			matcher.priority = MLX5_REG_BITS - mtrmng->max_mtr_bits;
+			matcher.crc = rte_raw_cksum
+					((const void *)matcher.mask.buf,
+					matcher.mask.size);
+			entry = mlx5_cache_register(&tbl_data->matchers, &ctx);
+			if (!entry) {
+				DRV_LOG(ERR,
+				"Failed to register meter drop matcher.");
+				goto policy_error;
+			}
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1] =
+				container_of(entry, struct mlx5_flow_dv_matcher,
+					     entry);
+		}
+		drop_matcher =
+			mtrmng->drop_matcher[domain][mtrmng->max_mtr_bits - 1];
+		/* Create drop rule, matching meter_id only. */
+		flow_dv_match_meta_reg(matcher_para.buf, value.buf,
+				(enum modify_reg)mtr_id_reg_c,
+				(mtr_idx << mtr_id_offset), UINT32_MAX);
+		i = 0;
+		cnt = flow_dv_counter_get_by_idx(dev,
+					fm->drop_cnt, NULL);
+		actions[i++] = cnt->action;
+		actions[i++] = priv->sh->dr_drop_action;
+		ret = mlx5_flow_os_create_flow(drop_matcher->matcher_object,
+					       (void *)&value, i, actions,
+					       &fm->drop_rule[domain]);
+		if (ret) {
+			DRV_LOG(ERR, "Failed to create meter "
+				"drop rule for drop table.");
+				goto policy_error;
+		}
 	}
 	return 0;
-}
-
-/**
- * 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 = mlx5_malloc(MLX5_MEM_ZERO, sizeof(*mtb), 0, SOCKET_ID_ANY);
-	if (!mtb) {
-		DRV_LOG(ERR, "Failed to allocate memory for meter.");
-		return NULL;
-	}
-	/* Egress meter table. */
-	ret = flow_dv_prepare_mtr_tables(dev, mtb, 1, 0);
-	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);
-	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);
-		if (ret) {
-			DRV_LOG(ERR, "Failed to prepare fdb meter table.");
-			goto error_exit;
+policy_error:
+	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+		if (fm->drop_rule[i]) {
+			claim_zero(mlx5_flow_os_destroy_flow
+				(fm->drop_rule[i]));
+			fm->drop_rule[i] = NULL;
 		}
 	}
-	return mtb;
-error_exit:
-	flow_dv_destroy_mtr_tbl(dev, mtb);
-	return NULL;
+	return -1;
 }
 
 /**
@@ -15296,8 +15435,8 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.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,
+	.create_mtr_tbls = flow_dv_create_mtr_tbls,
+	.destroy_mtr_tbls = flow_dv_destroy_mtr_tbls,
 	.destroy_mtr_drop_tbls = flow_dv_destroy_mtr_drop_tbls,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index b38ff77210..e97a1d77a6 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -665,9 +665,12 @@ mlx5_flow_meter_policy_add(struct rte_eth_dev *dev,
 	for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
 		if (!(domain_bitmap & (1 << i)))
 			continue;
-		mtr_policy->ingress = (i == MLX5_MTR_DOMAIN_INGRESS) ? 1 : 0;
-		mtr_policy->egress = (i == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
-		mtr_policy->transfer = (i == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+		if (i == MLX5_MTR_DOMAIN_INGRESS)
+			mtr_policy->ingress = 1;
+		if (i == MLX5_MTR_DOMAIN_EGRESS)
+			mtr_policy->egress = 1;
+		if (i == MLX5_MTR_DOMAIN_TRANSFER)
+			mtr_policy->transfer = 1;
 		sub_policy = mlx5_ipool_zmalloc
 				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
 				&sub_policy_idx);
@@ -779,6 +782,56 @@ mlx5_flow_meter_policy_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+/**
+ * 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)
+{
+	/* Meter must use global drop action. */
+	if (!priv->sh->dr_drop_action)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					  RTE_MTR_ERROR_TYPE_MTR_PARAMS,
+					  NULL,
+					  "No drop action ready for meter.");
+	/* 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.");
+	if (params->meter_policy_id == MLX5_INVALID_POLICY_ID)
+		return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+	/* Validate meter id. */
+	if (mlx5_flow_meter_find(priv, meter_id, NULL))
+		return -rte_mtr_error_set(error, EEXIST,
+			RTE_MTR_ERROR_TYPE_MTR_ID, NULL,
+			"Meter object already exists.");
+	return 0;
+}
+
 /**
  * Modify the flow meter action.
  *
@@ -884,13 +937,195 @@ mlx5_flow_meter_action_modify(struct mlx5_priv *priv,
 #endif
 }
 
-static void
-mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
+static int
+mlx5_flow_meter_stats_enable_update(struct rte_eth_dev *dev,
+				struct mlx5_flow_meter_info *fm,
 				uint64_t stats_mask)
 {
 	fm->bytes_dropped =
 		(stats_mask & RTE_MTR_STATS_N_BYTES_DROPPED) ? 1 : 0;
 	fm->pkts_dropped = (stats_mask & RTE_MTR_STATS_N_PKTS_DROPPED) ? 1 : 0;
+	if (fm->bytes_dropped || fm->pkts_dropped) {
+		if (!fm->drop_cnt) {
+			/* Alloc policer counters. */
+			fm->drop_cnt = mlx5_counter_alloc(dev);
+			if (!fm->drop_cnt)
+				return -1;
+		}
+	} else {
+		if (fm->drop_cnt) {
+			mlx5_counter_free(dev, fm->drop_cnt);
+			fm->drop_cnt = 0;
+		}
+	}
+	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_legacy_flow_meters *fms = &priv->flow_meters;
+	struct mlx5_flow_meter_profile *fmp;
+	struct mlx5_flow_meter_info *fm;
+	struct mlx5_legacy_flow_meter *legacy_fm;
+	struct mlx5_flow_meter_policy *mtr_policy = NULL;
+	struct mlx5_indexed_pool_config flow_ipool_cfg = {
+		.size = 0,
+		.trunk_size = 64,
+		.need_lock = 1,
+		.type = "mlx5_flow_mtr_flow_id_pool",
+	};
+	struct mlx5_aso_mtr *aso_mtr;
+	uint32_t mtr_idx, policy_idx;
+	union mlx5_l3t_data data;
+	int ret;
+	uint8_t domain_bitmap;
+	uint8_t mtr_id_bits;
+	uint8_t mtr_reg_bits = priv->mtr_reg_share ?
+				MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
+
+	if (!priv->mtr_en)
+		return -rte_mtr_error_set(error, ENOTSUP,
+					RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter is not supported");
+	/* 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.");
+	/* Meter policy must exist. */
+	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
+		__atomic_add_fetch
+			(&priv->sh->mtrmng->def_policy_ref_cnt,
+			1, __ATOMIC_RELAXED);
+		domain_bitmap = MLX5_MTR_ALL_DOMAIN_BIT;
+		if (!priv->config.dv_esw_en)
+			domain_bitmap &= ~MLX5_MTR_DOMAIN_TRANSFER_BIT;
+	} else {
+		mtr_policy = mlx5_flow_meter_policy_find(dev,
+				params->meter_policy_id, &policy_idx);
+		if (!priv->sh->meter_aso_en)
+			return -rte_mtr_error_set(error, ENOTSUP,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Part of the policies cannot be "
+				"supported without ASO ");
+		if (!mtr_policy)
+			return -rte_mtr_error_set(error, ENOENT,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL, "Meter policy id not valid.");
+		domain_bitmap = (mtr_policy->ingress ?
+					MLX5_MTR_DOMAIN_INGRESS_BIT : 0) |
+				(mtr_policy->egress ?
+					MLX5_MTR_DOMAIN_EGRESS_BIT : 0) |
+				(mtr_policy->transfer ?
+					MLX5_MTR_DOMAIN_TRANSFER_BIT : 0);
+	}
+	/* Allocate the flow meter memory. */
+	if (priv->sh->meter_aso_en) {
+		mtr_idx = mlx5_flow_mtr_alloc(dev);
+		if (!mtr_idx)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		aso_mtr = mlx5_aso_meter_by_idx(priv, mtr_idx);
+		fm = &aso_mtr->fm;
+	} else {
+		legacy_fm = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR], &mtr_idx);
+		if (legacy_fm == NULL)
+			return -rte_mtr_error_set(error, ENOMEM,
+				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+				"Memory alloc failed for meter.");
+		legacy_fm->idx = mtr_idx;
+		fm = &legacy_fm->fm;
+	}
+	mtr_id_bits = MLX5_REG_BITS - __builtin_clz(mtr_idx);
+	if ((mtr_id_bits + priv->sh->mtrmng->max_mtr_flow_bits) >
+	    mtr_reg_bits) {
+		DRV_LOG(ERR, "Meter number exceeds max limit.");
+		goto error;
+	}
+	if (mtr_id_bits > priv->sh->mtrmng->max_mtr_bits)
+		priv->sh->mtrmng->max_mtr_bits = mtr_id_bits;
+	/* Fill the flow meter parameters. */
+	fm->meter_id = meter_id;
+	fm->policy_id = params->meter_policy_id;
+	fm->profile = fmp;
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, params->stats_mask))
+		goto error;
+	if (mlx5_flow_create_mtr_tbls(dev, fm, mtr_idx, domain_bitmap))
+		goto error;
+	/* Add to the flow meter list. */
+	if (!priv->sh->meter_aso_en)
+		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
+	/* Add to the flow meter list. */
+	fm->active_state = 1; /* Config meter starts as active. */
+	fm->is_enable = 1;
+	fm->shared = !!shared;
+	__atomic_add_fetch(&fm->profile->ref_cnt, 1, __ATOMIC_RELAXED);
+	if (params->meter_policy_id == priv->sh->mtrmng->def_policy_id) {
+		fm->def_policy = 1;
+		fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
+		if (!fm->flow_ipool)
+			goto error;
+	}
+	rte_spinlock_init(&fm->sl);
+	/* If ASO meter supported, update ASO flow meter by wqe. */
+	if (priv->sh->meter_aso_en) {
+		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
+		ret = mlx5_aso_meter_update_by_wqe(priv->sh, aso_mtr);
+		if (ret)
+			goto error;
+		if (!priv->mtr_idx_tbl) {
+			priv->mtr_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+			if (!priv->mtr_idx_tbl)
+				goto error;
+		}
+		data.dword = mtr_idx;
+		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
+			goto error;
+	}
+	if (mtr_policy)
+		__atomic_add_fetch(&mtr_policy->ref_cnt, 1, __ATOMIC_RELAXED);
+	return 0;
+error:
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	/* Free policer counters. */
+	if (fm->drop_cnt)
+		mlx5_counter_free(dev, fm->drop_cnt);
+	if (priv->sh->meter_aso_en)
+		mlx5_flow_mtr_free(dev, mtr_idx);
+	else
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR], mtr_idx);
+	return -rte_mtr_error_set(error, ENOTSUP,
+		RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+		NULL, "Failed to create devx meter.");
 }
 
 static int
@@ -902,6 +1137,7 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm = NULL;
+	struct mlx5_flow_meter_policy *mtr_policy;
 
 	/* Meter object must not have any owner. */
 	MLX5_ASSERT(!fm->ref_cnt);
@@ -911,23 +1147,42 @@ mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 		return -1;
 	/* Update dependencies. */
 	__atomic_sub_fetch(&fmp->ref_cnt, 1, __ATOMIC_RELAXED);
+	fm->profile = NULL;
 	/* Remove from list. */
 	if (!priv->sh->meter_aso_en) {
-		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
+		legacy_fm = container_of(fm,
+			struct mlx5_legacy_flow_meter, fm);
 		TAILQ_REMOVE(fms, legacy_fm, next);
 	}
 	/* Free drop counters. */
 	if (fm->drop_cnt)
 		mlx5_counter_free(dev, fm->drop_cnt);
 	/* Free meter flow table. */
-	if (fm->flow_ipool)
+	if (fm->flow_ipool) {
 		mlx5_ipool_destroy(fm->flow_ipool);
-	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-	if (priv->sh->meter_aso_en)
+		fm->flow_ipool = 0;
+	}
+	mlx5_flow_destroy_mtr_tbls(dev, fm);
+	if (fm->def_policy)
+		__atomic_sub_fetch(&priv->sh->mtrmng->def_policy_ref_cnt,
+				1, __ATOMIC_RELAXED);
+	if (priv->sh->meter_aso_en) {
+		if (!fm->def_policy) {
+			mtr_policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+			if (mtr_policy)
+				__atomic_sub_fetch(&mtr_policy->ref_cnt,
+						1, __ATOMIC_RELAXED);
+			fm->policy_id = 0;
+		}
+		fm->def_policy = 0;
+		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, fm->meter_id))
+			return -1;
 		mlx5_flow_mtr_free(dev, mtr_idx);
-	else
+	} else {
 		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR],
 					legacy_fm->idx);
+	}
 	return 0;
 }
 
@@ -954,30 +1209,28 @@ mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
+					  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+					  NULL,
 					  "Meter is not supported");
 	/* Meter object must exist. */
 	fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
 	if (fm == NULL)
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
-					  NULL, "Meter object id not valid.");
+					  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.");
-	if (priv->sh->meter_aso_en) {
-		if (mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id))
-			return -rte_mtr_error_set(error, EBUSY,
-				RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Fail to delete ASO Meter in index table.");
-	}
+					  NULL,
+					  "Meter object is being used.");
 	/* Destroy the meter profile. */
 	if (mlx5_flow_meter_params_flush(dev, fm, mtr_idx))
 		return -rte_mtr_error_set(error, EINVAL,
 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
-					NULL, "MTR object meter profile invalid.");
+					NULL,
+					"MTR object meter profile invalid.");
 	return 0;
 }
 
@@ -1211,7 +1464,11 @@ mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
 					  NULL, "Meter object id not valid.");
-	mlx5_flow_meter_stats_enable_update(fm, stats_mask);
+	if (mlx5_flow_meter_stats_enable_update(dev, fm, stats_mask))
+		return -rte_mtr_error_set(error, ENOENT,
+					  RTE_MTR_ERROR_TYPE_MTR_ID,
+					  NULL, "Fail to allocate "
+					  "counter for meter.");
 	return 0;
 }
 
@@ -1289,6 +1546,7 @@ static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.meter_policy_validate = mlx5_flow_meter_policy_validate,
 	.meter_policy_add = mlx5_flow_meter_policy_add,
 	.meter_policy_delete = mlx5_flow_meter_policy_delete,
+	.create = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
@@ -1327,7 +1585,7 @@ mlx5_flow_meter_ops_get(struct rte_eth_dev *dev __rte_unused, void *arg)
  *   Pointer to Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
@@ -1342,30 +1600,27 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 
 	if (priv->sh->meter_aso_en) {
 		rte_spinlock_lock(&pools_mng->mtrsl);
-		if (priv->mtr_idx_tbl) {
-			if (mlx5_l3t_get_entry(priv->mtr_idx_tbl,
-				meter_id, &data) ||
-				!data.dword) {
-				rte_spinlock_unlock(&pools_mng->mtrsl);
-				return NULL;
-			}
-			if (mtr_idx)
-				*mtr_idx = data.dword;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
-			/* Remove reference taken by the mlx5_l3t_get_entry. */
-			mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
-		} else {
-			if (mtr_idx)
-				*mtr_idx = meter_id;
-			aso_mtr = mlx5_aso_meter_by_idx(priv, meter_id);
+		if (!pools_mng->n_valid || !priv->mtr_idx_tbl) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
 		}
+		if (mlx5_l3t_get_entry(priv->mtr_idx_tbl, meter_id, &data) ||
+			!data.dword) {
+			rte_spinlock_unlock(&pools_mng->mtrsl);
+			return NULL;
+		}
+		if (mtr_idx)
+			*mtr_idx = data.dword;
+		aso_mtr = mlx5_aso_meter_by_idx(priv, data.dword);
+		/* Remove reference taken by the mlx5_l3t_get_entry. */
+		mlx5_l3t_clear_entry(priv->mtr_idx_tbl, meter_id);
 		rte_spinlock_unlock(&pools_mng->mtrsl);
 		if (!aso_mtr || aso_mtr->state == ASO_METER_FREE)
 			return NULL;
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
-		if (meter_id == legacy_fm->meter_id) {
+		if (meter_id == legacy_fm->fm.meter_id) {
 			if (mtr_idx)
 				*mtr_idx = legacy_fm->idx;
 			return &legacy_fm->fm;
@@ -1382,7 +1637,7 @@ mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
  *   Meter index.
  *
  * @return
- *   Pointer to the profile found on success, NULL otherwise.
+ *   Pointer to the meter info found on success, NULL otherwise.
  */
 struct mlx5_flow_meter_info *
 flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
@@ -1391,6 +1646,8 @@ flow_dv_meter_find_by_idx(struct mlx5_priv *priv, uint32_t idx)
 
 	if (priv->sh->meter_aso_en) {
 		aso_mtr = mlx5_aso_meter_by_idx(priv, idx);
+		if (!aso_mtr)
+			return NULL;
 		return &aso_mtr->fm;
 	} else {
 		return mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR], idx);
@@ -1526,32 +1783,33 @@ 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_aso_mtr_pools_mng *pools_mng =
-				&priv->sh->mtrmng->pools_mng;
 	struct mlx5_legacy_flow_meters *fms = &priv->flow_meters;
 	struct mlx5_mtr_profiles *fmps = &priv->flow_meter_profiles;
 	struct mlx5_flow_meter_profile *fmp;
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
-	struct mlx5_aso_mtr_pool *mtr_pool;
 	struct mlx5_flow_meter_sub_policy *sub_policy;
 	void *tmp;
-	uint32_t i, offset, mtr_idx, policy_idx;
+	uint32_t i, mtr_idx, policy_idx;
 	void *entry;
+	struct mlx5_aso_mtr *aso_mtr;
 
 	if (!priv->mtr_en)
 		return 0;
 	if (priv->sh->meter_aso_en) {
-		i = pools_mng->n_valid;
-		while (i--) {
-			mtr_pool = pools_mng->pools[i];
-			for (offset = 0; offset < MLX5_ASO_MTRS_PER_POOL;
-				offset++) {
-				fm = &mtr_pool->mtrs[offset].fm;
-				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				(void)mlx5_flow_meter_params_flush(dev,
+		if (priv->mtr_idx_tbl) {
+			MLX5_L3T_FOREACH(priv->mtr_idx_tbl, i, entry) {
+				mtr_idx = *(uint32_t *)entry;
+				if (mtr_idx) {
+					aso_mtr =
+					mlx5_aso_meter_by_idx(priv, mtr_idx);
+					fm = &aso_mtr->fm;
+					(void)mlx5_flow_meter_params_flush(dev,
 						fm, mtr_idx);
+				}
 			}
+			mlx5_l3t_destroy(priv->mtr_idx_tbl);
+			priv->mtr_idx_tbl = NULL;
 		}
 	} else {
 		TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
@@ -1562,7 +1820,7 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 				NULL, "MTR object meter profile invalid.");
 		}
 	}
-	if (priv->sh->mtrmng->policy_idx_tbl) {
+	if (priv->sh->mtrmng->policy_idx_tbl && priv->sh->refcnt == 1) {
 		MLX5_L3T_FOREACH(priv->sh->mtrmng->policy_idx_tbl,
 					i, entry) {
 			policy_idx = *(uint32_t *)entry;
@@ -1597,6 +1855,7 @@ mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 	}
 	/* Delete default policy table. */
 	mlx5_flow_destroy_def_policy(dev);
-	mlx5_flow_destroy_mtr_drop_tbls(dev);
+	if (priv->sh->refcnt == 1)
+		mlx5_flow_destroy_mtr_drop_tbls(dev);
 	return 0;
 }
-- 
2.27.0


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

* [dpdk-dev] [PATCH v5 3/4] net/mlx5: prepare sub-policy for a flow with meter
  2021-04-15  5:05 ` [dpdk-dev] [PATCH v5 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 1/4] " Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 2/4] net/mlx5: support meter creation with policy Li Zhang
@ 2021-04-15  5:05   ` Li Zhang
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 4/4] net/mlx5: connect meter policy to created flows Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-15  5:05 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

When a flow has a RSS action, the driver splits
each sub flow finally is configured with
a different HW TIR action.

Any RSS action configured in meter policy may cause
a split in the flow configuration.
To save performance, any TIR action will be configured
in different flow table, so policy can be split to
sub-policies per TIR in the flow creation time.

Create a function to prepare the policy and
its sub-policies for a configured flow with meter.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/mlx5_flow.h    |  10 +++
 drivers/net/mlx5/mlx5_flow_dv.c | 144 ++++++++++++++++++++++++++++++++
 2 files changed, 154 insertions(+)

diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index 89e43f2de6..cc9b37b9eb 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -1095,6 +1095,11 @@ typedef int (*mlx5_flow_create_mtr_tbls_t)(struct rte_eth_dev *dev,
 typedef void (*mlx5_flow_destroy_mtr_tbls_t)(struct rte_eth_dev *dev,
 				struct mlx5_flow_meter_info *fm);
 typedef void (*mlx5_flow_destroy_mtr_drop_tbls_t)(struct rte_eth_dev *dev);
+typedef struct mlx5_flow_meter_sub_policy *
+	(*mlx5_flow_meter_sub_policy_rss_prepare_t)
+		(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 typedef uint32_t (*mlx5_flow_mtr_alloc_t)
 					    (struct rte_eth_dev *dev);
 typedef void (*mlx5_flow_mtr_free_t)(struct rte_eth_dev *dev,
@@ -1187,6 +1192,7 @@ struct mlx5_flow_driver_ops {
 	mlx5_flow_destroy_policy_rules_t destroy_policy_rules;
 	mlx5_flow_create_def_policy_t create_def_policy;
 	mlx5_flow_destroy_def_policy_t destroy_def_policy;
+	mlx5_flow_meter_sub_policy_rss_prepare_t meter_sub_policy_rss_prepare;
 	mlx5_flow_counter_alloc_t counter_alloc;
 	mlx5_flow_counter_free_t counter_free;
 	mlx5_flow_counter_query_t counter_query;
@@ -1418,6 +1424,10 @@ int mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev,
 void mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 			       struct mlx5_flow_meter_info *fm);
 void mlx5_flow_destroy_mtr_drop_tbls(struct rte_eth_dev *dev);
+struct mlx5_flow_meter_sub_policy *mlx5_flow_meter_sub_policy_rss_prepare
+		(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS]);
 int mlx5_flow_dv_discover_counter_offset_support(struct rte_eth_dev *dev);
 int mlx5_shared_action_flush(struct rte_eth_dev *dev);
 void mlx5_release_tunnel_hub(struct mlx5_dev_ctx_shared *sh, uint16_t port_id);
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index f789f2454e..ed17bd903f 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -14857,6 +14857,149 @@ flow_dv_create_mtr_tbls(struct rte_eth_dev *dev,
 	return -1;
 }
 
+/**
+ * Find the policy table for prefix table with RSS.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] policy_id
+ *   Policy index.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ * @return
+ *   Pointer to table set on success, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_dv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+		struct mlx5_flow_meter_policy *mtr_policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+	uint32_t sub_policy_idx = 0;
+	uint32_t hrxq_idx[MLX5_MTR_RTE_COLORS] = {0};
+	uint32_t i, j;
+	struct mlx5_hrxq *hrxq;
+	struct mlx5_flow_handle dh;
+	struct mlx5_meter_policy_action_container *act_cnt;
+	uint32_t domain = MLX5_MTR_DOMAIN_INGRESS;
+	uint16_t sub_policy_num;
+
+	rte_spinlock_lock(&mtr_policy->sl);
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		hrxq_idx[i] = mlx5_hrxq_get(dev, rss_desc[i]);
+		if (!hrxq_idx[i]) {
+			rte_spinlock_unlock(&mtr_policy->sl);
+			return NULL;
+		}
+	}
+	sub_policy_num = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+	for (i = 0; i < sub_policy_num;
+		i++) {
+		for (j = 0; j < MLX5_MTR_RTE_COLORS; j++) {
+			if (rss_desc[j] &&
+				hrxq_idx[j] !=
+			mtr_policy->sub_policys[domain][i]->rix_hrxq[j])
+				break;
+		}
+		if (j >= MLX5_MTR_RTE_COLORS) {
+			/*
+			 * Found the sub policy table with
+			 * the same queue per color
+			 */
+			rte_spinlock_unlock(&mtr_policy->sl);
+			for (j = 0; j < MLX5_MTR_RTE_COLORS; j++)
+				mlx5_hrxq_release(dev, hrxq_idx[j]);
+			return mtr_policy->sub_policys[domain][i];
+		}
+	}
+	/* Create sub policy. */
+	if (!mtr_policy->sub_policys[domain][0]->rix_hrxq[0]) {
+		/* Reuse the first dummy sub_policy*/
+		sub_policy = mtr_policy->sub_policys[domain][0];
+		sub_policy_idx = sub_policy->idx;
+	} else {
+		sub_policy = mlx5_ipool_zmalloc
+				(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+				&sub_policy_idx);
+		if (!sub_policy ||
+			sub_policy_idx > MLX5_MAX_SUB_POLICY_TBL_NUM)
+			goto rss_sub_policy_error;
+		sub_policy->idx = sub_policy_idx;
+		sub_policy->main_policy = mtr_policy;
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+		if (!rss_desc[i])
+			continue;
+		sub_policy->rix_hrxq[i] = hrxq_idx[i];
+		/*
+		 * Overwrite the last action from
+		 * RSS action to Queue action.
+		 */
+		hrxq = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_HRXQ],
+			      hrxq_idx[i]);
+		if (!hrxq) {
+			DRV_LOG(ERR, "Failed to create policy hrxq");
+			goto rss_sub_policy_error;
+		}
+		act_cnt = &mtr_policy->act_cnt[i];
+		if (act_cnt->rix_mark || act_cnt->modify_hdr) {
+			memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+			if (act_cnt->rix_mark)
+				dh.mark = 1;
+			dh.fate_action = MLX5_FLOW_FATE_QUEUE;
+			dh.rix_hrxq = hrxq_idx[i];
+			flow_drv_rxq_flags_set(dev, &dh);
+		}
+	}
+	if (__flow_dv_create_policy_acts_rules(dev, mtr_policy,
+		sub_policy, domain)) {
+		DRV_LOG(ERR, "Failed to create policy "
+			"rules per domain.");
+		goto rss_sub_policy_error;
+	}
+	if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+		i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+		mtr_policy->sub_policys[domain][i] = sub_policy;
+		i++;
+		if (i > MLX5_MTR_RSS_MAX_SUB_POLICY)
+			goto rss_sub_policy_error;
+		mtr_policy->sub_policy_num &= ~(MLX5_MTR_SUB_POLICY_NUM_MASK <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain));
+		mtr_policy->sub_policy_num |=
+			(i & MLX5_MTR_SUB_POLICY_NUM_MASK) <<
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain);
+	}
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return sub_policy;
+rss_sub_policy_error:
+	if (sub_policy) {
+		__flow_dv_destroy_sub_policy_rules(dev, sub_policy);
+		if (sub_policy != mtr_policy->sub_policys[domain][0]) {
+			i = (mtr_policy->sub_policy_num >>
+			(MLX5_MTR_SUB_POLICY_NUM_SHIFT * domain)) &
+			MLX5_MTR_SUB_POLICY_NUM_MASK;
+			mtr_policy->sub_policys[domain][i] = NULL;
+			mlx5_ipool_free
+			(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+					sub_policy->idx);
+		}
+	}
+	for (i = 0; i < MLX5_MTR_RTE_COLORS; i++)
+		mlx5_hrxq_release(dev, hrxq_idx[i]);
+	if (sub_policy_idx)
+		mlx5_ipool_free(priv->sh->ipool[MLX5_IPOOL_MTR_POLICY],
+			sub_policy_idx);
+	rte_spinlock_unlock(&mtr_policy->sl);
+	return NULL;
+}
+
 /**
  * Validate the batch counter support in root table.
  *
@@ -15447,6 +15590,7 @@ const struct mlx5_flow_driver_ops mlx5_flow_dv_drv_ops = {
 	.destroy_policy_rules = flow_dv_destroy_policy_rules,
 	.create_def_policy = flow_dv_create_def_policy,
 	.destroy_def_policy = flow_dv_destroy_def_policy,
+	.meter_sub_policy_rss_prepare = flow_dv_meter_sub_policy_rss_prepare,
 	.counter_alloc = flow_dv_counter_allocate,
 	.counter_free = flow_dv_counter_free,
 	.counter_query = flow_dv_counter_query,
-- 
2.27.0


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

* [dpdk-dev] [PATCH v5 4/4] net/mlx5: connect meter policy to created flows
  2021-04-15  5:05 ` [dpdk-dev] [PATCH v5 0/4] net/mlx5: support meter policy operations Li Zhang
                     ` (2 preceding siblings ...)
  2021-04-15  5:05   ` [dpdk-dev] [PATCH v5 3/4] net/mlx5: prepare sub-policy for a flow with meter Li Zhang
@ 2021-04-15  5:05   ` Li Zhang
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-15  5:05 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs
  Cc: dev, thomas, rasland, roniba, Shun Hao

From: Shun Hao <shunh@nvidia.com>

Currently ASO meter must be followed by policy table, so this adds
the support that connecting meter and policy table.

There are several cases to be considered:
1. For non-termination policy, connect meter to the default policy
table.
2. For non-RSS termination policy case, simply get the policy
table id and connect meter to it.
3. For RSS termination policy case, need to split the flow due
to RSS info in policy, and translate each sub-flow using that RSS,
then create the sub policy table to be connected.
4. In termination policy case, if there's no actions to modify the
packet before meter, no need to use set_tag to save meter id in
register. Only add a new flow in drop table using the same match
criteria as suf-flow, to save cache miss.

Signed-off-by: Shun Hao <shunh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 doc/guides/nics/mlx5.rst        |  12 +
 drivers/net/mlx5/mlx5_flow.c    | 446 ++++++++++++++++++++++++++++----
 drivers/net/mlx5/mlx5_flow.h    |   4 +
 drivers/net/mlx5/mlx5_flow_dv.c |  15 ++
 4 files changed, 420 insertions(+), 57 deletions(-)

diff --git a/doc/guides/nics/mlx5.rst b/doc/guides/nics/mlx5.rst
index d287b3aca1..1e67a91ee7 100644
--- a/doc/guides/nics/mlx5.rst
+++ b/doc/guides/nics/mlx5.rst
@@ -106,6 +106,7 @@ Features
 - E-Switch mirroring and modify.
 - 21844 flow priorities for ingress or egress flow groups greater than 0 and for any transfer
   flow group.
+- Flow metering, including meter policy API.
 
 Limitations
 -----------
@@ -400,10 +401,21 @@ Limitations
   - Hairpin in switchdev SR-IOV mode is not supported till now.
 
 - Meter:
+
   - All the meter colors with drop action will be counted only by the global drop statistics.
   - Green color is not supported with drop action.
   - Yellow detection is not supported.
   - Red color must be with drop action.
+  - Meter statistics are supported only for drop case.
+  - Meter yellow color detection is not supported.
+  - A meter action created with pre-defined policy must be the last action in the flow except single case where the policy actions are:
+     - green: NULL or END.
+     - yellow: NULL or END.
+     - RED: DROP / END.
+  - The only supported meter policy actions:
+     - green: QUEUE, RSS, PORT_ID, JUMP, MARK and SET_TAG.
+     - yellow: must be empty.
+     - RED: must be DROP.
 
 Statistics
 ----------
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 77590bbbed..71fce4a524 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -3343,18 +3343,52 @@ flow_drv_destroy(struct rte_eth_dev *dev, struct rte_flow *flow)
 	fops->destroy(dev, flow);
 }
 
+/**
+ * Flow driver find RSS policy tbl API. This abstracts calling driver
+ * specific functions. Parent flow (rte_flow) should have driver
+ * type (drv_type). It will find the RSS policy table that has the rss_desc.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in, out] flow
+ *   Pointer to flow structure.
+ * @param[in] policy_id
+ *   The policy id of a meter.
+ * @param[in] rss_desc
+ *   Pointer to rss_desc
+ */
+static struct mlx5_flow_meter_sub_policy *
+flow_drv_meter_sub_policy_rss_prepare(struct rte_eth_dev *dev,
+		struct rte_flow *flow,
+		struct mlx5_flow_meter_policy *policy,
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS])
+{
+	const struct mlx5_flow_driver_ops *fops;
+	enum mlx5_flow_drv_type type = flow->drv_type;
+
+	MLX5_ASSERT(type > MLX5_FLOW_TYPE_MIN && type < MLX5_FLOW_TYPE_MAX);
+	fops = flow_get_drv_ops(type);
+	return fops->meter_sub_policy_rss_prepare(dev, policy, rss_desc);
+}
+
 /**
  * Get RSS action from the action list.
  *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
+ * @param[in] flow
+ *   Parent flow structure pointer.
  *
  * @return
  *   Pointer to the RSS action if exist, else return NULL.
  */
 static const struct rte_flow_action_rss*
-flow_get_rss_action(const struct rte_flow_action actions[])
+flow_get_rss_action(struct rte_eth_dev *dev,
+		    const struct rte_flow_action actions[])
 {
+	struct mlx5_priv *priv = dev->data->dev_private;
 	const struct rte_flow_action_rss *rss = NULL;
 
 	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
@@ -3372,6 +3406,23 @@ flow_get_rss_action(const struct rte_flow_action actions[])
 					rss = act->conf;
 			break;
 		}
+		case RTE_FLOW_ACTION_TYPE_METER:
+		{
+			uint32_t mtr_idx;
+			struct mlx5_flow_meter_info *fm;
+			struct mlx5_flow_meter_policy *policy;
+			const struct rte_flow_action_meter *mtr = actions->conf;
+
+			fm = mlx5_flow_meter_find(priv, mtr->mtr_id, &mtr_idx);
+			if (fm) {
+				policy = mlx5_flow_meter_policy_find(dev,
+						fm->policy_id, NULL);
+				if (policy && policy->is_rss)
+					rss =
+				policy->act_cnt[RTE_COLOR_GREEN].rss->conf;
+			}
+			break;
+		}
 		default:
 			break;
 		}
@@ -3670,13 +3721,75 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
 	return actions_n + 1;
 }
 
+/**
+ * Check if the action will change packet.
+ *
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @param[in] type
+ *   action type.
+ *
+ * @return
+ *   true if action will change packet, false otherwise.
+ */
+static bool flow_check_modify_action_type(struct rte_eth_dev *dev,
+					  enum rte_flow_action_type type)
+{
+	struct mlx5_priv *priv = dev->data->dev_private;
+
+	switch (type) {
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_MAC_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DST:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_SRC:
+	case RTE_FLOW_ACTION_TYPE_SET_TP_DST:
+	case RTE_FLOW_ACTION_TYPE_DEC_TTL:
+	case RTE_FLOW_ACTION_TYPE_SET_TTL:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_SEQ:
+	case RTE_FLOW_ACTION_TYPE_INC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_DEC_TCP_ACK:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV4_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_IPV6_DSCP:
+	case RTE_FLOW_ACTION_TYPE_SET_META:
+	case RTE_FLOW_ACTION_TYPE_SET_TAG:
+	case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
+	case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_PCP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
+	case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
+	case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
+		return true;
+	case RTE_FLOW_ACTION_TYPE_FLAG:
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		if (priv->config.dv_xmeta_en != MLX5_XMETA_MODE_LEGACY)
+			return true;
+		else
+			return false;
+	default:
+		return false;
+	}
+}
+
 /**
  * Check meter action from the action list.
  *
+ * @param dev
+ *   Pointer to Ethernet device.
  * @param[in] actions
  *   Pointer to the list of actions.
  * @param[out] has_mtr
  *   Pointer to the meter exist flag.
+ * @param[out] has_modify
+ *   Pointer to the flag showing there's packet change action.
  * @param[out] meter_id
  *   Pointer to the meter id.
  *
@@ -3684,9 +3797,9 @@ flow_parse_metadata_split_actions_info(const struct rte_flow_action actions[],
  *   Total number of actions.
  */
 static int
-flow_check_meter_action(const struct rte_flow_action actions[],
-			bool *has_mtr,
-			uint32_t *meter_id)
+flow_check_meter_action(struct rte_eth_dev *dev,
+			const struct rte_flow_action actions[],
+			bool *has_mtr, bool *has_modify, uint32_t *meter_id)
 {
 	const struct rte_flow_action_meter *mtr = NULL;
 	int actions_n = 0;
@@ -3703,6 +3816,9 @@ flow_check_meter_action(const struct rte_flow_action actions[],
 		default:
 			break;
 		}
+		if (!*has_mtr)
+			*has_modify |= flow_check_modify_action_type(dev,
+								actions->type);
 		actions_n++;
 	}
 	/* Count RTE_FLOW_ACTION_TYPE_END. */
@@ -4348,6 +4464,108 @@ flow_create_split_inner(struct rte_eth_dev *dev,
 	return flow_drv_translate(dev, dev_flow, attr, items, actions, error);
 }
 
+/**
+ * Get the sub policy of a meter.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ * @param[in] flow
+ *   Parent flow structure pointer.
+ * @param[in] policy_id;
+ *   Meter Policy id.
+ * @param[in] attr
+ *   Flow rule attributes.
+ * @param[in] items
+ *   Pattern specification (list terminated by the END pattern item).
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ *
+ * @return
+ *   Pointer to the meter sub policy, NULL otherwise and rte_errno is set.
+ */
+static struct mlx5_flow_meter_sub_policy *
+get_meter_sub_policy(struct rte_eth_dev *dev,
+		     struct rte_flow *flow,
+		     uint32_t policy_id,
+		     const struct rte_flow_attr *attr,
+		     const struct rte_flow_item items[],
+		     struct rte_flow_error *error)
+{
+	struct mlx5_flow_meter_policy *policy;
+	struct mlx5_flow_meter_sub_policy *sub_policy = NULL;
+
+	policy = mlx5_flow_meter_policy_find(dev, policy_id, NULL);
+	if (!policy) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+				   "Failed to find Meter Policy.");
+		goto exit;
+	}
+	if (policy->is_rss) {
+		struct mlx5_flow_workspace *wks =
+				mlx5_flow_get_thread_workspace();
+		struct mlx5_flow_rss_desc rss_desc_v[MLX5_MTR_RTE_COLORS];
+		struct mlx5_flow_rss_desc *rss_desc[MLX5_MTR_RTE_COLORS] = {0};
+		uint32_t i;
+
+		MLX5_ASSERT(wks);
+		/**
+		 * This is a tmp dev_flow,
+		 * no need to register any matcher for it in translate.
+		 */
+		wks->skip_matcher_reg = 1;
+		for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+			struct mlx5_flow dev_flow = {0};
+			struct mlx5_flow_handle dev_handle = { {0} };
+			const void *rss_act = policy->act_cnt[i].rss->conf;
+			struct rte_flow_action rss_actions[2] = {
+				[0] = {
+					.type = RTE_FLOW_ACTION_TYPE_RSS,
+					.conf = rss_act
+				},
+				[1] = {
+					.type = RTE_FLOW_ACTION_TYPE_END,
+					.conf = NULL
+				}
+			};
+
+			dev_flow.handle = &dev_handle;
+			dev_flow.ingress = attr->ingress;
+			dev_flow.flow = flow;
+			dev_flow.external = 0;
+#ifdef HAVE_IBV_FLOW_DV_SUPPORT
+			dev_flow.dv.transfer = attr->transfer;
+#endif
+			/* Translate RSS action to get rss hash fields. */
+			if (flow_drv_translate(dev, &dev_flow, attr,
+						items, rss_actions, error))
+				goto exit;
+			rss_desc_v[i] = wks->rss_desc;
+			rss_desc_v[i].key_len = MLX5_RSS_HASH_KEY_LEN;
+			rss_desc_v[i].hash_fields = dev_flow.hash_fields;
+			rss_desc_v[i].queue_num = rss_desc_v[i].hash_fields ?
+						  rss_desc_v[i].queue_num : 1;
+			rss_desc[i] = &rss_desc_v[i];
+		}
+		sub_policy = flow_drv_meter_sub_policy_rss_prepare(dev,
+						flow, policy, rss_desc);
+	} else {
+		enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+		sub_policy = policy->sub_policys[mtr_domain][0];
+	}
+	if (!sub_policy) {
+		rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+			"Failed to get meter sub-policy.");
+		goto exit;
+	}
+exit:
+	return sub_policy;
+}
+
 /**
  * Split the meter flow.
  *
@@ -4378,13 +4596,15 @@ flow_create_split_inner(struct rte_eth_dev *dev,
  *   Suffix flow actions.
  * @param[out] actions_pre
  *   Prefix flow actions.
+ * @param[out] mtr_flow_id
+ *   Pointer to meter flow id.
  * @param[out] error
  *   Perform verbose error reporting if not NULL.
  *
  * @return
- *   The flow id, 0 otherwise and rte_errno is set.
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
-static uint32_t
+static int
 flow_meter_split_prep(struct rte_eth_dev *dev,
 		      struct rte_flow *flow,
 		      struct mlx5_flow_meter_info *fm,
@@ -4394,6 +4614,7 @@ 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[],
+		      uint32_t *mtr_flow_id,
 		      struct rte_flow_error *error)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
@@ -4407,7 +4628,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	uint32_t tag_id = 0;
 	bool copy_vlan = false;
 	struct rte_flow_action *hw_mtr_action;
-	struct rte_flow_action_jump *jump_data;
 	struct rte_flow_action *action_pre_head = NULL;
 	bool mtr_first = priv->sh->meter_aso_en &&
 			(attr->egress ||
@@ -4462,7 +4682,8 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 			break;
 		}
 		if (!action_cur)
-			action_cur = actions_sfx++;
+			action_cur = (fm->def_policy) ?
+					actions_sfx++ : actions_pre++;
 		memcpy(action_cur, actions, sizeof(struct rte_flow_action));
 	}
 	/* Add end action to the actions. */
@@ -4472,38 +4693,61 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 		 * For ASO meter, need to add an extra jump action explicitly,
 		 * to jump from meter to policer table.
 		 */
-		hw_mtr_action = actions_pre;
-		hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
-		actions_pre++;
-		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
-		actions_pre++;
-		jump_data = (struct rte_flow_action_jump *)actions_pre;
-		jump_data->group = attr->transfer ?
-				(MLX5_FLOW_TABLE_LEVEL_POLICY - 1) :
-				 MLX5_FLOW_TABLE_LEVEL_POLICY;
-		hw_mtr_action->conf = jump_data;
-		actions_pre = (struct rte_flow_action *)(jump_data + 1);
-	} else {
-		actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
-		actions_pre++;
+		struct mlx5_flow_meter_sub_policy *sub_policy;
+		struct mlx5_flow_tbl_data_entry *tbl_data;
+
+		if (!fm->def_policy) {
+			sub_policy = get_meter_sub_policy(dev, flow,
+							  fm->policy_id, attr,
+							  items, error);
+			if (!sub_policy)
+				return -rte_errno;
+		} else {
+			enum mlx5_meter_domain mtr_domain =
+			attr->transfer ? MLX5_MTR_DOMAIN_TRANSFER :
+				attr->egress ? MLX5_MTR_DOMAIN_EGRESS :
+					MLX5_MTR_DOMAIN_INGRESS;
+
+			sub_policy =
+			&priv->sh->mtrmng->def_policy[mtr_domain]->sub_policy;
+		}
+		tbl_data = container_of(sub_policy->tbl_rsc,
+					struct mlx5_flow_tbl_data_entry, tbl);
+		hw_mtr_action = actions_pre++;
+		hw_mtr_action->type = (enum rte_flow_action_type)
+				      MLX5_RTE_FLOW_ACTION_TYPE_JUMP;
+		hw_mtr_action->conf = tbl_data->jump.action;
 	}
-	/* Generate meter flow_id only if support multiple flows per meter. */
-	mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
-	if (!tag_id)
+	actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+	actions_pre++;
+	if (!tag_action)
 		return rte_flow_error_set(error, ENOMEM,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Failed to allocate meter flow id.");
-	flow_id = tag_id - 1;
-	flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
-	flow_id_bits = flow_id_bits ? flow_id_bits : 1;
-	if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) > mtr_reg_bits) {
-		mlx5_ipool_free(fm->flow_ipool, tag_id);
-		return rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-				"Meter flow id exceeds max limit.");
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"No tag action space.");
+	if (!mtr_flow_id) {
+		tag_action->type = RTE_FLOW_ACTION_TYPE_VOID;
+		goto exit;
+	}
+	/* Only default-policy Meter creates mtr flow id. */
+	if (fm->def_policy) {
+		mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
+		if (!tag_id)
+			return rte_flow_error_set(error, ENOMEM,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Failed to allocate meter flow id.");
+		flow_id = tag_id - 1;
+		flow_id_bits = MLX5_REG_BITS - __builtin_clz(flow_id);
+		flow_id_bits = flow_id_bits ? flow_id_bits : 1;
+		if ((flow_id_bits + priv->sh->mtrmng->max_mtr_bits) >
+		    mtr_reg_bits) {
+			mlx5_ipool_free(fm->flow_ipool, tag_id);
+			return rte_flow_error_set(error, EINVAL,
+					RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+					"Meter flow id exceeds max limit.");
+		}
+		if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
+			priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	}
-	if (flow_id_bits > priv->sh->mtrmng->max_mtr_flow_bits)
-		priv->sh->mtrmng->max_mtr_flow_bits = flow_id_bits;
 	/* Prepare the suffix subflow items. */
 	tag_item = sfx_items++;
 	for (; items->type != RTE_FLOW_ITEM_TYPE_END; items++) {
@@ -4533,7 +4777,6 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	sfx_items->type = RTE_FLOW_ITEM_TYPE_END;
 	sfx_items++;
 	/* Build tag actions and items for meter_id/meter flow_id. */
-	assert(tag_action);
 	set_tag = (struct mlx5_rte_flow_action_set_tag *)actions_pre;
 	tag_item_spec = (struct mlx5_rte_flow_item_tag *)sfx_items;
 	tag_item_mask = tag_item_spec + 1;
@@ -4551,8 +4794,9 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	 */
 	for (shift = 0; shift < flow_id_bits; shift++)
 		flow_id_reversed = (flow_id_reversed << 1) |
-			      ((flow_id >> shift) & 0x1);
-	set_tag->data |= flow_id_reversed << (mtr_reg_bits - flow_id_bits);
+				((flow_id >> shift) & 0x1);
+	set_tag->data |=
+		flow_id_reversed << (mtr_reg_bits - flow_id_bits);
 	tag_item_spec->id = set_tag->id;
 	tag_item_spec->data = set_tag->data << mtr_id_offset;
 	tag_item_mask->data = UINT32_MAX << mtr_id_offset;
@@ -4564,7 +4808,10 @@ flow_meter_split_prep(struct rte_eth_dev *dev,
 	tag_item->spec = tag_item_spec;
 	tag_item->last = NULL;
 	tag_item->mask = tag_item_mask;
-	return tag_id;
+exit:
+	if (mtr_flow_id)
+		*mtr_flow_id = tag_id;
+	return 0;
 }
 
 /**
@@ -5228,6 +5475,57 @@ flow_create_split_metadata(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/**
+ * Create meter internal drop flow with the original pattern.
+ *
+ * @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] flow_split_info
+ *   Pointer to flow split info structure.
+ * @param[in] fm
+ *   Pointer to flow meter structure.
+ * @param[out] error
+ *   Perform verbose error reporting if not NULL.
+ * @return
+ *   0 on success, negative value otherwise
+ */
+static uint32_t
+flow_meter_create_drop_flow_with_org_pattern(struct rte_eth_dev *dev,
+			struct rte_flow *flow,
+			const struct rte_flow_attr *attr,
+			const struct rte_flow_item items[],
+			struct mlx5_flow_split_info *flow_split_info,
+			struct mlx5_flow_meter_info *fm,
+			struct rte_flow_error *error)
+{
+	struct mlx5_flow *dev_flow = NULL;
+	struct rte_flow_attr drop_attr = *attr;
+	struct rte_flow_action drop_actions[3];
+	struct mlx5_flow_split_info drop_split_info = *flow_split_info;
+
+	MLX5_ASSERT(fm->drop_cnt);
+	drop_actions[0].type =
+		(enum rte_flow_action_type)MLX5_RTE_FLOW_ACTION_TYPE_COUNT;
+	drop_actions[0].conf = (void *)(uintptr_t)fm->drop_cnt;
+	drop_actions[1].type = RTE_FLOW_ACTION_TYPE_DROP;
+	drop_actions[1].conf = NULL;
+	drop_actions[2].type = RTE_FLOW_ACTION_TYPE_END;
+	drop_actions[2].conf = NULL;
+	drop_split_info.external = false;
+	drop_split_info.skip_scale |= 1 << MLX5_SCALE_FLOW_GROUP_BIT;
+	drop_split_info.table_id = MLX5_MTR_TABLE_ID_DROP;
+	drop_attr.group = MLX5_FLOW_TABLE_LEVEL_METER;
+	return flow_create_split_inner(dev, flow, &dev_flow,
+				&drop_attr, items, drop_actions,
+				&drop_split_info, error);
+}
+
 /**
  * The splitting for meter feature.
  *
@@ -5272,18 +5570,21 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 	struct mlx5_flow *dev_flow = NULL;
 	struct rte_flow_attr sfx_attr = *attr;
 	struct mlx5_flow_meter_info *fm = NULL;
+	uint8_t skip_scale_restore;
 	bool has_mtr = false;
-	uint32_t meter_id;
+	bool has_modify = false;
+	bool set_mtr_reg = true;
+	uint32_t meter_id = 0;
 	uint32_t mtr_idx = 0;
-	uint32_t mtr_tag_id = 0;
+	uint32_t mtr_flow_id = 0;
 	size_t act_size;
 	size_t item_size;
 	int actions_n = 0;
 	int ret = 0;
 
 	if (priv->mtr_en)
-		actions_n = flow_check_meter_action(actions, &has_mtr,
-						    &meter_id);
+		actions_n = flow_check_meter_action(dev, actions, &has_mtr,
+						    &has_modify, &meter_id);
 	if (has_mtr) {
 		if (flow->meter) {
 			fm = flow_dv_meter_find_by_idx(priv, flow->meter);
@@ -5303,11 +5604,20 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 				return -rte_errno;
 			flow->meter = mtr_idx;
 		}
+		MLX5_ASSERT(wks);
 		wks->fm = fm;
+		/*
+		 * If it isn't default-policy Meter, and
+		 * 1. There's no action in flow to change
+		 *    packet (modify/encap/decap etc.), OR
+		 * 2. No drop count needed for this meter.
+		 * no need to use regC to save meter id anymore.
+		 */
+		if (!fm->def_policy && (!has_modify || !fm->drop_cnt))
+			set_mtr_reg = false;
 		/* Prefix actions: meter, decap, encap, tag, jump, end. */
 		act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
-			   sizeof(struct mlx5_rte_flow_action_set_tag) +
-			   sizeof(struct rte_flow_action_jump);
+			   sizeof(struct mlx5_rte_flow_action_set_tag);
 		/* Suffix items: tag, vlan, port id, end. */
 #define METER_SUFFIX_ITEM 4
 		item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
@@ -5321,27 +5631,48 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 						  "meter flow");
 		sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
 			     act_size);
-		pre_actions = sfx_actions + actions_n;
-		mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
-						   items, sfx_items, actions,
-						   sfx_actions, pre_actions,
-						   error);
-		if (!mtr_tag_id) {
+		/* There's no suffix flow for meter of non-default policy. */
+		if (!fm->def_policy)
+			pre_actions = sfx_actions + 1;
+		else
+			pre_actions = sfx_actions + actions_n;
+		ret = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+					    items, sfx_items, actions,
+					    sfx_actions, pre_actions,
+					    (set_mtr_reg ? &mtr_flow_id : NULL),
+					    error);
+		if (ret) {
 			ret = -rte_errno;
 			goto exit;
 		}
 		/* Add the prefix subflow. */
 		flow_split_info->prefix_mark = 0;
+		skip_scale_restore = flow_split_info->skip_scale;
+		flow_split_info->skip_scale |=
+			1 << MLX5_SCALE_JUMP_FLOW_GROUP_BIT;
 		ret = flow_create_split_inner(dev, flow, &dev_flow,
 					      attr, items, pre_actions,
 					      flow_split_info, error);
+		flow_split_info->skip_scale = skip_scale_restore;
 		if (ret) {
-			mlx5_ipool_free(fm->flow_ipool, mtr_tag_id);
+			if (mtr_flow_id)
+				mlx5_ipool_free(fm->flow_ipool, mtr_flow_id);
 			ret = -rte_errno;
 			goto exit;
 		}
-		dev_flow->handle->split_flow_id = mtr_tag_id;
-		dev_flow->handle->is_meter_flow_id = 1;
+		if (mtr_flow_id) {
+			dev_flow->handle->split_flow_id = mtr_flow_id;
+			dev_flow->handle->is_meter_flow_id = 1;
+		}
+		if (!fm->def_policy) {
+			if (!set_mtr_reg && fm->drop_cnt)
+				ret =
+			flow_meter_create_drop_flow_with_org_pattern(dev, flow,
+							&sfx_attr, items,
+							flow_split_info,
+							fm, error);
+			goto exit;
+		}
 		/* Setting the sfx group atrr. */
 		sfx_attr.group = sfx_attr.transfer ?
 				(MLX5_FLOW_TABLE_LEVEL_METER - 1) :
@@ -5349,6 +5680,7 @@ flow_create_split_meter(struct rte_eth_dev *dev,
 		flow_split_info->prefix_layers =
 				flow_get_prefix_layer_flags(dev_flow);
 		flow_split_info->prefix_mark = dev_flow->handle->mark;
+		flow_split_info->table_id = MLX5_MTR_TABLE_ID_SUFFIX;
 	}
 	/* Add the prefix subflow. */
 	ret = flow_create_split_metadata(dev, flow,
@@ -5736,7 +6068,7 @@ flow_list_create(struct rte_eth_dev *dev, uint32_t *list,
 	memset(rss_desc, 0, offsetof(struct mlx5_flow_rss_desc, queue));
 	/* RSS Action only works on NIC RX domain */
 	if (attr->ingress && !attr->transfer)
-		rss = flow_get_rss_action(p_actions_rx);
+		rss = flow_get_rss_action(dev, p_actions_rx);
 	if (rss) {
 		if (flow_rss_workspace_adjust(wks, rss_desc, rss->queue_num))
 			return 0;
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index cc9b37b9eb..8a0a84a604 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -37,6 +37,8 @@ enum mlx5_rte_flow_action_type {
 	MLX5_RTE_FLOW_ACTION_TYPE_DEFAULT_MISS,
 	MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET,
 	MLX5_RTE_FLOW_ACTION_TYPE_AGE,
+	MLX5_RTE_FLOW_ACTION_TYPE_JUMP,
+	MLX5_RTE_FLOW_ACTION_TYPE_COUNT,
 };
 
 #define MLX5_SHARED_ACTION_TYPE_OFFSET 30
@@ -1048,6 +1050,8 @@ struct mlx5_flow_workspace {
 	uint32_t rssq_num; /* Allocated queue num in rss_desc. */
 	uint32_t flow_idx; /* Intermediate device flow index. */
 	struct mlx5_flow_meter_info *fm; /* Pointer to the meter in flow. */
+	uint32_t skip_matcher_reg:1;
+	/* Indicates if need to skip matcher register in translate. */
 };
 
 struct mlx5_flow_split_info {
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index ed17bd903f..eedbe2e43b 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -7423,6 +7423,7 @@ flow_dv_prepare(struct rte_eth_dev *dev,
 	struct mlx5_flow_workspace *wks = mlx5_flow_get_thread_workspace();
 
 	MLX5_ASSERT(wks);
+	wks->skip_matcher_reg = 0;
 	/* In case of corrupting the memory. */
 	if (wks->flow_idx >= MLX5_NUM_MAX_DEV_FLOWS) {
 		rte_flow_error_set(error, ENOSPC,
@@ -11254,6 +11255,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
 		int action_type = actions->type;
 		const struct rte_flow_action *found_action = NULL;
 		uint32_t jump_group = 0;
+		struct mlx5_flow_counter *cnt;
 
 		if (!mlx5_flow_os_action_supported(action_type))
 			return rte_flow_error_set(error, ENOTSUP,
@@ -11434,6 +11436,12 @@ flow_dv_translate(struct rte_eth_dev *dev,
 				age = action->conf;
 			action_flags |= MLX5_FLOW_ACTION_COUNT;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_COUNT:
+			cnt = flow_dv_counter_get_by_idx(dev,
+				(uint32_t)(uintptr_t)action->conf, NULL);
+			MLX5_ASSERT(cnt != NULL);
+			dev_flow->dv.actions[actions_n++] = cnt->action;
+			break;
 		case RTE_FLOW_ACTION_TYPE_OF_POP_VLAN:
 			dev_flow->dv.actions[actions_n++] =
 						priv->sh->pop_vlan_action;
@@ -11538,6 +11546,11 @@ flow_dv_translate(struct rte_eth_dev *dev,
 			/* If decap is followed by encap, handle it at encap. */
 			action_flags |= MLX5_FLOW_ACTION_DECAP;
 			break;
+		case MLX5_RTE_FLOW_ACTION_TYPE_JUMP:
+			dev_flow->dv.actions[actions_n++] =
+				(void *)(uintptr_t)action->conf;
+			action_flags |= MLX5_FLOW_ACTION_JUMP;
+			break;
 		case RTE_FLOW_ACTION_TYPE_JUMP:
 			jump_group = ((const struct rte_flow_action_jump *)
 							action->conf)->group;
@@ -12093,6 +12106,8 @@ flow_dv_translate(struct rte_eth_dev *dev,
 	}
 	dev_flow->dv.actions_n = actions_n;
 	dev_flow->act_flags = action_flags;
+	if (wks->skip_matcher_reg)
+		return 0;
 	/* Register matcher. */
 	matcher.crc = rte_raw_cksum((const void *)matcher.mask.buf,
 				    matcher.mask.size);
-- 
2.27.0


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

* [dpdk-dev] [PATCH v6 0/4] net/mlx5: support meter policy operations
  2021-04-01  8:16 [dpdk-dev] [PATCH 0/4] net/mlx5: support meter policy operations Li Zhang
                   ` (7 preceding siblings ...)
  2021-04-15  5:05 ` [dpdk-dev] [PATCH v5 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-15  5:09 ` Li Zhang
  2021-04-15  5:09   ` [dpdk-dev] [PATCH v6 1/4] " Li Zhang
                     ` (3 more replies)
  2021-04-21  3:11 ` [dpdk-dev] [PATCH v7 0/4] net/mlx5: support meter policy operations Li Zhang
  2021-04-27 10:43 ` [dpdk-dev] [PATCH v8 " Li Zhang
  10 siblings, 4 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-15  5:09 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

The termination policy must have a fate action as in the policy
actions, it can support QUEUE, RSS, PORT_ID, DROP, JUMP, MARK and SET_TAG
actions if policy color is GREEN, also supports DROP action
if policy color is RED.

The no-termination policy uses policy ID 0 as default policy,
it is created internal and cannot be changed by API. The default
policy red action is drop, green action is jump to suffix table.
Create this policy by policy API with green/yellow no action,
red with drop action.
One example in testpmd command:
add port meter policy 0 g_actions end y_actions end r_actions drop / end

Depends-on: series=16351  ("Add ASO meter support in MLX5 PMD ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16351

Depends-on: series=16389  ("Support meter policy API ")
https://patchwork.dpdk.org/project/dpdk/list/?series=16389

V2: Add MLX5_MTR_DEFAULT_POLICY_ID in MLX5 PMD
V3: Fix comments about Depends-on
V4: Fix comments about rte_mtr_meter_policy_add.
V5: Fix comments about destory meter on different ports.
V6: Fix comments about Depends-on

Li Zhang (3):
  net/mlx5: support meter policy operations
  net/mlx5: support meter creation with policy
  net/mlx5: prepare sub-policy for a flow with meter

Shun Hao (1):
  net/mlx5: connect meter policy to created flows

 doc/guides/nics/mlx5.rst           |   12 +
 drivers/net/mlx5/linux/mlx5_os.c   |   13 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  212 +++-
 drivers/net/mlx5/mlx5_flow.c       |  654 ++++++++--
 drivers/net/mlx5/mlx5_flow.h       |  119 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1896 ++++++++++++++++++++++++++--
 drivers/net/mlx5/mlx5_flow_meter.c |  742 ++++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 10 files changed, 3373 insertions(+), 363 deletions(-)

-- 
2.27.0


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

* [dpdk-dev] [PATCH v6 1/4] net/mlx5: support meter policy operations
  2021-04-15  5:09 ` [dpdk-dev] [PATCH v6 0/4] net/mlx5: support meter policy operations Li Zhang
@ 2021-04-15  5:09   ` Li Zhang
  2021-04-15  5:09   ` [dpdk-dev] [PATCH v6 2/4] net/mlx5: support meter creation with policy Li Zhang
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 42+ messages in thread
From: Li Zhang @ 2021-04-15  5:09 UTC (permalink / raw)
  To: dekelp, orika, viacheslavo, matan, shahafs; +Cc: dev, thomas, rasland, roniba

MLX5 PMD checks the validation of actions in policy while add
a new meter policy, if pass the validation, allocates the new
policy object from the meter policy indexed memory pool.

It is common to use the same policy for multiple meters.
MLX5 PMD supports two types of policy: termination policy and
no-termination policy.

Implement the next policy operations:
validate:
The driver doesn't support to configure actions in the flow
after the meter action except one case when the meter policy
is configured to do nothing in GREEN\YELLOW and only DROP action
in RED, this special policy is called non-terminated policy
and is handed as a singleton object internally.

For all the terminated policies, the next actions are supported:
GREEN - QUEUE, RSS, PORT_ID, JUMP, DROP, MARK and SET_TAG.
YELLOW - not supported at all -> must be empty.
RED - must include DROP action.

Hence, in ingress case, for example,
QUEUE\RSS\JUMP must be configured as last action for GREEN color.

All the above limitations will be validated.

create:
Validate the policy configuration.
Prepare the related tables and actions.

destroy:
Release the created policy resources.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
---
 drivers/net/mlx5/linux/mlx5_os.c   |    2 +-
 drivers/net/mlx5/mlx5.c            |   77 +-
 drivers/net/mlx5/mlx5.h            |  158 +++-
 drivers/net/mlx5/mlx5_flow.c       |  192 +++-
 drivers/net/mlx5/mlx5_flow.h       |   73 +-
 drivers/net/mlx5/mlx5_flow_aso.c   |   10 +-
 drivers/net/mlx5/mlx5_flow_dv.c    | 1412 +++++++++++++++++++++++++++-
 drivers/net/mlx5/mlx5_flow_meter.c |  445 ++++++++-
 drivers/net/mlx5/mlx5_trigger.c    |    1 +
 9 files changed, 2242 insertions(+), 128 deletions(-)

diff --git a/drivers/net/mlx5/linux/mlx5_os.c b/drivers/net/mlx5/linux/mlx5_os.c
index bec288c840..276283d492 100644
--- a/drivers/net/mlx5/linux/mlx5_os.c
+++ b/drivers/net/mlx5/linux/mlx5_os.c
@@ -1299,7 +1299,7 @@ mlx5_dev_spawn(struct rte_device *dpdk_dev,
 			log_obj_size <=
 			config->hca_attr.qos.log_meter_aso_max_alloc) {
 				sh->meter_aso_en = 1;
-				err = mlx5_aso_flow_mtrs_mng_init(priv);
+				err = mlx5_aso_flow_mtrs_mng_init(priv->sh);
 				if (err) {
 					err = -err;
 					goto error;
diff --git a/drivers/net/mlx5/mlx5.c b/drivers/net/mlx5/mlx5.c
index 572db1bc67..b4cdaa7131 100644
--- a/drivers/net/mlx5/mlx5.c
+++ b/drivers/net/mlx5/mlx5.c
@@ -350,6 +350,20 @@ static const struct mlx5_indexed_pool_config mlx5_ipool_cfg[] = {
 		.free = mlx5_free,
 		.type = "mlx5_shared_action_rss",
 	},
+	[MLX5_IPOOL_MTR_POLICY] = {
+		/**
+		 * The ipool index should grow continually from small to big,
+		 * for policy idx, so not set grow_trunk to avoid policy index
+		 * not jump continually.
+		 */
+		.size = sizeof(struct mlx5_flow_meter_sub_policy),
+		.trunk_size = 64,
+		.need_lock = 1,
+		.release_mem_en = 1,
+		.malloc = mlx5_malloc,
+		.free = mlx5_free,
+		.type = "mlx5_meter_policy_ipool",
+	},
 };
 
 
@@ -569,27 +583,25 @@ mlx5_flow_counters_mng_close(struct mlx5_dev_ctx_shared *sh)
  *   Pointer to mlx5_dev_ctx_shared object to free
  */
 int
-mlx5_aso_flow_mtrs_mng_init(struct mlx5_priv *priv)
+mlx5_aso_flow_mtrs_mng_init(struct mlx5_dev_ctx_shared *sh)
 {
-	if (!priv->mtr_idx_tbl) {
-		priv->mtr_idx_tbl = mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
-		if (!priv->mtr_idx_tbl) {
-			DRV_LOG(ERR, "fail to create meter lookup table.");
-			rte_errno = ENOMEM;
-			return -ENOMEM;
-		}
-	}
-	if (!priv->sh->mtrmng) {
-		priv->sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
-			sizeof(*priv->sh->mtrmng),
+	if (!sh->mtrmng) {
+		sh->mtrmng = mlx5_malloc(MLX5_MEM_ZERO,
+			sizeof(*sh->mtrmng),
 			RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
-		if (!priv->sh->mtrmng) {
-			DRV_LOG(ERR, "mlx5_aso_mtr_pools_mng allocation was failed.");
+		if (!sh->mtrmng) {
+			DRV_LOG(ERR,
+			"meter management allocation was failed.");
 			rte_errno = ENOMEM;
 			return -ENOMEM;
 		}
-		rte_spinlock_init(&priv->sh->mtrmng->mtrsl);
-		LIST_INIT(&priv->sh->mtrmng->meters);
+		if (sh->meter_aso_en) {
+			rte_spinlock_init(&sh->mtrmng->pools_mng.mtrsl);
+			LIST_INIT(&sh->mtrmng->pools_mng.meters);
+			sh->mtrmng->policy_idx_tbl =
+				mlx5_l3t_create(MLX5_L3T_TYPE_DWORD);
+		}
+		sh->mtrmng->def_policy_id = MLX5_INVALID_POLICY_ID;
 	}
 	return 0;
 }
@@ -605,31 +617,34 @@ static void
 mlx5_aso_flow_mtrs_mng_close(struct mlx5_dev_ctx_shared *sh)
 {
 	struct mlx5_aso_mtr_pool *mtr_pool;
-	struct mlx5_aso_mtr_pools_mng *mtrmng = sh->mtrmng;
+	struct mlx5_flow_mtr_mng *mtrmng = sh->mtrmng;
 	uint32_t idx;
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
 	struct mlx5_aso_mtr *aso_mtr;
 	int i;
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
 
-	mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
-	idx = mtrmng->n_valid;
-	while (idx--) {
-		mtr_pool = mtrmng->pools[idx];
+	if (sh->meter_aso_en) {
+		mlx5_aso_queue_uninit(sh, ASO_OPC_MOD_POLICER);
+		idx = mtrmng->pools_mng.n_valid;
+		while (idx--) {
+			mtr_pool = mtrmng->pools_mng.pools[idx];
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
-		for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
-			aso_mtr = &mtr_pool->mtrs[i];
-			if (aso_mtr->fm.meter_action)
-				claim_zero(mlx5_glue->destroy_flow_action
-						(aso_mtr->fm.meter_action));
-		}
+			for (i = 0; i < MLX5_ASO_MTRS_PER_POOL; i++) {
+				aso_mtr = &mtr_pool->mtrs[i];
+				if (aso_mtr->fm.meter_action)
+					claim_zero
+					(mlx5_glue->destroy_flow_action
+					(aso_mtr->fm.meter_action));
+			}
 #endif /* HAVE_MLX5_DR_CREATE_ACTION_ASO */
-		claim_zero(mlx5_devx_cmd_destroy
+			claim_zero(mlx5_devx_cmd_destroy
 						(mtr_pool->devx_obj));
-		mtrmng->n_valid--;
-		mlx5_free(mtr_pool);
+			mtrmng->pools_mng.n_valid--;
+			mlx5_free(mtr_pool);
+		}
+		mlx5_free(sh->mtrmng->pools_mng.pools);
 	}
-	mlx5_free(sh->mtrmng->pools);
 	mlx5_free(sh->mtrmng);
 	sh->mtrmng = NULL;
 }
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index a8e11023cc..cb7c75aa2e 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -56,6 +56,7 @@ enum mlx5_ipool_index {
 	MLX5_IPOOL_RTE_FLOW, /* Pool for rte_flow. */
 	MLX5_IPOOL_RSS_EXPANTION_FLOW_ID, /* Pool for Queue/RSS flow ID. */
 	MLX5_IPOOL_RSS_SHARED_ACTIONS, /* Pool for RSS shared actions. */
+	MLX5_IPOOL_MTR_POLICY, /* Pool for meter policy resource. */
 	MLX5_IPOOL_MAX,
 };
 
@@ -580,9 +581,126 @@ struct mlx5_dev_shared_port {
 	/* Aging information for per port. */
 };
 
+/*
+ * Max number of actions per DV flow.
+ * See CREATE_FLOW_MAX_FLOW_ACTIONS_SUPPORTED
+ * in rdma-core file providers/mlx5/verbs.c.
+ */
+#define MLX5_DV_MAX_NUMBER_OF_ACTIONS 8
+
 /*ASO flow meter structures*/
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
+/* Yellow is not supported. */
+#define MLX5_MTR_RTE_COLORS (RTE_COLOR_GREEN + 1)
+/* table_id 22 bits in mlx5_flow_tbl_key so limit policy number. */
+#define MLX5_MAX_SUB_POLICY_TBL_NUM 0x3FFFFF
+#define MLX5_INVALID_POLICY_ID UINT32_MAX
+/* Suffix table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_SUFFIX 1
+/* Drop table_id on MLX5_FLOW_TABLE_LEVEL_METER. */
+#define MLX5_MTR_TABLE_ID_DROP 2
+
+enum mlx5_meter_domain {
+	MLX5_MTR_DOMAIN_INGRESS,
+	MLX5_MTR_DOMAIN_EGRESS,
+	MLX5_MTR_DOMAIN_TRANSFER,
+	MLX5_MTR_DOMAIN_MAX,
+};
+#define MLX5_MTR_DOMAIN_INGRESS_BIT  (1 << MLX5_MTR_DOMAIN_INGRESS)
+#define MLX5_MTR_DOMAIN_EGRESS_BIT   (1 << MLX5_MTR_DOMAIN_EGRESS)
+#define MLX5_MTR_DOMAIN_TRANSFER_BIT (1 << MLX5_MTR_DOMAIN_TRANSFER)
+#define MLX5_MTR_ALL_DOMAIN_BIT      (MLX5_MTR_DOMAIN_INGRESS_BIT | \
+					MLX5_MTR_DOMAIN_EGRESS_BIT | \
+					MLX5_MTR_DOMAIN_TRANSFER_BIT)
+
+/*
+ * Meter sub-policy structure.
+ * Each RSS TIR in meter policy need its own sub-policy resource.
+ */
+struct mlx5_flow_meter_sub_policy {
+	uint32_t main_policy_id:1;
+	/* Main policy id is same as this sub_policy id. */
+	uint32_t idx:31;
+	/* Index to sub_policy ipool entity. */
+	void *main_policy;
+	/* Point to struct mlx5_flow_meter_policy. */
+	struct mlx5_flow_tbl_resource *tbl_rsc;
+	/* The sub-policy table resource. */
+	uint32_t rix_hrxq[MLX5_MTR_RTE_COLORS];
+	/* Index to TIR resource. */
+	struct mlx5_flow_tbl_resource *jump_tbl[MLX5_MTR_RTE_COLORS];
+	/* Meter jump/drop table. */
+	struct mlx5_flow_dv_matcher *color_matcher[RTE_COLORS];
+	/* Matcher for Color. */
+	void *color_rule[RTE_COLORS];
+	/* Meter green/yellow/drop rule. */
+};
+
+struct mlx5_meter_policy_acts {
+	uint8_t actions_n;
+	/* Number of actions. */
+	void *dv_actions[MLX5_DV_MAX_NUMBER_OF_ACTIONS];
+	/* Action list. */
+};
+
+struct mlx5_meter_policy_action_container {
+	uint32_t rix_mark;
+	/* Index to the mark action. */
+	struct mlx5_flow_dv_modify_hdr_resource *modify_hdr;
+	/* Pointer to modify header resource in cache. */
+	uint8_t fate_action;
+	/* Fate action type. */
+	union {
+		struct rte_flow_action *rss;
+		/* Rss action configuration. */
+		uint32_t rix_port_id_action;
+		/* Index to port ID action resource. */
+		void *dr_jump_action[MLX5_MTR_DOMAIN_MAX];
+		/* Jump/drop action per color. */
+	};
+};
+
+/* Flow meter policy parameter structure. */
+struct mlx5_flow_