diff mbox series

[v6,1/2] ethdev: add pre-defined meter policy API

Message ID 20210414085800.2051439-2-lizh@nvidia.com (mailing list archive)
State Superseded
Delegated to: Ferruh Yigit
Headers show
Series Support meter policy API | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Li Zhang April 14, 2021, 8:57 a.m. UTC
Currently, the flow meter policy does not support multiple actions
per color; also the allowed action types per color are very limited.
In addition, the policy cannot be pre-defined.

Due to the growing in flow actions offload abilities there is a potential
for the user to use variety of actions per color differently.
This new meter policy API comes to allow this potential in the most ethdev
common way using rte_flow action definition.
A list of rte_flow actions will be provided by the user per color
in order to create a meter policy.
In addition, the API forces to pre-define the policy before
the meters creation in order to allow sharing of single policy
with multiple meters efficiently.

meter_policy_id is added into struct rte_mtr_params.
So that it can get the policy during the meters creation.

Allow coloring the packet using a new rte_flow_action_color
as could be done by the old policy API.

The next API function were added:
- rte_mtr_meter_policy_create
- rte_mtr_meter_policy_delete
- rte_mtr_meter_policy_update
- rte_mtr_meter_policy_validate
The next struct was changed:
- rte_mtr_params
- rte_mtr_capabilities
The next API was deleted:
- rte_mtr_policer_actions_update

To support this API the following app were changed:
app/test-flow-perf: clean meter policer
app/testpmd: clean meter policer

To support this API the following drivers were changed:
net/softnic: support meter policy API
1. cleans meter rte_mtr_policer_action.
2. Support policy API to get color action as policer action did.
   The color action will be mapped into rte_table_action_policer.

net/mlx5: clean meter creation management
Cleans and breaks part of the current meter management
in order to allow better design with policy API.

Signed-off-by: Li Zhang <lizh@nvidia.com>
Signed-off-by: Haifei Luo <haifeil@nvidia.com>
Signed-off-by: Jiawei Wang <jiaweiw@nvidia.com>
Acked-by: Matan Azrad <matan@nvidia.com>
Acked-by: Ray Kinsella <mdr@ashroe.eu>
---
 app/test-flow-perf/main.c                     |   7 -
 app/test-pmd/cmdline.c                        |   1 -
 app/test-pmd/cmdline_mtr.c                    | 172 -------
 app/test-pmd/cmdline_mtr.h                    |   1 -
 doc/guides/prog_guide/rte_flow.rst            |  21 +
 .../traffic_metering_and_policing.rst         |  16 +-
 doc/guides/rel_notes/release_21_05.rst        |  22 +-
 doc/guides/testpmd_app_ug/testpmd_funcs.rst   |  18 -
 drivers/net/mlx5/mlx5.h                       |  24 +-
 drivers/net/mlx5/mlx5_flow.c                  |  46 --
 drivers/net/mlx5/mlx5_flow.h                  |  18 +-
 drivers/net/mlx5/mlx5_flow_aso.c              |   8 +-
 drivers/net/mlx5/mlx5_flow_dv.c               | 461 +-----------------
 drivers/net/mlx5/mlx5_flow_meter.c            | 369 +-------------
 drivers/net/softnic/rte_eth_softnic_flow.c    |  19 +-
 .../net/softnic/rte_eth_softnic_internals.h   |  18 +-
 drivers/net/softnic/rte_eth_softnic_meter.c   | 264 +++++++---
 lib/librte_ethdev/rte_flow.h                  |  22 +
 lib/librte_ethdev/rte_mtr.c                   |  55 ++-
 lib/librte_ethdev/rte_mtr.h                   | 162 ++++--
 lib/librte_ethdev/rte_mtr_driver.h            |  44 +-
 lib/librte_ethdev/version.map                 |   5 +-
 22 files changed, 515 insertions(+), 1258 deletions(-)

Comments

Dumitrescu, Cristian April 14, 2021, 4:16 p.m. UTC | #1
Hi Li,

Following the API changes, there are lots of changes in the drivers, as expected, so we'll have to take the necessary time to review them.

Here are just a few comments below, please expect more during the next few days.

<snip>

> +
> +/* MTR meter policy add */
> +static int
> +pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
> +	uint32_t meter_policy_id,
> +	struct rte_mtr_meter_policy_params *policy,
> +	struct rte_mtr_error *error)
> +{
> +	struct pmd_internals *p = dev->data->dev_private;
> +	struct softnic_mtr_meter_policy_list *mpl = &p-
> >mtr.meter_policies;
> +	struct softnic_mtr_meter_policy *mp;
> +	const struct rte_flow_action *act;
> +	const struct rte_flow_action_meter_color *recolor;
> +	uint32_t i;
> +
> +	/* Meter policy ID must be valid. */
> +	if (meter_policy_id == UINT32_MAX)
> +		return -rte_mtr_error_set(error,
> +			EINVAL,
> +			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
> +			NULL,
> +			"Meter policy id not valid");

This is obviously not correct, we need to check whether the meter_policy_id provided by the user is already in use (by a policy previously added) or not. You can do this with the policy find function that you have already implemented.

> +
> +	for (i = 0; i < RTE_COLORS; i++) {
> +		act = policy->actions[i];
> +		if (act && act->type !=
> RTE_FLOW_ACTION_TYPE_METER_COLOR &&
> +			act->type != RTE_FLOW_ACTION_TYPE_DROP)
> +			return -rte_mtr_error_set(error,
> +				EINVAL,
> +				RTE_MTR_ERROR_TYPE_METER_POLICY,
> +				NULL,
> +				"Action invalid");
> +	}

This check does not look right either: obviously we cannot accept a null action list for any color, plus the action list should contain only those action types we support (RTE_FLOW_ACTION_TYPE_METER_COLOR or RTE_FLOW_ACTION_TYPE_DROP).

I agree, fist you need to check that the linked list of policy actions for each color is non-NULL, then you need to traverse it until you meet the END action, skip any PAD actions, then check that exactly one (and one only) of METER_COLOR or DROP exist, but not both at the same time, and also we don't have the same action showing up multiple times. Makes sense?

Regards,
Cristian
Singh, Jasvinder April 14, 2021, 10:21 p.m. UTC | #2
<snip>

> +/* MTR meter policy add */
> +static int
> +pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
> +	uint32_t meter_policy_id,
> +	struct rte_mtr_meter_policy_params *policy,
> +	struct rte_mtr_error *error)
> +{
> +	struct pmd_internals *p = dev->data->dev_private;
> +	struct softnic_mtr_meter_policy_list *mpl = &p-
> >mtr.meter_policies;
> +	struct softnic_mtr_meter_policy *mp;
> +	const struct rte_flow_action *act;
> +	const struct rte_flow_action_meter_color *recolor;
> +	uint32_t i;
> +
> +	/* Meter policy ID must be valid. */
> +	if (meter_policy_id == UINT32_MAX)
> +		return -rte_mtr_error_set(error,
> +			EINVAL,
> +			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
> +			NULL,
> +			"Meter policy id not valid");

Add check for "policy",  could be null, before dereferencing this.    


<snip>
> 
> -/* MTR object policer action update */
> +/* MTR object policy update */
>  static int
> -pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
> +pmd_mtr_meter_policy_update(struct rte_eth_dev *dev,
>  	uint32_t mtr_id,
> -	uint32_t action_mask,
> -	enum rte_mtr_policer_action *actions,
> +	uint32_t meter_policy_id,
>  	struct rte_mtr_error *error)
>  {
>  	struct pmd_internals *p = dev->data->dev_private;
>  	struct softnic_mtr *m;
>  	uint32_t i;
>  	int status;
> +	struct softnic_mtr_meter_policy *mp_new, *mp_old;
> 
>  	/* MTR object id must be valid */
>  	m = softnic_mtr_find(p, mtr_id);
> @@ -527,29 +652,14 @@ pmd_mtr_policer_actions_update(struct
> rte_eth_dev *dev,
>  			RTE_MTR_ERROR_TYPE_MTR_ID,
>  			NULL,
>  			"MTR object id not valid");
> -
> -	/* Valid policer actions */
> -	if (actions == NULL)
> +	/* Meter policy must exist */
> +	mp_new = softnic_mtr_meter_policy_find(p, meter_policy_id);
> +	if (mp_new == NULL)
>  		return -rte_mtr_error_set(error,
>  			EINVAL,
> -			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
> +			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
>  			NULL,
> -			"Invalid actions");
> -
> -	for (i = 0; i < RTE_COLORS; i++) {
> -		if (action_mask & (1 << i)) {
> -			if (actions[i] !=
> MTR_POLICER_ACTION_COLOR_GREEN  &&
> -				actions[i] !=
> MTR_POLICER_ACTION_COLOR_YELLOW &&
> -				actions[i] !=
> MTR_POLICER_ACTION_COLOR_RED &&
> -				actions[i] != MTR_POLICER_ACTION_DROP) {
> -				return -rte_mtr_error_set(error,
> -					EINVAL,
> -
> 	RTE_MTR_ERROR_TYPE_UNSPECIFIED,
> -					NULL,
> -					" Invalid action value");
> -			}
> -		}
> -	}
> +			"Meter policy id invalid");

Please add check whether MTR object is already set to meter policy  id,  return success if true, no need to continue.
if (m->params.meter_policy_id == meter_policy_id)
		return 0;

>  	/* MTR object owner valid? */
>  	if (m->flow) {



Regards,
Jasvinder
Li Zhang April 15, 2021, 1:59 a.m. UTC | #3
Thanks Cristian.
Will change it in V7 patch.

Regards,
Li Zhang

> -----Original Message-----
> From: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Sent: Thursday, April 15, 2021 12:16 AM
> To: Li Zhang <lizh@nvidia.com>; dekelp@nvidia.com; Ori Kam
> <orika@nvidia.com>; Slava Ovsiienko <viacheslavo@nvidia.com>; Matan
> Azrad <matan@nvidia.com>; Shahaf Shuler <shahafs@nvidia.com>;
> lironh@marvell.com; jerinj@marvell.com; Yigit, Ferruh
> <ferruh.yigit@intel.com>; ajit.khaparde@broadcom.com; Wisam Monther
> <wisamm@nvidia.com>; Li, Xiaoyun <xiaoyun.li@intel.com>; Singh,
> Jasvinder <jasvinder.singh@intel.com>; NBU-Contact-Thomas Monjalon
> <thomas@monjalon.net>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Neil
> Horman <nhorman@tuxdriver.com>; Jerin Jacob <jerinjacobk@gmail.com>;
> Hemant Agrawal <hemant.agrawal@nxp.com>
> Cc: dev@dpdk.org; Raslan Darawsheh <rasland@nvidia.com>; Roni Bar Yanai
> <roniba@nvidia.com>; Haifei Luo <haifeil@nvidia.com>; Jiawei(Jonny) Wang
> <jiaweiw@nvidia.com>
> Subject: RE: [PATCH v6 1/2] ethdev: add pre-defined meter policy API
> 
> External email: Use caution opening links or attachments
> 
> 
> Hi Li,
> 
> Following the API changes, there are lots of changes in the drivers, as
> expected, so we'll have to take the necessary time to review them.
> 
> Here are just a few comments below, please expect more during the next
> few days.
> 
> <snip>
> 
> > +
> > +/* MTR meter policy add */
> > +static int
> > +pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
> > +     uint32_t meter_policy_id,
> > +     struct rte_mtr_meter_policy_params *policy,
> > +     struct rte_mtr_error *error)
> > +{
> > +     struct pmd_internals *p = dev->data->dev_private;
> > +     struct softnic_mtr_meter_policy_list *mpl = &p-
> > >mtr.meter_policies;
> > +     struct softnic_mtr_meter_policy *mp;
> > +     const struct rte_flow_action *act;
> > +     const struct rte_flow_action_meter_color *recolor;
> > +     uint32_t i;
> > +
> > +     /* Meter policy ID must be valid. */
> > +     if (meter_policy_id == UINT32_MAX)
> > +             return -rte_mtr_error_set(error,
> > +                     EINVAL,
> > +                     RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
> > +                     NULL,
> > +                     "Meter policy id not valid");
> 
> This is obviously not correct, we need to check whether the meter_policy_id
> provided by the user is already in use (by a policy previously added) or not.
> You can do this with the policy find function that you have already
> implemented.
> 
> > +
> > +     for (i = 0; i < RTE_COLORS; i++) {
> > +             act = policy->actions[i];
> > +             if (act && act->type !=
> > RTE_FLOW_ACTION_TYPE_METER_COLOR &&
> > +                     act->type != RTE_FLOW_ACTION_TYPE_DROP)
> > +                     return -rte_mtr_error_set(error,
> > +                             EINVAL,
> > +                             RTE_MTR_ERROR_TYPE_METER_POLICY,
> > +                             NULL,
> > +                             "Action invalid");
> > +     }
> 
> This check does not look right either: obviously we cannot accept a null
> action list for any color, plus the action list should contain only those action
> types we support (RTE_FLOW_ACTION_TYPE_METER_COLOR or
> RTE_FLOW_ACTION_TYPE_DROP).
> 
> I agree, fist you need to check that the linked list of policy actions for each
> color is non-NULL, then you need to traverse it until you meet the END
> action, skip any PAD actions, then check that exactly one (and one only) of
> METER_COLOR or DROP exist, but not both at the same time, and also we
> don't have the same action showing up multiple times. Makes sense?
> 
> Regards,
> Cristian
Li Zhang April 15, 2021, 2 a.m. UTC | #4
Thanks Jasvinder.
Will change it in V7 patch.

Regards,
Li Zhang

> -----Original Message-----
> From: Singh, Jasvinder <jasvinder.singh@intel.com>
> Sent: Thursday, April 15, 2021 6:22 AM
> To: Li Zhang <lizh@nvidia.com>; dekelp@nvidia.com; Ori Kam
> <orika@nvidia.com>; Slava Ovsiienko <viacheslavo@nvidia.com>; Matan
> Azrad <matan@nvidia.com>; Shahaf Shuler <shahafs@nvidia.com>;
> Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; lironh@marvell.com;
> jerinj@marvell.com; Yigit, Ferruh <ferruh.yigit@intel.com>;
> ajit.khaparde@broadcom.com; Wisam Monther <wisamm@nvidia.com>; Li,
> Xiaoyun <xiaoyun.li@intel.com>; NBU-Contact-Thomas Monjalon
> <thomas@monjalon.net>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Neil
> Horman <nhorman@tuxdriver.com>
> Cc: dev@dpdk.org; Raslan Darawsheh <rasland@nvidia.com>; Roni Bar Yanai
> <roniba@nvidia.com>; Haifei Luo <haifeil@nvidia.com>; Jiawei(Jonny) Wang
> <jiaweiw@nvidia.com>
> Subject: RE: [PATCH v6 1/2] ethdev: add pre-defined meter policy API
> 
> External email: Use caution opening links or attachments
> 
> 
> <snip>
> 
> > +/* MTR meter policy add */
> > +static int
> > +pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
> > +     uint32_t meter_policy_id,
> > +     struct rte_mtr_meter_policy_params *policy,
> > +     struct rte_mtr_error *error)
> > +{
> > +     struct pmd_internals *p = dev->data->dev_private;
> > +     struct softnic_mtr_meter_policy_list *mpl = &p-
> > >mtr.meter_policies;
> > +     struct softnic_mtr_meter_policy *mp;
> > +     const struct rte_flow_action *act;
> > +     const struct rte_flow_action_meter_color *recolor;
> > +     uint32_t i;
> > +
> > +     /* Meter policy ID must be valid. */
> > +     if (meter_policy_id == UINT32_MAX)
> > +             return -rte_mtr_error_set(error,
> > +                     EINVAL,
> > +                     RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
> > +                     NULL,
> > +                     "Meter policy id not valid");
> 
> Add check for "policy",  could be null, before dereferencing this.
> 
> 
> <snip>
> >
> > -/* MTR object policer action update */
> > +/* MTR object policy update */
> >  static int
> > -pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
> > +pmd_mtr_meter_policy_update(struct rte_eth_dev *dev,
> >       uint32_t mtr_id,
> > -     uint32_t action_mask,
> > -     enum rte_mtr_policer_action *actions,
> > +     uint32_t meter_policy_id,
> >       struct rte_mtr_error *error)
> >  {
> >       struct pmd_internals *p = dev->data->dev_private;
> >       struct softnic_mtr *m;
> >       uint32_t i;
> >       int status;
> > +     struct softnic_mtr_meter_policy *mp_new, *mp_old;
> >
> >       /* MTR object id must be valid */
> >       m = softnic_mtr_find(p, mtr_id); @@ -527,29 +652,14 @@
> > pmd_mtr_policer_actions_update(struct
> > rte_eth_dev *dev,
> >                       RTE_MTR_ERROR_TYPE_MTR_ID,
> >                       NULL,
> >                       "MTR object id not valid");
> > -
> > -     /* Valid policer actions */
> > -     if (actions == NULL)
> > +     /* Meter policy must exist */
> > +     mp_new = softnic_mtr_meter_policy_find(p, meter_policy_id);
> > +     if (mp_new == NULL)
> >               return -rte_mtr_error_set(error,
> >                       EINVAL,
> > -                     RTE_MTR_ERROR_TYPE_UNSPECIFIED,
> > +                     RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
> >                       NULL,
> > -                     "Invalid actions");
> > -
> > -     for (i = 0; i < RTE_COLORS; i++) {
> > -             if (action_mask & (1 << i)) {
> > -                     if (actions[i] !=
> > MTR_POLICER_ACTION_COLOR_GREEN  &&
> > -                             actions[i] !=
> > MTR_POLICER_ACTION_COLOR_YELLOW &&
> > -                             actions[i] !=
> > MTR_POLICER_ACTION_COLOR_RED &&
> > -                             actions[i] != MTR_POLICER_ACTION_DROP) {
> > -                             return -rte_mtr_error_set(error,
> > -                                     EINVAL,
> > -
> >       RTE_MTR_ERROR_TYPE_UNSPECIFIED,
> > -                                     NULL,
> > -                                     " Invalid action value");
> > -                     }
> > -             }
> > -     }
> > +                     "Meter policy id invalid");
> 
> Please add check whether MTR object is already set to meter policy  id,
> return success if true, no need to continue.
> if (m->params.meter_policy_id == meter_policy_id)
>                 return 0;
> 
> >       /* MTR object owner valid? */
> >       if (m->flow) {
> 
> 
> 
> Regards,
> Jasvinder
diff mbox series

Patch

diff --git a/app/test-flow-perf/main.c b/app/test-flow-perf/main.c
index 8e229679df..9be8edc31d 100644
--- a/app/test-flow-perf/main.c
+++ b/app/test-flow-perf/main.c
@@ -928,13 +928,6 @@  create_meter_rule(int port_id, uint32_t counter)
 
 	/*create meter*/
 	params.meter_profile_id = default_prof_id;
-	params.action[RTE_COLOR_GREEN] =
-		MTR_POLICER_ACTION_COLOR_GREEN;
-	params.action[RTE_COLOR_YELLOW] =
-		MTR_POLICER_ACTION_COLOR_YELLOW;
-	params.action[RTE_COLOR_RED] =
-		MTR_POLICER_ACTION_DROP;
-
 	ret = rte_mtr_create(port_id, counter, &params, 1, &error);
 	if (ret != 0) {
 		printf("Port %u create meter idx(%d) error(%d) message: %s\n",
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 56cf0bf405..0bb6394314 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -17071,7 +17071,6 @@  cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_del_port_meter,
 	(cmdline_parse_inst_t *)&cmd_set_port_meter_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_meter_dscp_table,
-	(cmdline_parse_inst_t *)&cmd_set_port_meter_policer_action,
 	(cmdline_parse_inst_t *)&cmd_set_port_meter_stats_mask,
 	(cmdline_parse_inst_t *)&cmd_show_port_meter_stats,
 	(cmdline_parse_inst_t *)&cmd_mcast_addr,
diff --git a/app/test-pmd/cmdline_mtr.c b/app/test-pmd/cmdline_mtr.c
index 3982787d20..44394e3ea1 100644
--- a/app/test-pmd/cmdline_mtr.c
+++ b/app/test-pmd/cmdline_mtr.c
@@ -146,53 +146,6 @@  parse_meter_color_str(char *c_str, uint32_t *use_prev_meter_color,
 	return 0;
 }
 
-static int
-string_to_policer_action(char *s)
-{
-	if ((strcmp(s, "G") == 0) || (strcmp(s, "g") == 0))
-		return MTR_POLICER_ACTION_COLOR_GREEN;
-
-	if ((strcmp(s, "Y") == 0) || (strcmp(s, "y") == 0))
-		return MTR_POLICER_ACTION_COLOR_YELLOW;
-
-	if ((strcmp(s, "R") == 0) || (strcmp(s, "r") == 0))
-		return MTR_POLICER_ACTION_COLOR_RED;
-
-	if ((strcmp(s, "D") == 0) || (strcmp(s, "d") == 0))
-		return MTR_POLICER_ACTION_DROP;
-
-	return -1;
-}
-
-static int
-parse_policer_action_string(char *p_str, uint32_t action_mask,
-	enum rte_mtr_policer_action actions[])
-{
-	char *token;
-	int count = __builtin_popcount(action_mask);
-	int g_color = 0, y_color = 0, action, i;
-
-	for (i = 0; i < count; i++) {
-		token = strtok_r(p_str, PARSE_DELIMITER, &p_str);
-		if (token ==  NULL)
-			return -1;
-
-		action = string_to_policer_action(token);
-		if (action == -1)
-			return -1;
-
-		if (g_color == 0 && (action_mask & 0x1)) {
-			actions[RTE_COLOR_GREEN] = action;
-			g_color = 1;
-		} else if (y_color == 0 && (action_mask & 0x2)) {
-			actions[RTE_COLOR_YELLOW] = action;
-			y_color = 1;
-		} else
-			actions[RTE_COLOR_RED] = action;
-	}
-	return 0;
-}
-
 static int
 parse_multi_token_string(char *t_str, uint16_t *port_id,
 	uint32_t *mtr_id, enum rte_color **dscp_table)
@@ -302,10 +255,6 @@  static void cmd_show_port_meter_cap_parsed(void *parsed_result,
 		cap.color_aware_trtcm_rfc2698_supported);
 	printf("cap.color_aware_trtcm_rfc4115_supported %" PRId32 "\n",
 		cap.color_aware_trtcm_rfc4115_supported);
-	printf("cap.policer_action_recolor_supported %" PRId32 "\n",
-		cap.policer_action_recolor_supported);
-	printf("cap.policer_action_drop_supported %" PRId32 "\n",
-		cap.policer_action_drop_supported);
 	printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
 }
 
@@ -808,12 +757,6 @@  static void cmd_create_port_meter_parsed(void *parsed_result,
 	else
 		params.meter_enable = 0;
 
-	params.action[RTE_COLOR_GREEN] =
-		string_to_policer_action(res->g_action);
-	params.action[RTE_COLOR_YELLOW] =
-		string_to_policer_action(res->y_action);
-	params.action[RTE_COLOR_RED] =
-		string_to_policer_action(res->r_action);
 	params.stats_mask = res->statistics_mask;
 
 	ret = rte_mtr_create(port_id, mtr_id, &params, shared, &error);
@@ -1181,121 +1124,6 @@  cmdline_parse_inst_t cmd_set_port_meter_dscp_table = {
 	},
 };
 
-/* *** Set Port Meter Policer Action *** */
-struct cmd_set_port_meter_policer_action_result {
-	cmdline_fixed_string_t set;
-	cmdline_fixed_string_t port;
-	cmdline_fixed_string_t meter;
-	cmdline_fixed_string_t policer;
-	cmdline_fixed_string_t action;
-	uint16_t port_id;
-	uint32_t mtr_id;
-	uint32_t action_mask;
-	cmdline_multi_string_t policer_action;
-};
-
-cmdline_parse_token_string_t cmd_set_port_meter_policer_action_set =
-	TOKEN_STRING_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, set, "set");
-cmdline_parse_token_string_t cmd_set_port_meter_policer_action_port =
-	TOKEN_STRING_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, port, "port");
-cmdline_parse_token_string_t cmd_set_port_meter_policer_action_meter =
-	TOKEN_STRING_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, meter,
-		"meter");
-cmdline_parse_token_string_t cmd_set_port_meter_policer_action_policer =
-	TOKEN_STRING_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, policer,
-		"policer");
-cmdline_parse_token_string_t cmd_set_port_meter_policer_action_action =
-	TOKEN_STRING_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, action,
-		"action");
-cmdline_parse_token_num_t cmd_set_port_meter_policer_action_port_id =
-	TOKEN_NUM_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, port_id,
-		RTE_UINT16);
-cmdline_parse_token_num_t cmd_set_port_meter_policer_action_mtr_id =
-	TOKEN_NUM_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, mtr_id,
-		RTE_UINT32);
-cmdline_parse_token_num_t cmd_set_port_meter_policer_action_action_mask =
-	TOKEN_NUM_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result, action_mask,
-		RTE_UINT32);
-cmdline_parse_token_string_t cmd_set_port_meter_policer_action_policer_action =
-	TOKEN_STRING_INITIALIZER(
-		struct cmd_set_port_meter_policer_action_result,
-		policer_action, TOKEN_STRING_MULTI);
-
-static void cmd_set_port_meter_policer_action_parsed(void *parsed_result,
-	__rte_unused struct cmdline *cl,
-	__rte_unused void *data)
-{
-	struct cmd_set_port_meter_policer_action_result *res = parsed_result;
-	enum rte_mtr_policer_action *actions;
-	struct rte_mtr_error error;
-	uint32_t mtr_id = res->mtr_id;
-	uint32_t action_mask = res->action_mask;
-	uint16_t port_id = res->port_id;
-	char *p_str = res->policer_action;
-	int ret;
-
-	if (port_id_is_invalid(port_id, ENABLED_WARN))
-		return;
-
-	/* Check: action mask */
-	if (action_mask == 0 || (action_mask & (~0x7UL))) {
-		printf(" Policer action mask not correct (error)\n");
-		return;
-	}
-
-	/* Allocate memory for policer actions */
-	actions = (enum rte_mtr_policer_action *)malloc(RTE_COLORS *
-		sizeof(enum rte_mtr_policer_action));
-	if (actions == NULL) {
-		printf("Memory for policer actions not allocated (error)\n");
-		return;
-	}
-	/* Parse policer action string */
-	ret = parse_policer_action_string(p_str, action_mask, actions);
-	if (ret) {
-		printf(" Policer action string parse error\n");
-		free(actions);
-		return;
-	}
-
-	ret = rte_mtr_policer_actions_update(port_id, mtr_id,
-		action_mask, actions, &error);
-	if (ret != 0) {
-		free(actions);
-		print_err_msg(&error);
-		return;
-	}
-
-	free(actions);
-}
-
-cmdline_parse_inst_t cmd_set_port_meter_policer_action = {
-	.f = cmd_set_port_meter_policer_action_parsed,
-	.data = NULL,
-	.help_str = "set port meter policer action <port_id> <mtr_id> "
-		"<action_mask> <action0> [<action1> <action2>]",
-	.tokens = {
-		(void *)&cmd_set_port_meter_policer_action_set,
-		(void *)&cmd_set_port_meter_policer_action_port,
-		(void *)&cmd_set_port_meter_policer_action_meter,
-		(void *)&cmd_set_port_meter_policer_action_policer,
-		(void *)&cmd_set_port_meter_policer_action_action,
-		(void *)&cmd_set_port_meter_policer_action_port_id,
-		(void *)&cmd_set_port_meter_policer_action_mtr_id,
-		(void *)&cmd_set_port_meter_policer_action_action_mask,
-		(void *)&cmd_set_port_meter_policer_action_policer_action,
-		NULL,
-	},
-};
-
 /* *** Set Port Meter Stats Mask *** */
 struct cmd_set_port_meter_stats_mask_result {
 	cmdline_fixed_string_t set;
diff --git a/app/test-pmd/cmdline_mtr.h b/app/test-pmd/cmdline_mtr.h
index e69d6da023..7e2713cea3 100644
--- a/app/test-pmd/cmdline_mtr.h
+++ b/app/test-pmd/cmdline_mtr.h
@@ -17,7 +17,6 @@  extern cmdline_parse_inst_t cmd_disable_port_meter;
 extern cmdline_parse_inst_t cmd_del_port_meter;
 extern cmdline_parse_inst_t cmd_set_port_meter_profile;
 extern cmdline_parse_inst_t cmd_set_port_meter_dscp_table;
-extern cmdline_parse_inst_t cmd_set_port_meter_policer_action;
 extern cmdline_parse_inst_t cmd_set_port_meter_stats_mask;
 extern cmdline_parse_inst_t cmd_show_port_meter_stats;
 
diff --git a/doc/guides/prog_guide/rte_flow.rst b/doc/guides/prog_guide/rte_flow.rst
index e1b93ecedf..2f5a6e0c31 100644
--- a/doc/guides/prog_guide/rte_flow.rst
+++ b/doc/guides/prog_guide/rte_flow.rst
@@ -2841,6 +2841,27 @@  for ``RTE_FLOW_FIELD_VALUE`` and ``RTE_FLOW_FIELD_POINTER`` respectively.
    | ``value``     | immediate value or a pointer to this value               |
    +---------------+----------------------------------------------------------+
 
+Action: ``METER_COLOR``
+^^^^^^^^^^^^^^^^^^^^^^^
+
+Color the packet to reflect the meter color result.
+
+The meter action must be configured before meter color action.
+Meter color action is set to a color to reflect the meter color result.
+Set the meter color in the mbuf to the selected color.
+The meter color action output color is the output color of the packet,
+which is set in the packet meta-data (i.e. struct ``rte_mbuf::sched::color``)
+
+.. _table_rte_flow_action_meter_color:
+
+.. table:: METER_COLOR
+
+   +-----------------+--------------+
+   | Field           | Value        |
+   +=================+==============+
+   | ``meter_color`` | Packet color |
+   +-----------------+--------------+
+
 Negative types
 ~~~~~~~~~~~~~~
 
diff --git a/doc/guides/prog_guide/traffic_metering_and_policing.rst b/doc/guides/prog_guide/traffic_metering_and_policing.rst
index 90c781eb1d..c0537e653c 100644
--- a/doc/guides/prog_guide/traffic_metering_and_policing.rst
+++ b/doc/guides/prog_guide/traffic_metering_and_policing.rst
@@ -56,18 +56,10 @@  The processing done for each input packet hitting an MTR object is:
   color blind mode, which is equivalent to considering all input packets
   initially colored as green.
 
-* Policing: There is a separate policer action configured for each meter
-  output color, which can:
-
-  * Drop the packet.
-
-  * Keep the same packet color: the policer output color matches the meter
-    output color (essentially a no-op action).
-
-  * Recolor the packet: the policer output color is set to a different color
-    than the meter output color. The policer output color is the output color
-    of the packet, which is set in the packet meta-data (i.e. struct
-    ``rte_mbuf::sched::color``).
+* There is a meter policy API to manage pre-defined policies for meter.
+  Any rte_flow action list can be configured per color for each policy.
+  A meter object configured with a policy executes the actions per packet
+  according to the packet color.
 
 * Statistics: The set of counters maintained for each MTR object is
   configurable and subject to the implementation support. This set includes
diff --git a/doc/guides/rel_notes/release_21_05.rst b/doc/guides/rel_notes/release_21_05.rst
index a0b907994a..5c4617d236 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -174,7 +174,27 @@  New Features
     ``dpdk-testpmd -- --eth-link-speed N``
   * Added command to display Rx queue used descriptor count.
     ``show port (port_id) rxq (queue_id) desc used count``
-
+  * deleted the port meter policer action command .
+    ``set port meter policer action (port_id) (mtr_id) (action_mask) ...``
+  * Added command to create meter policy.
+    ``add port meter policy (port_id) (policy_id) g_actions {action} end y_actions {action} end r_actions {action} end``
+  * Added command to delete meter policy.
+    ``del port meter policy (port_id) (policy_id)``
+
+* **Updated meter API.**
+
+  * ethdev: Deleted meter policer API to support policy API.
+    ``rte_mtr_policer_actions_update()``
+  * ethdev: Added meter API to support pre-defined policy, rte_flow action list per color.
+    ``rte_mtr_meter_policy_add()``, ``rte_mtr_meter_policy_delete()`` and
+    ``rte_mtr_create_with_policy()``
+  * ethdev: Removed rte_mtr_policer_action from rte_mtr_params structures.
+  * ethdev: Added rte_mtr_meter_policy_params structures to support policy API.
+  * ethdev: Added meter_policy_id into rte_mtr_params structures.
+  * ethdev: Removed policer_action_recolor_supported and policer_action_drop_supported from rte_mtr_capabilities structures.
+  * ethdev: Added meter_policy_n_max into rte_mtr_capabilities structures.
+  * ethdev: Added RTE_FLOW_ACTION_TYPE_METER_COLOR in enum rte_flow_action_type.
+  * ethdev: Added RTE_MTR_ERROR_TYPE_METER_POLICY_ID and RTE_MTR_ERROR_TYPE_METER_POLICY_ID into rte_mtr_error_type.
 
 Removed Items
 -------------
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 36f0a328a5..3f7a1c0e33 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2830,24 +2830,6 @@  Set meter dscp table for the ethernet device::
    testpmd> set port meter dscp table (port_id) (mtr_id) [(dscp_tbl_entry0) \
    (dscp_tbl_entry1)...(dscp_tbl_entry63)]
 
-set port meter policer action
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Set meter policer action for the ethernet device::
-
-   testpmd> set port meter policer action (port_id) (mtr_id) (action_mask) \
-   (action0) [(action1) (action1)]
-
-where:
-
-* ``action_mask``: Bit mask indicating which policer actions need to be
-  updated. One or more policer actions can be updated in a single function
-  invocation. To update the policer action associated with color C, bit
-  (1 << C) needs to be set in *action_mask* and element at position C
-  in the *actions* array needs to be valid.
-* ``actionx``: Policer action for the color x,
-  RTE_MTR_GREEN <= x < RTE_MTR_COLORS
-
 set port meter stats mask
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/drivers/net/mlx5/mlx5.h b/drivers/net/mlx5/mlx5.h
index 9a02aa4488..a8e11023cc 100644
--- a/drivers/net/mlx5/mlx5.h
+++ b/drivers/net/mlx5/mlx5.h
@@ -584,14 +584,6 @@  struct mlx5_dev_shared_port {
 /* Modify this value if enum rte_mtr_color changes. */
 #define RTE_MTR_DROPPED RTE_COLORS
 
-/* Meter policer statistics */
-struct mlx5_flow_policer_stats {
-	uint32_t pass_cnt;
-	/**< Color counter for pass. */
-	uint32_t drop_cnt;
-	/**< Color counter for drop. */
-};
-
 /* Meter table structure. */
 struct mlx5_meter_domain_info {
 	struct mlx5_flow_tbl_resource *tbl;
@@ -630,24 +622,12 @@  struct mlx5_meter_domains_infos {
 
 /* Meter parameter structure. */
 struct mlx5_flow_meter_info {
-	uint32_t meter_id;
-	/**< Meter id. */
 	struct mlx5_flow_meter_profile *profile;
 	/**< Meter profile parameters. */
 	rte_spinlock_t sl; /**< Meter action spinlock. */
-	/** Policer actions (per meter output color). */
-	enum rte_mtr_policer_action action[RTE_COLORS];
 	/** Set of stats counters to be enabled.
 	 * @see enum rte_mtr_stats_type
 	 */
-	uint32_t green_bytes:1;
-	/** Set green bytes stats to be enabled. */
-	uint32_t green_pkts:1;
-	/** Set green packets stats to be enabled. */
-	uint32_t red_bytes:1;
-	/** Set red bytes stats to be enabled. */
-	uint32_t red_pkts:1;
-	/** Set red packets stats to be enabled. */
 	uint32_t bytes_dropped:1;
 	/** Set bytes dropped stats to be enabled. */
 	uint32_t pkts_dropped:1;
@@ -682,8 +662,8 @@  struct mlx5_flow_meter_info {
 	uint32_t transfer:1;
 	struct mlx5_meter_domains_infos *mfts;
 	/**< Flow table created for this meter. */
-	struct mlx5_flow_policer_stats policer_stats;
-	/**< Meter policer statistics. */
+	uint32_t drop_cnt;
+	/**< Color counter for drop. */
 	uint32_t ref_cnt;
 	/**< Use count. */
 	struct mlx5_indexed_pool *flow_ipool;
diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c
index 242c6f2288..ee2c351649 100644
--- a/drivers/net/mlx5/mlx5_flow.c
+++ b/drivers/net/mlx5/mlx5_flow.c
@@ -6647,52 +6647,6 @@  mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev,
 	return fops->destroy_mtr_tbls(dev, tbls);
 }
 
-/**
- * Prepare policer rules.
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[in] fm
- *   Pointer to flow meter structure.
- * @param[in] attr
- *   Pointer to flow attributes.
- *
- * @return
- *   0 on success, -1 otherwise.
- */
-int
-mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,
-			       struct mlx5_flow_meter_info *fm,
-			       const struct rte_flow_attr *attr)
-{
-	const struct mlx5_flow_driver_ops *fops;
-
-	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->prepare_policer_rules(dev, fm, attr);
-}
-
-/**
- * Destroy policer rules.
- *
- * @param[in] fm
- *   Pointer to flow meter structure.
- * @param[in] attr
- *   Pointer to flow attributes.
- *
- * @return
- *   0 on success, -1 otherwise.
- */
-int
-mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
-				struct mlx5_flow_meter_info *fm,
-				const struct rte_flow_attr *attr)
-{
-	const struct mlx5_flow_driver_ops *fops;
-
-	fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
-	return fops->destroy_policer_rules(dev, fm, attr);
-}
-
 /**
  * Allocate the needed aso flow meter id.
  *
diff --git a/drivers/net/mlx5/mlx5_flow.h b/drivers/net/mlx5/mlx5_flow.h
index cb2803d080..7fa15eef7b 100644
--- a/drivers/net/mlx5/mlx5_flow.h
+++ b/drivers/net/mlx5/mlx5_flow.h
@@ -839,6 +839,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. */
 };
 
@@ -1097,14 +1099,6 @@  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_policer_rules_t)
-					(struct rte_eth_dev *dev,
-					 struct mlx5_flow_meter_info *fm,
-					 const struct rte_flow_attr *attr);
-typedef int (*mlx5_flow_destroy_policer_rules_t)
-					(struct rte_eth_dev *dev,
-					 const struct mlx5_flow_meter_info *fm,
-					 const struct rte_flow_attr *attr);
 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,
@@ -1161,8 +1155,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_create_policer_rules_t prepare_policer_rules;
-	mlx5_flow_destroy_policer_rules_t destroy_policer_rules;
 	mlx5_flow_mtr_alloc_t create_meter;
 	mlx5_flow_mtr_free_t free_meter;
 	mlx5_flow_counter_alloc_t counter_alloc;
@@ -1392,12 +1384,6 @@  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_prepare_policer_rules(struct rte_eth_dev *dev,
-				   struct mlx5_flow_meter_info *fm,
-				   const struct rte_flow_attr *attr);
-int mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
-				    struct mlx5_flow_meter_info *fm,
-				    const struct rte_flow_attr *attr);
 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_aso.c b/drivers/net/mlx5/mlx5_flow_aso.c
index cd2cc016b9..62d2df054b 100644
--- a/drivers/net/mlx5/mlx5_flow_aso.c
+++ b/drivers/net/mlx5/mlx5_flow_aso.c
@@ -808,8 +808,8 @@  mlx5_aso_meter_update_by_wqe(struct mlx5_dev_ctx_shared *sh,
 		/* Waiting for wqe resource. */
 		rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
 	} while (--poll_wqe_times);
-	DRV_LOG(ERR, "Fail to send WQE for ASO meter %d",
-			mtr->fm.meter_id);
+	DRV_LOG(ERR, "Fail to send WQE for ASO meter offset %d",
+			mtr->offset);
 	return -1;
 }
 
@@ -844,7 +844,7 @@  mlx5_aso_mtr_wait(struct mlx5_dev_ctx_shared *sh,
 		/* Waiting for CQE ready. */
 		rte_delay_us_sleep(MLX5_ASO_WQE_CQE_RESPONSE_DELAY);
 	} while (--poll_cqe_times);
-	DRV_LOG(ERR, "Fail to poll CQE ready for ASO meter %d",
-			mtr->fm.meter_id);
+	DRV_LOG(ERR, "Fail to poll CQE ready for ASO meter offset %d",
+			mtr->offset);
 	return -1;
 }
diff --git a/drivers/net/mlx5/mlx5_flow_dv.c b/drivers/net/mlx5/mlx5_flow_dv.c
index d8ea440668..af3397fb55 100644
--- a/drivers/net/mlx5/mlx5_flow_dv.c
+++ b/drivers/net/mlx5/mlx5_flow_dv.c
@@ -184,31 +184,6 @@  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. */
@@ -6025,12 +6000,10 @@  flow_dv_mtr_pool_create(struct rte_eth_dev *dev,
 	mtrmng->n_valid++;
 	for (i = 1; i < MLX5_ASO_MTRS_PER_POOL; ++i) {
 		pool->mtrs[i].offset = i;
-		pool->mtrs[i].fm.meter_id = UINT32_MAX;
 		LIST_INSERT_HEAD(&mtrmng->meters,
 						&pool->mtrs[i], next);
 	}
 	pool->mtrs[0].offset = 0;
-	pool->mtrs[0].fm.meter_id = UINT32_MAX;
 	*mtr_free = &pool->mtrs[0];
 	return pool;
 }
@@ -6054,7 +6027,6 @@  flow_dv_aso_mtr_release_to_pool(struct rte_eth_dev *dev, uint32_t mtr_idx)
 	rte_spinlock_lock(&mtrmng->mtrsl);
 	memset(&aso_mtr->fm, 0, sizeof(struct mlx5_flow_meter_info));
 	aso_mtr->state = ASO_METER_FREE;
-	aso_mtr->fm.meter_id = UINT32_MAX;
 	LIST_INSERT_HEAD(&mtrmng->meters, aso_mtr, next);
 	rte_spinlock_unlock(&mtrmng->mtrsl);
 }
@@ -6094,8 +6066,8 @@  flow_dv_mtr_alloc(struct rte_eth_dev *dev)
 	mtr_free->state = ASO_METER_WAIT;
 	rte_spinlock_unlock(&mtrmng->mtrsl);
 	pool = container_of(mtr_free,
-					struct mlx5_aso_mtr_pool,
-					mtrs[mtr_free->offset]);
+			struct mlx5_aso_mtr_pool,
+			mtrs[mtr_free->offset]);
 	mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, mtr_free->offset);
 	if (!mtr_free->fm.meter_action) {
 #ifdef HAVE_MLX5_DR_CREATE_ACTION_ASO
@@ -13702,433 +13674,6 @@  flow_dv_create_mtr_tbl(struct rte_eth_dev *dev)
 	return NULL;
 }
 
-/**
- * Destroy the meter table matchers.
- * Lock free, (mutex should be acquired by caller).
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[in,out] dtb
- *   Pointer to DV meter table.
- *
- * @return
- *   Always 0.
- */
-static int
-flow_dv_destroy_mtr_matchers(struct rte_eth_dev *dev,
-			     struct mlx5_meter_domain_info *dtb)
-{
-	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_tbl_data_entry *tbl;
-
-	if (!priv->config.dv_flow_en)
-		return 0;
-	if (dtb->drop_matcher) {
-		tbl = container_of(dtb->drop_matcher->tbl, typeof(*tbl), tbl);
-		mlx5_cache_unregister(&tbl->matchers,
-				      &dtb->drop_matcher->entry);
-		dtb->drop_matcher = NULL;
-	}
-	if (dtb->color_matcher) {
-		tbl = container_of(dtb->color_matcher->tbl, typeof(*tbl), tbl);
-		mlx5_cache_unregister(&tbl->matchers,
-				      &dtb->color_matcher->entry);
-		dtb->color_matcher = NULL;
-	}
-	return 0;
-}
-
-/**
- * Create the matchers for meter table.
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[in] color_reg_c_idx
- *   Reg C index for color match.
- * @param[in] mtr_id_reg_c_idx
- *   Reg C index for meter_id match.
- * @param[in] mtr_id_mask
- *   Mask for meter_id match criteria.
- * @param[in,out] dtb
- *   Pointer to DV meter table.
- * @param[out] error
- *   Perform verbose error reporting if not NULL.
- *
- * @return
- *   0 on success, a negative errno value otherwise and rte_errno is set.
- */
-static int
-flow_dv_prepare_mtr_matchers(struct rte_eth_dev *dev,
-			     uint32_t color_reg_c_idx,
-			     uint32_t mtr_id_reg_c_idx,
-			     uint32_t mtr_id_mask,
-			     struct mlx5_meter_domain_info *dtb,
-			     struct rte_flow_error *error)
-{
-	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_tbl_data_entry *tbl_data;
-	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),
-		},
-		.tbl = dtb->tbl,
-	};
-	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,
-	};
-	uint32_t color_mask = (UINT32_C(1) << MLX5_MTR_COLOR_BITS) - 1;
-
-	tbl_data = container_of(dtb->tbl, struct mlx5_flow_tbl_data_entry, tbl);
-	if (!dtb->drop_matcher) {
-		/* Create matchers for Drop. */
-		flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
-				       mtr_id_reg_c_idx, 0, mtr_id_mask);
-		matcher.priority = MLX5_REG_BITS * 2 - priv->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.");
-			return -1;
-		}
-		dtb->drop_matcher =
-			container_of(entry, struct mlx5_flow_dv_matcher, entry);
-	}
-	if (!dtb->color_matcher) {
-		/* Create matchers for Color + meter_id. */
-		if (priv->mtr_reg_share) {
-			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
-					color_reg_c_idx, 0,
-					(mtr_id_mask | color_mask));
-		} else {
-			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
-					color_reg_c_idx, 0, color_mask);
-			flow_dv_match_meta_reg(matcher.mask.buf, value.buf,
-					mtr_id_reg_c_idx, 0, mtr_id_mask);
-		}
-		matcher.priority = MLX5_REG_BITS - priv->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 color matcher.");
-			return -1;
-		}
-		dtb->color_matcher =
-			container_of(entry, struct mlx5_flow_dv_matcher, entry);
-	}
-	return 0;
-}
-
-/**
- * Destroy domain policer rule.
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[in] dt
- *   Pointer to domain table.
- */
-static void
-flow_dv_destroy_domain_policer_rule(struct rte_eth_dev *dev,
-				    struct mlx5_meter_domain_info *dt)
-{
-	if (dt->drop_rule) {
-		claim_zero(mlx5_flow_os_destroy_flow(dt->drop_rule));
-		dt->drop_rule = NULL;
-	}
-	if (dt->green_rule) {
-		claim_zero(mlx5_flow_os_destroy_flow(dt->green_rule));
-		dt->green_rule = NULL;
-	}
-	flow_dv_destroy_mtr_matchers(dev, dt);
-	if (dt->jump_actn) {
-		claim_zero(mlx5_flow_os_destroy_flow_action(dt->jump_actn));
-		dt->jump_actn = NULL;
-	}
-}
-
-/**
- * Destroy policer rules.
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[in] fm
- *   Pointer to flow meter structure.
- * @param[in] attr
- *   Pointer to flow attributes.
- *
- * @return
- *   Always 0.
- */
-static int
-flow_dv_destroy_policer_rules(struct rte_eth_dev *dev,
-			      const struct mlx5_flow_meter_info *fm,
-			      const struct rte_flow_attr *attr)
-{
-	struct mlx5_meter_domains_infos *mtb = fm ? fm->mfts : NULL;
-
-	if (!mtb)
-		return 0;
-	if (attr->egress)
-		flow_dv_destroy_domain_policer_rule(dev, &mtb->egress);
-	if (attr->ingress)
-		flow_dv_destroy_domain_policer_rule(dev, &mtb->ingress);
-	if (attr->transfer)
-		flow_dv_destroy_domain_policer_rule(dev, &mtb->transfer);
-	return 0;
-}
-
-/**
- * Create specify domain meter policer rule.
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[in] fm
- *   Pointer to flow meter structure.
- * @param[in] mtr_idx
- *   meter index.
- * @param[in] mtb
- *   Pointer to DV meter table set.
- * @param[out] drop_rule
- *   The address of pointer saving drop rule.
- * @param[out] color_rule
- *   The address of pointer saving green rule.
- *
- * @return
- *   0 on success, -1 otherwise.
- */
-static int
-flow_dv_create_policer_forward_rule(struct rte_eth_dev *dev,
-				    struct mlx5_flow_meter_info *fm,
-				    uint32_t mtr_idx,
-				    struct mlx5_meter_domain_info *dtb,
-				    void **drop_rule,
-				    void **green_rule)
-{
-	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_flow_dv_match_params matcher = {
-		.size = sizeof(matcher.buf) -
-			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
-	};
-	struct mlx5_flow_dv_match_params value = {
-		.size = sizeof(value.buf) -
-			MLX5_ST_SZ_BYTES(fte_match_set_misc4),
-	};
-	struct mlx5_meter_domains_infos *mtb = fm->mfts;
-	struct rte_flow_error error;
-	uint32_t color_reg_c = mlx5_flow_get_reg_id(dev, MLX5_MTR_COLOR,
-						    0, &error);
-	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;
-	uint32_t mtr_id_mask =
-		((UINT32_C(1) << priv->max_mtr_bits) - 1) << mtr_id_offset;
-	void *actions[METER_ACTIONS];
-	int i;
-	int ret = 0;
-
-	/* Create jump action. */
-	if (!dtb->jump_actn)
-		ret = mlx5_flow_os_create_flow_action_dest_flow_tbl
-				(dtb->sfx_tbl->obj, &dtb->jump_actn);
-	if (ret) {
-		DRV_LOG(ERR, "Failed to create policer jump action.");
-		goto error;
-	}
-	/* Prepare matchers. */
-	if (!dtb->drop_matcher || !dtb->color_matcher) {
-		ret = flow_dv_prepare_mtr_matchers(dev, color_reg_c,
-						   mtr_id_reg_c, mtr_id_mask,
-						   dtb, &error);
-		if (ret) {
-			DRV_LOG(ERR, "Failed to setup matchers for mtr table.");
-			goto error;
-		}
-	}
-	/* Create Drop flow, matching meter_id only. */
-	i = 0;
-	flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,
-			       (mtr_idx << mtr_id_offset), UINT32_MAX);
-	if (mtb->drop_count)
-		actions[i++] = mtb->drop_count;
-	actions[i++] = priv->sh->dr_drop_action;
-	ret = mlx5_flow_os_create_flow(dtb->drop_matcher->matcher_object,
-				       (void *)&value, i, actions, drop_rule);
-	if (ret) {
-		DRV_LOG(ERR, "Failed to create meter policer drop rule.");
-		goto error;
-	}
-	/* Create flow matching Green color + meter_id. */
-	i = 0;
-	if (priv->mtr_reg_share) {
-		flow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c,
-				       ((mtr_idx << mtr_id_offset) |
-					rte_col_2_mlx5_col(RTE_COLOR_GREEN)),
-				       UINT32_MAX);
-	} else {
-		flow_dv_match_meta_reg(matcher.buf, value.buf, color_reg_c,
-				       rte_col_2_mlx5_col(RTE_COLOR_GREEN),
-				       UINT32_MAX);
-		flow_dv_match_meta_reg(matcher.buf, value.buf, mtr_id_reg_c,
-				       mtr_idx, UINT32_MAX);
-	}
-	if (mtb->green_count)
-		actions[i++] = mtb->green_count;
-	actions[i++] = dtb->jump_actn;
-	ret = mlx5_flow_os_create_flow(dtb->color_matcher->matcher_object,
-				       (void *)&value, i, actions, green_rule);
-	if (ret) {
-		DRV_LOG(ERR, "Failed to create meter policer color rule.");
-		goto error;
-	}
-	return 0;
-error:
-	rte_errno = errno;
-	return -1;
-}
-
-/**
- * Prepare policer rules for all domains.
- * If meter already initialized, this will replace all old rules with new ones.
- *
- * @param[in] dev
- *   Pointer to Ethernet device.
- * @param[in] fm
- *   Pointer to flow meter structure.
- * @param[in] attr
- *   Pointer to flow attributes.
- *
- * @return
- *   0 on success, -1 otherwise.
- */
-static int
-flow_dv_prepare_policer_rules(struct rte_eth_dev *dev,
-			      struct mlx5_flow_meter_info *fm,
-			      const struct rte_flow_attr *attr)
-{
-	struct mlx5_priv *priv = dev->data->dev_private;
-	struct mlx5_meter_domains_infos *mtb = fm->mfts;
-	bool initialized = false;
-	struct mlx5_flow_counter *cnt;
-	void *egress_drop_rule = NULL;
-	void *egress_green_rule = NULL;
-	void *ingress_drop_rule = NULL;
-	void *ingress_green_rule = NULL;
-	void *transfer_drop_rule = NULL;
-	void *transfer_green_rule = NULL;
-	uint32_t mtr_idx;
-	int ret;
-
-	/* Get the statistics counters for green/drop. */
-	if (fm->policer_stats.pass_cnt) {
-		cnt = flow_dv_counter_get_by_idx(dev,
-					fm->policer_stats.pass_cnt,
-					NULL);
-		mtb->green_count = cnt->action;
-	} else {
-		mtb->green_count = NULL;
-	}
-	if (fm->policer_stats.drop_cnt) {
-		cnt = flow_dv_counter_get_by_idx(dev,
-					fm->policer_stats.drop_cnt,
-					NULL);
-		mtb->drop_count = cnt->action;
-	} else {
-		mtb->drop_count = NULL;
-	}
-	/**
-	 * If flow meter has been initialized, all policer rules
-	 * are created. So can get if meter initialized by checking
-	 * any policer rule.
-	 */
-	if (mtb->egress.drop_rule)
-		initialized = true;
-	if (priv->sh->meter_aso_en) {
-		struct mlx5_aso_mtr *aso_mtr = NULL;
-		struct mlx5_aso_mtr_pool *pool;
-
-		aso_mtr = container_of(fm, struct mlx5_aso_mtr, fm);
-		pool = container_of(aso_mtr, struct mlx5_aso_mtr_pool,
-				    mtrs[aso_mtr->offset]);
-		mtr_idx = MLX5_MAKE_MTR_IDX(pool->index, aso_mtr->offset);
-	} else {
-		struct mlx5_legacy_flow_meter *legacy_fm;
-
-		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
-		mtr_idx = legacy_fm->idx;
-	}
-	if (attr->egress) {
-		ret = flow_dv_create_policer_forward_rule(dev,
-				fm, mtr_idx, &mtb->egress,
-				&egress_drop_rule, &egress_green_rule);
-		if (ret) {
-			DRV_LOG(ERR, "Failed to create egress policer.");
-			goto error;
-		}
-	}
-	if (attr->ingress) {
-		ret = flow_dv_create_policer_forward_rule(dev,
-				fm, mtr_idx, &mtb->ingress,
-				&ingress_drop_rule, &ingress_green_rule);
-		if (ret) {
-			DRV_LOG(ERR, "Failed to create ingress policer.");
-			goto error;
-		}
-	}
-	if (attr->transfer) {
-		ret = flow_dv_create_policer_forward_rule(dev,
-				fm, mtr_idx, &mtb->transfer,
-				&transfer_drop_rule, &transfer_green_rule);
-		if (ret) {
-			DRV_LOG(ERR, "Failed to create transfer policer.");
-			goto error;
-		}
-	}
-	/* Replace old flows if existing. */
-	if (mtb->egress.drop_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(mtb->egress.drop_rule));
-	if (mtb->egress.green_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(mtb->egress.green_rule));
-	if (mtb->ingress.drop_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(mtb->ingress.drop_rule));
-	if (mtb->ingress.green_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(mtb->ingress.green_rule));
-	if (mtb->transfer.drop_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(mtb->transfer.drop_rule));
-	if (mtb->transfer.green_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(mtb->transfer.green_rule));
-	mtb->egress.drop_rule = egress_drop_rule;
-	mtb->egress.green_rule = egress_green_rule;
-	mtb->ingress.drop_rule = ingress_drop_rule;
-	mtb->ingress.green_rule = ingress_green_rule;
-	mtb->transfer.drop_rule = transfer_drop_rule;
-	mtb->transfer.green_rule = transfer_green_rule;
-	return 0;
-error:
-	if (egress_drop_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(egress_drop_rule));
-	if (egress_green_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(egress_green_rule));
-	if (ingress_drop_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(ingress_drop_rule));
-	if (ingress_green_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(ingress_green_rule));
-	if (transfer_drop_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(transfer_drop_rule));
-	if (transfer_green_rule)
-		claim_zero(mlx5_flow_os_destroy_flow(transfer_green_rule));
-	if (!initialized)
-		flow_dv_destroy_policer_rules(dev, fm, attr);
-	return -1;
-}
-
 /**
  * Validate the batch counter support in root table.
  *
@@ -14423,8 +13968,6 @@  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,
-	.prepare_policer_rules = flow_dv_prepare_policer_rules,
-	.destroy_policer_rules = flow_dv_destroy_policer_rules,
 	.create_meter = flow_dv_mtr_alloc,
 	.free_meter = flow_dv_aso_mtr_release_to_pool,
 	.counter_alloc = flow_dv_counter_allocate,
diff --git a/drivers/net/mlx5/mlx5_flow_meter.c b/drivers/net/mlx5/mlx5_flow_meter.c
index 714b382d55..af0a1c18cb 100644
--- a/drivers/net/mlx5/mlx5_flow_meter.c
+++ b/drivers/net/mlx5/mlx5_flow_meter.c
@@ -329,7 +329,6 @@  mlx5_flow_mtr_cap_get(struct rte_eth_dev *dev,
 	cap->chaining_n_mtrs_per_flow_max = 1; /* Chaining is not supported. */
 	cap->meter_srtcm_rfc2697_n_max = qattr->flow_meter_old ? cap->n_max : 0;
 	cap->meter_rate_max = 1ULL << 40; /* 1 Tera tokens per sec. */
-	cap->policer_action_drop_supported = 1;
 	cap->stats_mask = RTE_MTR_STATS_N_BYTES_DROPPED |
 			  RTE_MTR_STATS_N_PKTS_DROPPED;
 	return 0;
@@ -436,90 +435,6 @@  mlx5_flow_meter_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
-/**
- * Convert wrong color setting action to verbose error.
- *
- * @param[in] action
- *   Policy color action.
- *
- * @return
- *   Verbose meter color error type.
- */
-static inline enum rte_mtr_error_type
-action2error(enum rte_mtr_policer_action action)
-{
-	switch (action) {
-	case MTR_POLICER_ACTION_COLOR_GREEN:
-		return RTE_MTR_ERROR_TYPE_POLICER_ACTION_GREEN;
-	case MTR_POLICER_ACTION_COLOR_YELLOW:
-		return RTE_MTR_ERROR_TYPE_POLICER_ACTION_YELLOW;
-	case MTR_POLICER_ACTION_COLOR_RED:
-		return RTE_MTR_ERROR_TYPE_POLICER_ACTION_RED;
-	default:
-		break;
-	}
-	return RTE_MTR_ERROR_TYPE_UNSPECIFIED;
-}
-
-/**
- * Check meter validation.
- *
- * @param[in] priv
- *   Pointer to mlx5 private data structure.
- * @param[in] meter_id
- *   Meter id.
- * @param[in] params
- *   Pointer to rte meter parameters.
- * @param[out] error
- *   Pointer to rte meter error structure.
- *
- * @return
- *   0 on success, a negative errno value otherwise and rte_errno is set.
- */
-static int
-mlx5_flow_meter_validate(struct mlx5_priv *priv, uint32_t meter_id,
-			 struct rte_mtr_params *params,
-			 struct rte_mtr_error *error)
-{
-	/* 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.");
-	/* Validate policer settings. */
-	if (params->action[RTE_COLOR_RED] != MTR_POLICER_ACTION_DROP)
-		return -rte_mtr_error_set
-				(error, ENOTSUP,
-				 action2error(params->action[RTE_COLOR_RED]),
-				 NULL,
-				 "Red color only supports drop action.");
-	if (params->action[RTE_COLOR_GREEN] != MTR_POLICER_ACTION_COLOR_GREEN)
-		return -rte_mtr_error_set
-				(error, ENOTSUP,
-				 action2error(params->action[RTE_COLOR_GREEN]),
-				 NULL,
-				 "Green color only supports recolor green action.");
-	/* 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.
  *
@@ -629,167 +544,14 @@  static void
 mlx5_flow_meter_stats_enable_update(struct mlx5_flow_meter_info *fm,
 				uint64_t stats_mask)
 {
-	fm->green_bytes = (stats_mask & RTE_MTR_STATS_N_BYTES_GREEN) ? 1 : 0;
-	fm->green_pkts = (stats_mask & RTE_MTR_STATS_N_PKTS_GREEN) ? 1 : 0;
-	fm->red_bytes = (stats_mask & RTE_MTR_STATS_N_BYTES_RED) ? 1 : 0;
-	fm->red_pkts = (stats_mask & RTE_MTR_STATS_N_PKTS_RED) ? 1 : 0;
 	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;
 }
 
-/**
- * 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_legacy_flow_meter *legacy_fm;
-	struct mlx5_flow_meter_info *fm;
-	const struct rte_flow_attr attr = {
-				.ingress = 1,
-				.egress = 1,
-				.transfer = priv->config.dv_esw_en ? 1 : 0,
-			};
-	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;
-	union mlx5_l3t_data data;
-	uint32_t mtr_idx;
-	int ret;
-	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.");
-	/* 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->max_mtr_flow_bits) > mtr_reg_bits) {
-		DRV_LOG(ERR, "Meter number exceeds max limit.");
-		goto error;
-	}
-	if (mtr_id_bits > priv->max_mtr_bits)
-		priv->max_mtr_bits = mtr_id_bits;
-	/* Fill the flow meter parameters. */
-	fm->meter_id = meter_id;
-	fm->profile = fmp;
-	memcpy(fm->action, params->action, sizeof(params->action));
-	mlx5_flow_meter_stats_enable_update(fm, params->stats_mask);
-	/* Alloc policer counters. */
-	if (fm->green_bytes || fm->green_pkts) {
-		fm->policer_stats.pass_cnt = mlx5_counter_alloc(dev);
-		if (!fm->policer_stats.pass_cnt)
-			goto error;
-	}
-	if (fm->red_bytes || fm->red_pkts ||
-	    fm->bytes_dropped || fm->pkts_dropped) {
-		fm->policer_stats.drop_cnt = mlx5_counter_alloc(dev);
-		if (!fm->policer_stats.drop_cnt)
-			goto error;
-	}
-	fm->mfts = mlx5_flow_create_mtr_tbls(dev);
-	if (!fm->mfts)
-		goto error;
-	ret = mlx5_flow_prepare_policer_rules(dev, fm, &attr);
-	if (ret)
-		goto error;
-	/* Add to the flow meter list. */
-	if (!priv->sh->meter_aso_en)
-		TAILQ_INSERT_TAIL(fms, legacy_fm, next);
-	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);
-	fm->flow_ipool = mlx5_ipool_create(&flow_ipool_cfg);
-	if (!fm->flow_ipool)
-		goto error;
-	rte_spinlock_init(&fm->sl);
-	/* If ASO meter supported, allocate ASO flow meter. */
-	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;
-		data.dword = mtr_idx;
-		if (mlx5_l3t_set_entry(priv->mtr_idx_tbl, meter_id, &data))
-			goto error;
-	}
-	return 0;
-error:
-	mlx5_flow_destroy_policer_rules(dev, fm, &attr);
-	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
-	/* Free policer counters. */
-	if (fm->policer_stats.pass_cnt)
-		mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
-	if (fm->policer_stats.drop_cnt)
-		mlx5_counter_free(dev, fm->policer_stats.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, -ret,
-				  RTE_MTR_ERROR_TYPE_UNSPECIFIED,
-				  NULL, "Failed to create devx meter.");
-}
-
 static int
 mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 			struct mlx5_flow_meter_info *fm,
-			const struct rte_flow_attr *attr,
 			uint32_t mtr_idx)
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
@@ -810,15 +572,12 @@  mlx5_flow_meter_params_flush(struct rte_eth_dev *dev,
 		legacy_fm = container_of(fm, struct mlx5_legacy_flow_meter, fm);
 		TAILQ_REMOVE(fms, legacy_fm, next);
 	}
-	/* Free policer counters. */
-	if (fm->policer_stats.pass_cnt)
-		mlx5_counter_free(dev, fm->policer_stats.pass_cnt);
-	if (fm->policer_stats.drop_cnt)
-		mlx5_counter_free(dev, fm->policer_stats.drop_cnt);
+	/* Free drop counters. */
+	if (fm->drop_cnt)
+		mlx5_counter_free(dev, fm->drop_cnt);
 	/* Free meter flow table. */
 	if (fm->flow_ipool)
 		mlx5_ipool_destroy(fm->flow_ipool);
-	mlx5_flow_destroy_policer_rules(dev, fm, attr);
 	mlx5_flow_destroy_mtr_tbls(dev, fm->mfts);
 	if (priv->sh->meter_aso_en)
 		mlx5_flow_mtr_free(dev, mtr_idx);
@@ -847,11 +606,6 @@  mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_meter_info *fm;
-	const struct rte_flow_attr attr = {
-				.ingress = 1,
-				.egress = 1,
-				.transfer = priv->config.dv_esw_en ? 1 : 0,
-			};
 	uint32_t mtr_idx = 0;
 
 	if (!priv->mtr_en)
@@ -876,7 +630,7 @@  mlx5_flow_meter_destroy(struct rte_eth_dev *dev, uint32_t meter_id,
 				"Fail to delete ASO Meter in index table.");
 	}
 	/* Destroy the meter profile. */
-	if (mlx5_flow_meter_params_flush(dev, fm, &attr, mtr_idx))
+	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.");
@@ -1102,13 +856,6 @@  mlx5_flow_meter_stats_update(struct rte_eth_dev *dev,
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_meter_info *fm;
-	const struct rte_flow_attr attr = {
-				.ingress = 1,
-				.egress = 1,
-				.transfer = priv->config.dv_esw_en ? 1 : 0,
-			};
-	bool need_updated = false;
-	struct mlx5_flow_policer_stats old_policer_stats;
 
 	if (!priv->mtr_en)
 		return -rte_mtr_error_set(error, ENOTSUP,
@@ -1120,69 +867,6 @@  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.");
-	old_policer_stats.pass_cnt = 0;
-	old_policer_stats.drop_cnt = 0;
-	if (!!((RTE_MTR_STATS_N_PKTS_GREEN |
-				RTE_MTR_STATS_N_BYTES_GREEN) & stats_mask) !=
-		!!fm->policer_stats.pass_cnt) {
-		need_updated = true;
-		if (fm->policer_stats.pass_cnt) {
-			old_policer_stats.pass_cnt = fm->policer_stats.pass_cnt;
-			fm->policer_stats.pass_cnt = 0;
-		} else {
-			fm->policer_stats.pass_cnt =
-				mlx5_counter_alloc(dev);
-			if (!fm->policer_stats.pass_cnt)
-				return -rte_mtr_error_set(error, ENOMEM,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-					  "Counter alloc failed for meter.");
-		}
-	}
-	if (!!((RTE_MTR_STATS_N_PKTS_RED | RTE_MTR_STATS_N_BYTES_RED |
-		RTE_MTR_STATS_N_PKTS_DROPPED | RTE_MTR_STATS_N_BYTES_DROPPED) &
-		stats_mask) !=
-		!!fm->policer_stats.drop_cnt) {
-		need_updated = true;
-		if (fm->policer_stats.drop_cnt) {
-			old_policer_stats.drop_cnt = fm->policer_stats.drop_cnt;
-			fm->policer_stats.drop_cnt = 0;
-		} else {
-			fm->policer_stats.drop_cnt =
-				mlx5_counter_alloc(dev);
-			if (!fm->policer_stats.drop_cnt)
-				return -rte_mtr_error_set(error, ENOMEM,
-					  RTE_MTR_ERROR_TYPE_UNSPECIFIED, NULL,
-					  "Counter alloc failed for meter.");
-		}
-	}
-	if (need_updated) {
-		if (mlx5_flow_prepare_policer_rules(dev, fm, &attr)) {
-			if (fm->policer_stats.pass_cnt &&
-				fm->policer_stats.pass_cnt !=
-				old_policer_stats.pass_cnt)
-				mlx5_counter_free(dev,
-					fm->policer_stats.pass_cnt);
-			fm->policer_stats.pass_cnt =
-					old_policer_stats.pass_cnt;
-			if (fm->policer_stats.drop_cnt &&
-				fm->policer_stats.drop_cnt !=
-				old_policer_stats.drop_cnt)
-				mlx5_counter_free(dev,
-					fm->policer_stats.drop_cnt);
-			fm->policer_stats.pass_cnt =
-					old_policer_stats.pass_cnt;
-			return -rte_mtr_error_set(error, ENOTSUP,
-				RTE_MTR_ERROR_TYPE_UNSPECIFIED,
-				NULL, "Failed to create meter policer rules.");
-		}
-		/* Free old policer counters. */
-		if (old_policer_stats.pass_cnt)
-			mlx5_counter_free(dev,
-				old_policer_stats.pass_cnt);
-		if (old_policer_stats.drop_cnt)
-			mlx5_counter_free(dev,
-				old_policer_stats.drop_cnt);
-	}
 	mlx5_flow_meter_stats_enable_update(fm, stats_mask);
 	return 0;
 }
@@ -1216,7 +900,6 @@  mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
 {
 	struct mlx5_priv *priv = dev->data->dev_private;
 	struct mlx5_flow_meter_info *fm;
-	struct mlx5_flow_policer_stats *ps;
 	uint64_t pkts;
 	uint64_t bytes;
 	int ret = 0;
@@ -1231,35 +914,14 @@  mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
 		return -rte_mtr_error_set(error, ENOENT,
 					  RTE_MTR_ERROR_TYPE_MTR_ID,
 					  NULL, "Meter object id not valid.");
-	ps = &fm->policer_stats;
 	*stats_mask = 0;
-	if (fm->green_bytes)
-		*stats_mask |= RTE_MTR_STATS_N_BYTES_GREEN;
-	if (fm->green_pkts)
-		*stats_mask |= RTE_MTR_STATS_N_PKTS_GREEN;
-	if (fm->red_bytes)
-		*stats_mask |= RTE_MTR_STATS_N_BYTES_RED;
-	if (fm->red_pkts)
-		*stats_mask |= RTE_MTR_STATS_N_PKTS_RED;
 	if (fm->bytes_dropped)
 		*stats_mask |= RTE_MTR_STATS_N_BYTES_DROPPED;
 	if (fm->pkts_dropped)
 		*stats_mask |= RTE_MTR_STATS_N_PKTS_DROPPED;
 	memset(stats, 0, sizeof(*stats));
-	if (ps->pass_cnt) {
-		ret = mlx5_counter_query(dev, ps->pass_cnt, clear, &pkts,
-						 &bytes);
-		if (ret)
-			goto error;
-		/* If need to read the packets, set it. */
-		if (fm->green_pkts)
-			stats->n_pkts[RTE_COLOR_GREEN] = pkts;
-		/* If need to read the bytes, set it. */
-		if (fm->green_bytes)
-			stats->n_bytes[RTE_COLOR_GREEN] = bytes;
-	}
-	if (ps->drop_cnt) {
-		ret = mlx5_counter_query(dev, ps->drop_cnt, clear, &pkts,
+	if (fm->drop_cnt) {
+		ret = mlx5_counter_query(dev, fm->drop_cnt, clear, &pkts,
 						 &bytes);
 		if (ret)
 			goto error;
@@ -1273,20 +935,18 @@  mlx5_flow_meter_stats_read(struct rte_eth_dev *dev,
 	return 0;
 error:
 	return -rte_mtr_error_set(error, ret, RTE_MTR_ERROR_TYPE_STATS, NULL,
-				 "Failed to read policer counters.");
+				 "Failed to read meter drop counters.");
 }
 
 static const struct rte_mtr_ops mlx5_flow_mtr_ops = {
 	.capabilities_get = mlx5_flow_mtr_cap_get,
 	.meter_profile_add = mlx5_flow_meter_profile_add,
 	.meter_profile_delete = mlx5_flow_meter_profile_delete,
-	.create = mlx5_flow_meter_create,
 	.destroy = mlx5_flow_meter_destroy,
 	.meter_enable = mlx5_flow_meter_enable,
 	.meter_disable = mlx5_flow_meter_disable,
 	.meter_profile_update = mlx5_flow_meter_profile_update,
 	.meter_dscp_table_update = NULL,
-	.policer_actions_update = NULL,
 	.stats_update = mlx5_flow_meter_stats_update,
 	.stats_read = mlx5_flow_meter_stats_read,
 };
@@ -1344,12 +1004,11 @@  mlx5_flow_meter_find(struct mlx5_priv *priv, uint32_t meter_id,
 		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);
-		MLX5_ASSERT(meter_id == aso_mtr->fm.meter_id);
 		rte_spinlock_unlock(&mtrmng->mtrsl);
 		return &aso_mtr->fm;
 	}
 	TAILQ_FOREACH(legacy_fm, fms, next)
-		if (meter_id == legacy_fm->fm.meter_id) {
+		if (meter_id == legacy_fm->meter_id) {
 			if (mtr_idx)
 				*mtr_idx = legacy_fm->idx;
 			return &legacy_fm->fm;
@@ -1517,11 +1176,6 @@  mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 	struct mlx5_legacy_flow_meter *legacy_fm;
 	struct mlx5_flow_meter_info *fm;
 	struct mlx5_aso_mtr_pool *mtr_pool;
-	const struct rte_flow_attr attr = {
-				.ingress = 1,
-				.egress = 1,
-				.transfer = priv->config.dv_esw_en ? 1 : 0,
-			};
 	void *tmp;
 	uint32_t i, offset, mtr_idx;
 
@@ -1533,9 +1187,8 @@  mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 				offset++) {
 				fm = &mtr_pool->mtrs[offset].fm;
 				mtr_idx = MLX5_MAKE_MTR_IDX(i, offset);
-				if (fm->meter_id != UINT32_MAX &&
-					mlx5_flow_meter_params_flush(dev,
-						fm, &attr, mtr_idx))
+				if (mlx5_flow_meter_params_flush(dev,
+						fm, mtr_idx))
 					return -rte_mtr_error_set
 					(error, EINVAL,
 					RTE_MTR_ERROR_TYPE_METER_PROFILE_ID,
@@ -1545,7 +1198,7 @@  mlx5_flow_meter_flush(struct rte_eth_dev *dev, struct rte_mtr_error *error)
 	} else {
 		TAILQ_FOREACH_SAFE(legacy_fm, fms, next, tmp) {
 			fm = &legacy_fm->fm;
-			if (mlx5_flow_meter_params_flush(dev, fm, &attr, 0))
+			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.");
diff --git a/drivers/net/softnic/rte_eth_softnic_flow.c b/drivers/net/softnic/rte_eth_softnic_flow.c
index 7925bad1c0..27eaf380cd 100644
--- a/drivers/net/softnic/rte_eth_softnic_flow.c
+++ b/drivers/net/softnic/rte_eth_softnic_flow.c
@@ -1166,6 +1166,7 @@  flow_rule_action_get(struct pmd_internals *softnic,
 {
 	struct softnic_table_action_profile *profile;
 	struct softnic_table_action_profile_params *params;
+	struct softnic_mtr_meter_policy *policy;
 	int n_jump_queue_rss_drop = 0;
 	int n_count = 0;
 	int n_mark = 0;
@@ -1621,15 +1622,25 @@  flow_rule_action_get(struct pmd_internals *softnic,
 					return -1;
 				}
 			}
-
+			/* Meter policy must exist */
+			policy = softnic_mtr_meter_policy_find(softnic,
+					m->params.meter_policy_id);
+			if (policy == NULL) {
+				rte_flow_error_set(error,
+						EINVAL,
+						RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+						NULL,
+						"METER: fail to find meter policy");
+				return -1;
+			}
 			/* RTE_TABLE_ACTION_METER */
 			rule_action->mtr.mtr[0].meter_profile_id = meter_profile_id;
 			rule_action->mtr.mtr[0].policer[RTE_COLOR_GREEN] =
-				softnic_table_action_policer(m->params.action[RTE_COLOR_GREEN]);
+				policy->policer[RTE_COLOR_GREEN];
 			rule_action->mtr.mtr[0].policer[RTE_COLOR_YELLOW] =
-				softnic_table_action_policer(m->params.action[RTE_COLOR_YELLOW]);
+				policy->policer[RTE_COLOR_YELLOW];
 			rule_action->mtr.mtr[0].policer[RTE_COLOR_RED] =
-				softnic_table_action_policer(m->params.action[RTE_COLOR_RED]);
+				policy->policer[RTE_COLOR_RED];
 			rule_action->mtr.tc_mask = 1;
 			rule_action->action_mask |= 1 << RTE_TABLE_ACTION_MTR;
 			break;
diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index faf90a5a8c..1b3186ef0b 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -83,6 +83,16 @@  struct softnic_mtr_meter_profile {
 
 TAILQ_HEAD(softnic_mtr_meter_profile_list, softnic_mtr_meter_profile);
 
+/* MTR meter policy */
+struct softnic_mtr_meter_policy {
+	TAILQ_ENTRY(softnic_mtr_meter_policy) node;
+	uint32_t meter_policy_id;
+	enum rte_table_action_policer policer[RTE_COLORS];
+	uint32_t n_users;
+};
+
+TAILQ_HEAD(softnic_mtr_meter_policy_list, softnic_mtr_meter_policy);
+
 /* MTR meter object */
 struct softnic_mtr {
 	TAILQ_ENTRY(softnic_mtr) node;
@@ -95,6 +105,7 @@  TAILQ_HEAD(softnic_mtr_list, softnic_mtr);
 
 struct mtr_internals {
 	struct softnic_mtr_meter_profile_list meter_profiles;
+	struct softnic_mtr_meter_policy_list meter_policies;
 	struct softnic_mtr_list mtrs;
 };
 
@@ -678,6 +689,10 @@  struct softnic_mtr_meter_profile *
 softnic_mtr_meter_profile_find(struct pmd_internals *p,
 	uint32_t meter_profile_id);
 
+struct softnic_mtr_meter_policy *
+softnic_mtr_meter_policy_find(struct pmd_internals *p,
+	uint32_t meter_policy_id);
+
 extern const struct rte_mtr_ops pmd_mtr_ops;
 
 /**
@@ -841,9 +856,6 @@  softnic_table_action_profile_create(struct pmd_internals *p,
 	const char *name,
 	struct softnic_table_action_profile_params *params);
 
-enum rte_table_action_policer
-softnic_table_action_policer(enum rte_mtr_policer_action action);
-
 /**
  * Pipeline
  */
diff --git a/drivers/net/softnic/rte_eth_softnic_meter.c b/drivers/net/softnic/rte_eth_softnic_meter.c
index 31a2a0e6d9..de49831775 100644
--- a/drivers/net/softnic/rte_eth_softnic_meter.c
+++ b/drivers/net/softnic/rte_eth_softnic_meter.c
@@ -65,27 +65,6 @@  softnic_mtr_meter_profile_find(struct pmd_internals *p,
 	return NULL;
 }
 
-enum rte_table_action_policer
-softnic_table_action_policer(enum rte_mtr_policer_action action)
-{
-	switch (action) {
-	case MTR_POLICER_ACTION_COLOR_GREEN:
-		return RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
-
-		/* FALLTHROUGH */
-	case MTR_POLICER_ACTION_COLOR_YELLOW:
-		return RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
-
-		/* FALLTHROUGH */
-	case MTR_POLICER_ACTION_COLOR_RED:
-		return RTE_TABLE_ACTION_POLICER_COLOR_RED;
-
-		/* FALLTHROUGH */
-	default:
-		return RTE_TABLE_ACTION_POLICER_DROP;
-	}
-}
-
 static int
 meter_profile_check(struct rte_eth_dev *dev,
 	uint32_t meter_profile_id,
@@ -200,6 +179,129 @@  pmd_mtr_meter_profile_delete(struct rte_eth_dev *dev,
 	return 0;
 }
 
+struct softnic_mtr_meter_policy *
+softnic_mtr_meter_policy_find(struct pmd_internals *p,
+	uint32_t meter_policy_id)
+{
+	struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
+	struct softnic_mtr_meter_policy *mp;
+
+	TAILQ_FOREACH(mp, mpl, node)
+		if (meter_policy_id == mp->meter_policy_id)
+			return mp;
+
+	return NULL;
+}
+
+/* MTR meter policy add */
+static int
+pmd_mtr_meter_policy_add(struct rte_eth_dev *dev,
+	uint32_t meter_policy_id,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct softnic_mtr_meter_policy_list *mpl = &p->mtr.meter_policies;
+	struct softnic_mtr_meter_policy *mp;
+	const struct rte_flow_action *act;
+	const struct rte_flow_action_meter_color *recolor;
+	uint32_t i;
+
+	/* Meter policy ID must be valid. */
+	if (meter_policy_id == UINT32_MAX)
+		return -rte_mtr_error_set(error,
+			EINVAL,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+			NULL,
+			"Meter policy id not valid");
+
+	for (i = 0; i < RTE_COLORS; i++) {
+		act = policy->actions[i];
+		if (act && act->type != RTE_FLOW_ACTION_TYPE_METER_COLOR &&
+			act->type != RTE_FLOW_ACTION_TYPE_DROP)
+			return -rte_mtr_error_set(error,
+				EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY,
+				NULL,
+				"Action invalid");
+	}
+
+	/* Memory allocation */
+	mp = calloc(1, sizeof(struct softnic_mtr_meter_policy));
+	if (mp == NULL)
+		return -rte_mtr_error_set(error,
+			ENOMEM,
+			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			"Memory alloc failed");
+
+	/* Fill in */
+	mp->meter_policy_id = meter_policy_id;
+	for (i = 0; i < RTE_COLORS; i++) {
+		mp->policer[i] = RTE_TABLE_ACTION_POLICER_DROP;
+		act = policy->actions[i];
+		if (!act)
+			continue;
+		if (act->type == RTE_FLOW_ACTION_TYPE_METER_COLOR) {
+			recolor = act->conf;
+			switch (recolor->color) {
+			case RTE_COLOR_GREEN:
+				mp->policer[i] =
+				RTE_TABLE_ACTION_POLICER_COLOR_GREEN;
+				break;
+			case RTE_COLOR_YELLOW:
+				mp->policer[i] =
+				RTE_TABLE_ACTION_POLICER_COLOR_YELLOW;
+				break;
+			case RTE_COLOR_RED:
+				mp->policer[i] =
+				RTE_TABLE_ACTION_POLICER_COLOR_RED;
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	/* Add to list */
+	TAILQ_INSERT_TAIL(mpl, mp, node);
+
+	return 0;
+}
+
+/* MTR meter policy delete */
+static int
+pmd_mtr_meter_policy_delete(struct rte_eth_dev *dev,
+	uint32_t meter_policy_id,
+	struct rte_mtr_error *error)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct softnic_mtr_meter_policy *mp;
+
+	/* Meter policy must exist */
+	mp = softnic_mtr_meter_policy_find(p, meter_policy_id);
+	if (mp == NULL)
+		return -rte_mtr_error_set(error,
+			EINVAL,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+			NULL,
+			"Meter policy id invalid");
+
+	/* Check unused */
+	if (mp->n_users)
+		return -rte_mtr_error_set(error,
+			EBUSY,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+			NULL,
+			"Meter policy in use");
+
+	/* Remove from list */
+	TAILQ_REMOVE(&p->mtr.meter_policies, mp, node);
+	free(mp);
+
+	return 0;
+}
+
 struct softnic_mtr *
 softnic_mtr_find(struct pmd_internals *p, uint32_t mtr_id)
 {
@@ -267,6 +369,7 @@  pmd_mtr_create(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
 	struct softnic_mtr_meter_profile *mp;
+	struct softnic_mtr_meter_policy *policy;
 	struct softnic_mtr *m;
 	int status;
 
@@ -284,6 +387,16 @@  pmd_mtr_create(struct rte_eth_dev *dev,
 			NULL,
 			"Meter profile id not valid");
 
+	/* Meter policy must exist */
+	policy = softnic_mtr_meter_policy_find(p, params->meter_policy_id);
+	if (policy == NULL) {
+		return -rte_mtr_error_set(error,
+				EINVAL,
+				RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+				NULL,
+				"Meter policy id invalid");
+	}
+
 	/* Memory allocation */
 	m = calloc(1, sizeof(struct softnic_mtr));
 	if (m == NULL)
@@ -302,6 +415,7 @@  pmd_mtr_create(struct rte_eth_dev *dev,
 
 	/* Update dependencies */
 	mp->n_users++;
+	policy->n_users++;
 
 	return 0;
 }
@@ -316,6 +430,7 @@  pmd_mtr_destroy(struct rte_eth_dev *dev,
 	struct softnic_mtr_list *ml = &p->mtr.mtrs;
 	struct softnic_mtr_meter_profile *mp;
 	struct softnic_mtr *m;
+	struct softnic_mtr_meter_policy *policy;
 
 	/* MTR object must exist */
 	m = softnic_mtr_find(p, mtr_id);
@@ -343,8 +458,18 @@  pmd_mtr_destroy(struct rte_eth_dev *dev,
 			NULL,
 			"MTR object meter profile invalid");
 
+	/* Meter policy must exist */
+	policy = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
+	if (policy == NULL)
+		return -rte_mtr_error_set(error,
+			EINVAL,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+			NULL,
+			"MTR object meter policy invalid");
+
 	/* Update dependencies */
 	mp->n_users--;
+	policy->n_users--;
 
 	/* Remove from list */
 	TAILQ_REMOVE(ml, m, node);
@@ -506,18 +631,18 @@  pmd_mtr_meter_dscp_table_update(struct rte_eth_dev *dev,
 	return 0;
 }
 
-/* MTR object policer action update */
+/* MTR object policy update */
 static int
-pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
+pmd_mtr_meter_policy_update(struct rte_eth_dev *dev,
 	uint32_t mtr_id,
-	uint32_t action_mask,
-	enum rte_mtr_policer_action *actions,
+	uint32_t meter_policy_id,
 	struct rte_mtr_error *error)
 {
 	struct pmd_internals *p = dev->data->dev_private;
 	struct softnic_mtr *m;
 	uint32_t i;
 	int status;
+	struct softnic_mtr_meter_policy *mp_new, *mp_old;
 
 	/* MTR object id must be valid */
 	m = softnic_mtr_find(p, mtr_id);
@@ -527,29 +652,14 @@  pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
 			RTE_MTR_ERROR_TYPE_MTR_ID,
 			NULL,
 			"MTR object id not valid");
-
-	/* Valid policer actions */
-	if (actions == NULL)
+	/* Meter policy must exist */
+	mp_new = softnic_mtr_meter_policy_find(p, meter_policy_id);
+	if (mp_new == NULL)
 		return -rte_mtr_error_set(error,
 			EINVAL,
-			RTE_MTR_ERROR_TYPE_UNSPECIFIED,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
 			NULL,
-			"Invalid actions");
-
-	for (i = 0; i < RTE_COLORS; i++) {
-		if (action_mask & (1 << i)) {
-			if (actions[i] != MTR_POLICER_ACTION_COLOR_GREEN  &&
-				actions[i] != MTR_POLICER_ACTION_COLOR_YELLOW &&
-				actions[i] != MTR_POLICER_ACTION_COLOR_RED &&
-				actions[i] != MTR_POLICER_ACTION_DROP) {
-				return -rte_mtr_error_set(error,
-					EINVAL,
-					RTE_MTR_ERROR_TYPE_UNSPECIFIED,
-					NULL,
-					" Invalid action value");
-			}
-		}
-	}
+			"Meter policy id invalid");
 
 	/* MTR object owner valid? */
 	if (m->flow) {
@@ -561,9 +671,7 @@  pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
 
 		/* Set action */
 		for (i = 0; i < RTE_COLORS; i++)
-			if (action_mask & (1 << i))
-				action.mtr.mtr[0].policer[i] =
-					softnic_table_action_policer(actions[i]);
+			action.mtr.mtr[0].policer[i] = mp_new->policer[i];
 
 		/* Re-add the rule */
 		status = softnic_pipeline_table_rule_add(p,
@@ -587,10 +695,20 @@  pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
 			1, NULL, 1);
 	}
 
-	/* Meter: Update policer actions */
-	for (i = 0; i < RTE_COLORS; i++)
-		if (action_mask & (1 << i))
-			m->params.action[i] = actions[i];
+	mp_old = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
+	if (mp_old == NULL)
+		return -rte_mtr_error_set(error,
+			EINVAL,
+			RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+			NULL,
+			"Old meter policy id invalid");
+
+	/* Meter: Set meter profile */
+	m->params.meter_policy_id = meter_policy_id;
+
+	/* Update dependencies*/
+	mp_old->n_users--;
+	mp_new->n_users++;
 
 	return 0;
 }
@@ -607,28 +725,40 @@  pmd_mtr_policer_actions_update(struct rte_eth_dev *dev,
 
 /* MTR object stats read */
 static void
-mtr_stats_convert(struct softnic_mtr *m,
+mtr_stats_convert(struct pmd_internals *p,
+	struct softnic_mtr *m,
 	struct rte_table_action_mtr_counters_tc *in,
 	struct rte_mtr_stats *out,
 	uint64_t *out_mask)
 {
+	struct softnic_mtr_meter_policy *mp;
+
 	memset(&out, 0, sizeof(out));
 	*out_mask = 0;
 
+	/* Meter policy must exist */
+	mp = softnic_mtr_meter_policy_find(p, m->params.meter_policy_id);
+	if (mp == NULL)
+		return;
+
 	if (in->n_packets_valid) {
 		uint32_t i;
 
 		for (i = 0; i < RTE_COLORS; i++) {
-			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
 				out->n_pkts[RTE_COLOR_GREEN] += in->n_packets[i];
 
-			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
 				out->n_pkts[RTE_COLOR_YELLOW] += in->n_packets[i];
 
-			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_COLOR_RED)
 				out->n_pkts[RTE_COLOR_RED] += in->n_packets[i];
 
-			if (m->params.action[i] == MTR_POLICER_ACTION_DROP)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_DROP)
 				out->n_pkts_dropped += in->n_packets[i];
 		}
 
@@ -639,16 +769,20 @@  mtr_stats_convert(struct softnic_mtr *m,
 		uint32_t i;
 
 		for (i = 0; i < RTE_COLORS; i++) {
-			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_GREEN)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_COLOR_GREEN)
 				out->n_bytes[RTE_COLOR_GREEN] += in->n_bytes[i];
 
-			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_YELLOW)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_COLOR_YELLOW)
 				out->n_bytes[RTE_COLOR_YELLOW] += in->n_bytes[i];
 
-			if (m->params.action[i] == MTR_POLICER_ACTION_COLOR_RED)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_COLOR_RED)
 				out->n_bytes[RTE_COLOR_RED] += in->n_bytes[i];
 
-			if (m->params.action[i] == MTR_POLICER_ACTION_DROP)
+			if (mp->policer[i] ==
+				RTE_TABLE_ACTION_POLICER_DROP)
 				out->n_bytes_dropped += in->n_bytes[i];
 		}
 
@@ -714,7 +848,8 @@  pmd_mtr_stats_read(struct rte_eth_dev *dev,
 		struct rte_mtr_stats s;
 		uint64_t s_mask = 0;
 
-		mtr_stats_convert(m,
+		mtr_stats_convert(p,
+			m,
 			&counters.stats[0],
 			&s,
 			&s_mask);
@@ -735,6 +870,9 @@  const struct rte_mtr_ops pmd_mtr_ops = {
 	.meter_profile_add = pmd_mtr_meter_profile_add,
 	.meter_profile_delete = pmd_mtr_meter_profile_delete,
 
+	.meter_policy_add = pmd_mtr_meter_policy_add,
+	.meter_policy_delete = pmd_mtr_meter_policy_delete,
+
 	.create = pmd_mtr_create,
 	.destroy = pmd_mtr_destroy,
 	.meter_enable = NULL,
@@ -742,7 +880,7 @@  const struct rte_mtr_ops pmd_mtr_ops = {
 
 	.meter_profile_update = pmd_mtr_meter_profile_update,
 	.meter_dscp_table_update = pmd_mtr_meter_dscp_table_update,
-	.policer_actions_update = pmd_mtr_policer_actions_update,
+	.meter_policy_update = pmd_mtr_meter_policy_update,
 	.stats_update = NULL,
 
 	.stats_read = pmd_mtr_stats_read,
diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index c476a0f59d..0eedcb09be 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -32,6 +32,7 @@ 
 #include <rte_ecpri.h>
 #include <rte_mbuf.h>
 #include <rte_mbuf_dyn.h>
+#include <rte_meter.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -2267,6 +2268,14 @@  enum rte_flow_action_type {
 	 * See struct rte_flow_action_modify_field.
 	 */
 	RTE_FLOW_ACTION_TYPE_MODIFY_FIELD,
+
+	/**
+	 * Color the packet to reflect the meter color result.
+	 * Set the meter color in the mbuf to the selected color.
+	 *
+	 * See struct rte_flow_action_meter_color.
+	 */
+	RTE_FLOW_ACTION_TYPE_METER_COLOR,
 };
 
 /**
@@ -2859,6 +2868,19 @@  struct rte_flow_action_set_dscp {
  */
 struct rte_flow_shared_action;
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this structure may change without prior notice
+ *
+ * RTE_FLOW_ACTION_TYPE_METER_COLOR
+ *
+ * The meter color should be set in the packet meta-data
+ * (i.e. struct rte_mbuf::sched::color).
+ */
+struct rte_flow_action_meter_color {
+	enum rte_color color; /**< Packet color. */
+};
+
 /**
  * Field IDs for MODIFY_FIELD action.
  */
diff --git a/lib/librte_ethdev/rte_mtr.c b/lib/librte_ethdev/rte_mtr.c
index 3073ac03f2..e49fcf271c 100644
--- a/lib/librte_ethdev/rte_mtr.c
+++ b/lib/librte_ethdev/rte_mtr.c
@@ -91,6 +91,40 @@  rte_mtr_meter_profile_delete(uint16_t port_id,
 		meter_profile_id, error);
 }
 
+/* MTR meter policy validate */
+int
+rte_mtr_meter_policy_validate(uint16_t port_id,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, meter_policy_validate)(dev,
+		policy, error);
+}
+
+/* MTR meter policy add */
+int
+rte_mtr_meter_policy_add(uint16_t port_id,
+	uint32_t policy_id,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, meter_policy_add)(dev,
+		policy_id, policy, error);
+}
+
+/** MTR meter policy delete */
+int
+rte_mtr_meter_policy_delete(uint16_t port_id,
+	uint32_t policy_id,
+	struct rte_mtr_error *error)
+{
+	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
+	return RTE_MTR_FUNC(port_id, meter_policy_delete)(dev,
+		policy_id, error);
+}
+
 /** MTR object create */
 int
 rte_mtr_create(uint16_t port_id,
@@ -149,29 +183,28 @@  rte_mtr_meter_profile_update(uint16_t port_id,
 		mtr_id, meter_profile_id, error);
 }
 
-/** MTR object meter DSCP table update */
+/** MTR object meter policy update */
 int
-rte_mtr_meter_dscp_table_update(uint16_t port_id,
+rte_mtr_meter_policy_update(uint16_t port_id,
 	uint32_t mtr_id,
-	enum rte_color *dscp_table,
+	uint32_t meter_policy_id,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
-	return RTE_MTR_FUNC(port_id, meter_dscp_table_update)(dev,
-		mtr_id, dscp_table, error);
+	return RTE_MTR_FUNC(port_id, meter_policy_update)(dev,
+		mtr_id, meter_policy_id, error);
 }
 
-/** MTR object policer action update */
+/** MTR object meter DSCP table update */
 int
-rte_mtr_policer_actions_update(uint16_t port_id,
+rte_mtr_meter_dscp_table_update(uint16_t port_id,
 	uint32_t mtr_id,
-	uint32_t action_mask,
-	enum rte_mtr_policer_action *actions,
+	enum rte_color *dscp_table,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
-	return RTE_MTR_FUNC(port_id, policer_actions_update)(dev,
-		mtr_id, action_mask, actions, error);
+	return RTE_MTR_FUNC(port_id, meter_dscp_table_update)(dev,
+		mtr_id, dscp_table, error);
 }
 
 /** MTR object enabled stats update */
diff --git a/lib/librte_ethdev/rte_mtr.h b/lib/librte_ethdev/rte_mtr.h
index 916a09c5c3..49c98f3da4 100644
--- a/lib/librte_ethdev/rte_mtr.h
+++ b/lib/librte_ethdev/rte_mtr.h
@@ -49,6 +49,7 @@ 
 #include <rte_compat.h>
 #include <rte_common.h>
 #include <rte_meter.h>
+#include <rte_flow.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -175,20 +176,16 @@  struct rte_mtr_meter_profile {
 };
 
 /**
- * Policer actions
+ * Meter policy
  */
-enum rte_mtr_policer_action {
-	/** Recolor the packet as green. */
-	MTR_POLICER_ACTION_COLOR_GREEN = 0,
-
-	/** Recolor the packet as yellow. */
-	MTR_POLICER_ACTION_COLOR_YELLOW,
-
-	/** Recolor the packet as red. */
-	MTR_POLICER_ACTION_COLOR_RED,
-
-	/** Drop the packet. */
-	MTR_POLICER_ACTION_DROP,
+struct rte_mtr_meter_policy_params {
+	/**
+	 * Policy action list per color.
+	 * actions[i] potentially represents a chain of rte_flow actions
+	 * terminated by the END action, exactly as specified by the rte_flow
+	 * API for the flow definition, and not just a single action.
+	 */
+	const struct rte_flow_action *actions[RTE_COLORS];
 };
 
 /**
@@ -232,13 +229,13 @@  struct rte_mtr_params {
 	 */
 	int meter_enable;
 
-	/** Policer actions (per meter output color). */
-	enum rte_mtr_policer_action action[RTE_COLORS];
-
 	/** Set of stats counters to be enabled.
 	 * @see enum rte_mtr_stats_type
 	 */
 	uint64_t stats_mask;
+
+	/** Meter policy ID. */
+	uint32_t meter_policy_id;
 };
 
 /**
@@ -324,6 +321,13 @@  struct rte_mtr_capabilities {
 	 */
 	uint64_t meter_rate_max;
 
+	/**
+	 * Maximum number of policy objects that can have.
+	 * The value of 0 is invalid. Policy must be supported for meter.
+	 * The maximum value is *n_max*.
+	 */
+	uint64_t meter_policy_n_max;
+
 	/**
 	 * When non-zero, it indicates that color aware mode is supported for
 	 * the srTCM RFC 2697 metering algorithm.
@@ -342,18 +346,6 @@  struct rte_mtr_capabilities {
 	 */
 	int color_aware_trtcm_rfc4115_supported;
 
-	/** When non-zero, it indicates that the policer packet recolor actions
-	 * are supported.
-	 * @see enum rte_mtr_policer_action
-	 */
-	int policer_action_recolor_supported;
-
-	/** When non-zero, it indicates that the policer packet drop action is
-	 * supported.
-	 * @see enum rte_mtr_policer_action
-	 */
-	int policer_action_drop_supported;
-
 	/** Set of supported statistics counter types.
 	 * @see enum rte_mtr_stats_type
 	 */
@@ -379,6 +371,8 @@  enum rte_mtr_error_type {
 	RTE_MTR_ERROR_TYPE_STATS_MASK,
 	RTE_MTR_ERROR_TYPE_STATS,
 	RTE_MTR_ERROR_TYPE_SHARED,
+	RTE_MTR_ERROR_TYPE_METER_POLICY_ID,
+	RTE_MTR_ERROR_TYPE_METER_POLICY,
 };
 
 /**
@@ -462,6 +456,83 @@  rte_mtr_meter_profile_delete(uint16_t port_id,
 	uint32_t meter_profile_id,
 	struct rte_mtr_error *error);
 
+/**
+ * Check whether a meter policy can be created on a given port.
+ *
+ * The meter policy is validated for correctness and
+ * whether it could be accepted by the device given sufficient resources.
+ * The policy is checked against the current capability information
+ * meter_policy_n_max configuration.
+ * The policy may also optionally be validated against existing
+ * device policy resources.
+ * This function has no effect on the target device.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] policy
+ *   Associated action list per color.
+ *   list NULL is legal and means no special action.
+ *   (list terminated by the END action).
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+__rte_experimental
+int
+rte_mtr_meter_policy_validate(uint16_t port_id,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error);
+
+/**
+ * Meter policy add
+ *
+ * Create a new meter policy. The new policy
+ * is used to create single or multiple MTR objects.
+ * The same policy can be used to create multiple MTR objects.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] policy_id
+ *   Policy identifier for the new meter policy.
+ * @param[in] policy
+ *   Associated actions per color.
+ *   list NULL is legal and means no special action.
+ *   Non-NULL list must be terminated.
+ *   (list terminated by the END action).
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+__rte_experimental
+int
+rte_mtr_meter_policy_add(uint16_t port_id,
+	uint32_t policy_id,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error);
+
+/**
+ * Meter policy delete
+ *
+ * Delete an existing meter policy. This operation fails when there is
+ * currently at least one user (i.e. MTR object) of this policy.
+ *
+ * @param[in] port_id
+ *   The port identifier of the Ethernet device.
+ * @param[in] policy_id
+ *   Policy identifier.
+ * @param[out] error
+ *   Error details. Filled in only on error, when not NULL.
+ * @return
+ *   0 on success, non-zero error code otherwise.
+ */
+__rte_experimental
+int
+rte_mtr_meter_policy_delete(uint16_t port_id,
+	uint32_t policy_id,
+	struct rte_mtr_error *error);
+
 /**
  * MTR object create
  *
@@ -587,18 +658,14 @@  rte_mtr_meter_profile_update(uint16_t port_id,
 	struct rte_mtr_error *error);
 
 /**
- * MTR object DSCP table update
+ * MTR object meter policy update
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
  * @param[in] mtr_id
  *   MTR object ID. Needs to be valid.
- * @param[in] dscp_table
- *   When non-NULL: it points to a pre-allocated and pre-populated table with
- *   exactly 64 elements providing the input color for each value of the
- *   IPv4/IPv6 Differentiated Services Code Point (DSCP) input packet field.
- *   When NULL: it is equivalent to setting this parameter to an “all-green”
- *   populated table (i.e. table with all the 64 elements set to green color).
+ * @param[in] meter_policy_id
+ *   Meter policy ID for the current MTR object. Needs to be valid.
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
  * @return
@@ -606,26 +673,24 @@  rte_mtr_meter_profile_update(uint16_t port_id,
  */
 __rte_experimental
 int
-rte_mtr_meter_dscp_table_update(uint16_t port_id,
+rte_mtr_meter_policy_update(uint16_t port_id,
 	uint32_t mtr_id,
-	enum rte_color *dscp_table,
+	uint32_t meter_policy_id,
 	struct rte_mtr_error *error);
 
 /**
- * MTR object policer actions update
+ * MTR object DSCP table update
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
  * @param[in] mtr_id
  *   MTR object ID. Needs to be valid.
- * @param[in] action_mask
- *   Bit mask indicating which policer actions need to be updated. One or more
- *   policer actions can be updated in a single function invocation. To update
- *   the policer action associated with color C, bit (1 << C) needs to be set in
- *   *action_mask* and element at position C in the *actions* array needs to be
- *   valid.
- * @param[in] actions
- *   Pre-allocated and pre-populated array of policer actions.
+ * @param[in] dscp_table
+ *   When non-NULL: it points to a pre-allocated and pre-populated table with
+ *   exactly 64 elements providing the input color for each value of the
+ *   IPv4/IPv6 Differentiated Services Code Point (DSCP) input packet field.
+ *   When NULL: it is equivalent to setting this parameter to an “all-green”
+ *   populated table (i.e. table with all the 64 elements set to green color).
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
  * @return
@@ -633,10 +698,9 @@  rte_mtr_meter_dscp_table_update(uint16_t port_id,
  */
 __rte_experimental
 int
-rte_mtr_policer_actions_update(uint16_t port_id,
+rte_mtr_meter_dscp_table_update(uint16_t port_id,
 	uint32_t mtr_id,
-	uint32_t action_mask,
-	enum rte_mtr_policer_action *actions,
+	enum rte_color *dscp_table,
 	struct rte_mtr_error *error);
 
 /**
diff --git a/lib/librte_ethdev/rte_mtr_driver.h b/lib/librte_ethdev/rte_mtr_driver.h
index a0ddc2b5f4..62273ed3a9 100644
--- a/lib/librte_ethdev/rte_mtr_driver.h
+++ b/lib/librte_ethdev/rte_mtr_driver.h
@@ -41,6 +41,22 @@  typedef int (*rte_mtr_meter_profile_delete_t)(struct rte_eth_dev *dev,
 	struct rte_mtr_error *error);
 /**< @internal MTR meter profile delete */
 
+typedef int (*rte_mtr_meter_policy_validate_t)(struct rte_eth_dev *dev,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error);
+/**< @internal MTR meter policy validate */
+
+typedef int (*rte_mtr_meter_policy_add_t)(struct rte_eth_dev *dev,
+	uint32_t policy_id,
+	struct rte_mtr_meter_policy_params *policy,
+	struct rte_mtr_error *error);
+/**< @internal MTR meter policy add */
+
+typedef int (*rte_mtr_meter_policy_delete_t)(struct rte_eth_dev *dev,
+	uint32_t policy_id,
+	struct rte_mtr_error *error);
+/**< @internal MTR meter policy delete */
+
 typedef int (*rte_mtr_create_t)(struct rte_eth_dev *dev,
 	uint32_t mtr_id,
 	struct rte_mtr_params *params,
@@ -69,18 +85,17 @@  typedef int (*rte_mtr_meter_profile_update_t)(struct rte_eth_dev *dev,
 	struct rte_mtr_error *error);
 /**< @internal MTR object meter profile update */
 
-typedef int (*rte_mtr_meter_dscp_table_update_t)(struct rte_eth_dev *dev,
+typedef int (*rte_mtr_meter_policy_update_t)(struct rte_eth_dev *dev,
 	uint32_t mtr_id,
-	enum rte_color *dscp_table,
+	uint32_t meter_policy_id,
 	struct rte_mtr_error *error);
-/**< @internal MTR object meter DSCP table update */
+/**< @internal MTR object meter policy update */
 
-typedef int (*rte_mtr_policer_actions_update_t)(struct rte_eth_dev *dev,
+typedef int (*rte_mtr_meter_dscp_table_update_t)(struct rte_eth_dev *dev,
 	uint32_t mtr_id,
-	uint32_t action_mask,
-	enum rte_mtr_policer_action *actions,
+	enum rte_color *dscp_table,
 	struct rte_mtr_error *error);
-/**< @internal MTR object policer action update*/
+/**< @internal MTR object meter DSCP table update */
 
 typedef int (*rte_mtr_stats_update_t)(struct rte_eth_dev *dev,
 	uint32_t mtr_id,
@@ -124,14 +139,23 @@  struct rte_mtr_ops {
 	/** MTR object meter DSCP table update */
 	rte_mtr_meter_dscp_table_update_t meter_dscp_table_update;
 
-	/** MTR object policer action update */
-	rte_mtr_policer_actions_update_t policer_actions_update;
-
 	/** MTR object enabled stats update */
 	rte_mtr_stats_update_t stats_update;
 
 	/** MTR object stats read */
 	rte_mtr_stats_read_t stats_read;
+
+	/** MTR meter policy validate */
+	rte_mtr_meter_policy_validate_t meter_policy_validate;
+
+	/** MTR meter policy add */
+	rte_mtr_meter_policy_add_t meter_policy_add;
+
+	/** MTR meter policy delete */
+	rte_mtr_meter_policy_delete_t meter_policy_delete;
+
+	/** MTR object meter policy update */
+	rte_mtr_meter_policy_update_t meter_policy_update;
 };
 
 /**
diff --git a/lib/librte_ethdev/version.map b/lib/librte_ethdev/version.map
index 93ad388e96..b3e9b83d95 100644
--- a/lib/librte_ethdev/version.map
+++ b/lib/librte_ethdev/version.map
@@ -138,7 +138,6 @@  EXPERIMENTAL {
 	rte_mtr_meter_profile_add;
 	rte_mtr_meter_profile_delete;
 	rte_mtr_meter_profile_update;
-	rte_mtr_policer_actions_update;
 	rte_mtr_stats_read;
 	rte_mtr_stats_update;
 
@@ -246,6 +245,10 @@  EXPERIMENTAL {
 
 	# added in 21.05
 	rte_eth_representor_info_get;
+	rte_mtr_meter_policy_add;
+	rte_mtr_meter_policy_delete;
+	rte_mtr_meter_policy_update;
+	rte_mtr_meter_policy_validate;
 };
 
 INTERNAL {