diff mbox series

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

Message ID 20210413001428.1999959-2-lizh@nvidia.com (mailing list archive)
State Superseded, archived
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 13, 2021, 12:14 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>
---
 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                   | 215 ++++++--
 lib/librte_ethdev/rte_mtr_driver.h            |  44 +-
 lib/librte_ethdev/version.map                 |   5 +-
 22 files changed, 568 insertions(+), 1258 deletions(-)

Comments

Dumitrescu, Cristian April 13, 2021, 2:19 p.m. UTC | #1
Hi Li,

This patch does not apply on top of the latest DPDK. Can you please rebase on top of DPDK version and resend. If this depends on some other patch sets to be applied first, then please send clear steps on how to apply.

Thanks,
Cristian
Dumitrescu, Cristian April 13, 2021, 2:59 p.m. UTC | #2
Hi Li,

Here are some initial comments while waiting for a new version that applies cleanly.

> -----Original Message-----
> From: Li Zhang <lizh@nvidia.com>
> Sent: Tuesday, April 13, 2021 1:14 AM
> To: dekelp@nvidia.com; orika@nvidia.com; viacheslavo@nvidia.com;
> matan@nvidia.com; shahafs@nvidia.com; Dumitrescu, Cristian
> <cristian.dumitrescu@intel.com>; lironh@marvell.com; Wisam Jaddo
> <wisamm@nvidia.com>; Li, Xiaoyun <xiaoyun.li@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; Thomas Monjalon <thomas@monjalon.net>;
> Yigit, Ferruh <ferruh.yigit@intel.com>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Neil
> Horman <nhorman@tuxdriver.com>
> Cc: dev@dpdk.org; rasland@nvidia.com; roniba@nvidia.com; Haifei Luo
> <haifeil@nvidia.com>; Jiawei Wang <jiaweiw@nvidia.com>
> Subject: [PATCH v3 1/2] ethdev: add pre-defined meter policy API
> 
> 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>
> ---
>  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                   | 215 ++++++--
>  lib/librte_ethdev/rte_mtr_driver.h            |  44 +-
>  lib/librte_ethdev/version.map                 |   5 +-
>  22 files changed, 568 insertions(+), 1258 deletions(-)
> 
> diff --git a/app/test-flow-perf/main.c b/app/test-flow-perf/main.c
> index 0aef767350..c1f38cbec5 100644
> --- a/app/test-flow-perf/main.c
> +++ b/app/test-flow-perf/main.c
> @@ -921,13 +921,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 f44116b087..fae79d4c85 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 113b37cddc..1b1b4368f6 100644
> --- a/doc/guides/rel_notes/release_21_05.rst
> +++ b/doc/guides/rel_notes/release_21_05.rst
> @@ -161,7 +161,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_create()``, ``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..2a05a85cdb 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 create */
> +static int
> +pmd_mtr_meter_policy_create(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_create = pmd_mtr_meter_policy_create,
> +	.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 6cc57136ac..d4fd36dd0e 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..9b03cf1d50 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 create */
> +int
> +rte_mtr_meter_policy_create(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_create)(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..9f6f5e1a45 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,136 @@ 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.
> + *

Maybe tweak the explanation a bit: The same policy can be used to create multiple MTR objects.

> + * Two common examples to define meter policy action list:
> + * Example #1: GREEN - GREEN, YELLOW - YELLOW, RED - RED
> + *	struct rte_mtr_meter_policy_params policy_0 =
> + *					(struct
> rte_mtr_meter_policy_params) {
> + *		.actions[RTE_COLOR_GREEN] = (struct rte_flow_action[]) {
> + *			{
> + *				.type =
> RTE_FLOW_ACTION_TYPE_METER_COLOR,
> + *				.conf = &(struct
> rte_flow_action_meter_color) {
> + *					.color = RTE_COLOR_GREEN,
> + *				},
> + *			},
> + *			{
> + *				.type = RTE_FLOW_ACTION_TYPE_END,
> + *			},
> + *		},
> + *		.actions[RTE_COLOR_YELLOW] = (struct rte_flow_action[]) {
> + *			{
> + *				.type =
> RTE_FLOW_ACTION_TYPE_METER_COLOR,
> + *				.conf = &(struct
> rte_flow_action_meter_color) {
> + *					.color = RTE_COLOR_YELLOW,
> + *				},
> + *			},
> + *			{
> + *			.type = RTE_FLOW_ACTION_TYPE_END,
> + *			},
> + *		},
> + *		.actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> + *			{
> + *				.type =
> RTE_FLOW_ACTION_TYPE_METER_COLOR,
> + *				.conf = &(struct
> rte_flow_action_meter_color) {
> + *					.color = RTE_COLOR_RED,
> + *				},
> + *			},
> + *			{
> + *				.type = RTE_FLOW_ACTION_TYPE_END,
> + *			},
> + *		},
> + *	};
> + *
> + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
> + *	struct rte_mtr_meter_policy_params policy_1 =
> + *					(struct
> rte_mtr_meter_policy_params) {
> + *		.actions[RTE_COLOR_GREEN] = NULL,
> + *		.actions[RTE_COLOR_YELLOW] = NULL,
> + *		.actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> + *			{
> + *				.type = RTE_FLOW_ACTION_TYPE_DROP,
> + *			},
> + *			{
> + *				.type = RTE_FLOW_ACTION_TYPE_END,
> + *			},
> + *		},
> + *	};
> + *

These two example policies should be available to be used straight away, please make them real data structures, not comments.

I suggest their names as: pass_color_policy_params and drop_red_policy_params.

> + * @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_create(uint16_t port_id,

The name of this function at the top of its description is mentioned as "meter policy add", while this function name here is policy create, please align the two.

Since we already have other API functions in this file for profiles/policies with the naming convention of add/delete as opposed to create/destroy (rte_mtr_meter_profile_add  and rte_mtr_meter_profile_delete), please let's use the existing convention and call these ones rte_mtr_meter_policy_add and rte_mtr_meter_policy_delete.

> +	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 +711,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 +726,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 +751,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..462a1e862c 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_create_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 create */
> +	rte_mtr_meter_policy_create_t meter_policy_create;
> +
> +	/** 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..0045baff8c 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_create;
> +	rte_mtr_meter_policy_delete;
> +	rte_mtr_meter_policy_update;
> +	rte_mtr_meter_policy_validate;
>  };
> 
>  INTERNAL {
> --
> 2.27.0

Regards,
Cristian
Kinsella, Ray April 13, 2021, 4:25 p.m. UTC | #3
On 13/04/2021 01:14, Li Zhang wrote:
> 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>
> ---
>  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                   | 215 ++++++--
>  lib/librte_ethdev/rte_mtr_driver.h            |  44 +-
>  lib/librte_ethdev/version.map                 |   5 +-
>  22 files changed, 568 insertions(+), 1258 deletions(-)
> 


Acked-by: Ray Kinsella <mdr@ashroe.eu>
Li Zhang April 14, 2021, 3:23 a.m. UTC | #4
Hi Cristian,

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

Because RTE API change and it need change PMD part to fix building issue.

Regards,
Li Zhang

> -----Original Message-----
> From: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Sent: Tuesday, April 13, 2021 10:19 PM
> 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; Wisam Monther <wisamm@nvidia.com>; Li, Xiaoyun
> <xiaoyun.li@intel.com>; Singh, Jasvinder <jasvinder.singh@intel.com>; NBU-
> Contact-Thomas Monjalon <thomas@monjalon.net>; Yigit, Ferruh
> <ferruh.yigit@intel.com>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Neil
> Horman <nhorman@tuxdriver.com>; Jerin Jacob <jerinjacobk@gmail.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 v3 1/2] ethdev: add pre-defined meter policy API
> 
> External email: Use caution opening links or attachments
> 
> 
> Hi Li,
> 
> This patch does not apply on top of the latest DPDK. Can you please rebase on
> top of DPDK version and resend. If this depends on some other patch sets to be
> applied first, then please send clear steps on how to apply.
> 
> Thanks,
> Cristian
Li Zhang April 14, 2021, 4:55 a.m. UTC | #5
Hi Cristian,
> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Dumitrescu, Cristian
> Sent: Tuesday, April 13, 2021 11:00 PM
> 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; Wisam Monther <wisamm@nvidia.com>; Li, Xiaoyun
> <xiaoyun.li@intel.com>; Singh, Jasvinder <jasvinder.singh@intel.com>; NBU-
> Contact-Thomas Monjalon <thomas@monjalon.net>; Yigit, Ferruh
> <ferruh.yigit@intel.com>; 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: [dpdk-dev] [PATCH v3 1/2] ethdev: add pre-defined meter policy
> API
> 
> External email: Use caution opening links or attachments
> 
> 
> Hi Li,
> 
> Here are some initial comments while waiting for a new version that applies
> cleanly.
> 
> > -----Original Message-----
> > From: Li Zhang <lizh@nvidia.com>
> > Sent: Tuesday, April 13, 2021 1:14 AM
> > To: dekelp@nvidia.com; orika@nvidia.com; viacheslavo@nvidia.com;
> > matan@nvidia.com; shahafs@nvidia.com; Dumitrescu, Cristian
> > <cristian.dumitrescu@intel.com>; lironh@marvell.com; Wisam Jaddo
> > <wisamm@nvidia.com>; Li, Xiaoyun <xiaoyun.li@intel.com>; Singh,
> Jasvinder
> > <jasvinder.singh@intel.com>; Thomas Monjalon <thomas@monjalon.net>;
> > Yigit, Ferruh <ferruh.yigit@intel.com>; Andrew Rybchenko
> > <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Neil
> > Horman <nhorman@tuxdriver.com>
> > Cc: dev@dpdk.org; rasland@nvidia.com; roniba@nvidia.com; Haifei Luo
> > <haifeil@nvidia.com>; Jiawei Wang <jiaweiw@nvidia.com>
> > Subject: [PATCH v3 1/2] ethdev: add pre-defined meter policy API
> >
> > 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>
> > ---
> >  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                   | 215 ++++++--
> >  lib/librte_ethdev/rte_mtr_driver.h            |  44 +-
> >  lib/librte_ethdev/version.map                 |   5 +-
> >  22 files changed, 568 insertions(+), 1258 deletions(-)
> >
> > diff --git a/app/test-flow-perf/main.c b/app/test-flow-perf/main.c
> > index 0aef767350..c1f38cbec5 100644
> > --- a/app/test-flow-perf/main.c
> > +++ b/app/test-flow-perf/main.c
> > @@ -921,13 +921,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 f44116b087..fae79d4c85 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 113b37cddc..1b1b4368f6 100644
> > --- a/doc/guides/rel_notes/release_21_05.rst
> > +++ b/doc/guides/rel_notes/release_21_05.rst
> > @@ -161,7 +161,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_create()``, ``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..2a05a85cdb 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 create */
> > +static int
> > +pmd_mtr_meter_policy_create(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_create = pmd_mtr_meter_policy_create,
> > +     .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 6cc57136ac..d4fd36dd0e 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..9b03cf1d50 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 create */
> > +int
> > +rte_mtr_meter_policy_create(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_create)(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..9f6f5e1a45 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,136 @@ 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.
> > + *
> 
> Maybe tweak the explanation a bit: The same policy can be used to create
> multiple MTR objects.
> 
Thanks, will add in V5 patch.

> > + * Two common examples to define meter policy action list:
> > + * Example #1: GREEN - GREEN, YELLOW - YELLOW, RED - RED
> > + *   struct rte_mtr_meter_policy_params policy_0 =
> > + *                                   (struct
> > rte_mtr_meter_policy_params) {
> > + *           .actions[RTE_COLOR_GREEN] = (struct rte_flow_action[]) {
> > + *                   {
> > + *                           .type =
> > RTE_FLOW_ACTION_TYPE_METER_COLOR,
> > + *                           .conf = &(struct
> > rte_flow_action_meter_color) {
> > + *                                   .color = RTE_COLOR_GREEN,
> > + *                           },
> > + *                   },
> > + *                   {
> > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> > + *                   },
> > + *           },
> > + *           .actions[RTE_COLOR_YELLOW] = (struct rte_flow_action[]) {
> > + *                   {
> > + *                           .type =
> > RTE_FLOW_ACTION_TYPE_METER_COLOR,
> > + *                           .conf = &(struct
> > rte_flow_action_meter_color) {
> > + *                                   .color = RTE_COLOR_YELLOW,
> > + *                           },
> > + *                   },
> > + *                   {
> > + *                   .type = RTE_FLOW_ACTION_TYPE_END,
> > + *                   },
> > + *           },
> > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> > + *                   {
> > + *                           .type =
> > RTE_FLOW_ACTION_TYPE_METER_COLOR,
> > + *                           .conf = &(struct
> > rte_flow_action_meter_color) {
> > + *                                   .color = RTE_COLOR_RED,
> > + *                           },
> > + *                   },
> > + *                   {
> > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> > + *                   },
> > + *           },
> > + *   };
> > + *
> > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
> > + *   struct rte_mtr_meter_policy_params policy_1 =
> > + *                                   (struct
> > rte_mtr_meter_policy_params) {
> > + *           .actions[RTE_COLOR_GREEN] = NULL,
> > + *           .actions[RTE_COLOR_YELLOW] = NULL,
> > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> > + *                   {
> > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
> > + *                   },
> > + *                   {
> > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> > + *                   },
> > + *           },
> > + *   };
> > + *
> 
> These two example policies should be available to be used straight away,
> please make them real data structures, not comments.
> 
> I suggest their names as: pass_color_policy_params and
> drop_red_policy_params.
>
Thanks. Will change the names. But it can not be real data structures, since it just one example define and no use code.
It will bring build as below:
error: 'drop_red_policy_params' defined but not used.
 User can copy these example to his .c file when it using rte_mtr_meter_policy_add().

> > + * @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_create(uint16_t port_id,
> 
> The name of this function at the top of its description is mentioned as "meter
> policy add", while this function name here is policy create, please align the
> two.
> 
> Since we already have other API functions in this file for profiles/policies with
> the naming convention of add/delete as opposed to create/destroy
> (rte_mtr_meter_profile_add  and rte_mtr_meter_profile_delete), please let's
> use the existing convention and call these ones rte_mtr_meter_policy_add
> and rte_mtr_meter_policy_delete.
> 
Thanks, will change it in V5 patch.

> > +     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 +711,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 +726,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 +751,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..462a1e862c 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_create_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 create */
> > +     rte_mtr_meter_policy_create_t meter_policy_create;
> > +
> > +     /** 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..0045baff8c 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_create;
> > +     rte_mtr_meter_policy_delete;
> > +     rte_mtr_meter_policy_update;
> > +     rte_mtr_meter_policy_validate;
> >  };
> >
> >  INTERNAL {
> > --
> > 2.27.0
> 
> Regards,
> Cristian
Thomas Monjalon April 14, 2021, 8:02 a.m. UTC | #6
Cristian, Li, please remove useless context when replying.

14/04/2021 06:55, Li Zhang:
> > > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
> > > + *   struct rte_mtr_meter_policy_params policy_1 =
> > > + *                                   (struct
> > > rte_mtr_meter_policy_params) {
> > > + *           .actions[RTE_COLOR_GREEN] = NULL,
> > > + *           .actions[RTE_COLOR_YELLOW] = NULL,
> > > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> > > + *                   {
> > > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
> > > + *                   },
> > > + *                   {
> > > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> > > + *                   },
> > > + *           },
> > > + *   };
> > > + *
> >
> > These two example policies should be available to be used straight away,
> > please make them real data structures, not comments.

Wait, you are giving code examples as part of doxygen?
It's really too long, we don't do that.

> > I suggest their names as: pass_color_policy_params and
> > drop_red_policy_params.
> >
> Thanks. Will change the names. But it can not be real data structures, since it just one example define and no use code.
> It will bring build as below:
> error: 'drop_red_policy_params' defined but not used.
>  User can copy these example to his .c file when it using rte_mtr_meter_policy_add().

If you need to provide an example, we use the directory examples.
I see rte_mtr is not implemented in any example,
so it could be a later addition.
Matan Azrad April 14, 2021, 8:31 a.m. UTC | #7
From: Thomas Monjalon
> Cristian, Li, please remove useless context when replying.
> 
> 14/04/2021 06:55, Li Zhang:
> > > > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
> > > > + *   struct rte_mtr_meter_policy_params policy_1 =
> > > > + *                                   (struct
> > > > rte_mtr_meter_policy_params) {
> > > > + *           .actions[RTE_COLOR_GREEN] = NULL,
> > > > + *           .actions[RTE_COLOR_YELLOW] = NULL,
> > > > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> > > > + *                   {
> > > > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
> > > > + *                   },
> > > > + *                   {
> > > > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> > > > + *                   },
> > > > + *           },
> > > > + *   };
> > > > + *
> > >
> > > These two example policies should be available to be used straight
> > > away, please make them real data structures, not comments.
> 
> Wait, you are giving code examples as part of doxygen?
> It's really too long, we don't do that.
> 
> > > I suggest their names as: pass_color_policy_params and
> > > drop_red_policy_params.
> > >
> > Thanks. Will change the names. But it can not be real data structures, since it
> just one example define and no use code.
> > It will bring build as below:
> > error: 'drop_red_policy_params' defined but not used.
> >  User can copy these example to his .c file when it using
> rte_mtr_meter_policy_add().
> 
> If you need to provide an example, we use the directory examples.
> I see rte_mtr is not implemented in any example, so it could be a later
> addition.

+1
Asaf Penso April 14, 2021, 8:47 a.m. UTC | #8
>-----Original Message-----
>From: dev <dev-bounces@dpdk.org> On Behalf Of Thomas Monjalon
>Sent: Wednesday, April 14, 2021 11:02 AM
>To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Li Zhang
><lizh@nvidia.com>
>Cc: Ori Kam <orika@nvidia.com>; Slava Ovsiienko <viacheslavo@nvidia.com>;
>Matan Azrad <matan@nvidia.com>; lironh@marvell.com; Wisam Monther
><wisamm@nvidia.com>; Li, Xiaoyun <xiaoyun.li@intel.com>; Singh, Jasvinder
><jasvinder.singh@intel.com>; Yigit, Ferruh <ferruh.yigit@intel.com>; Andrew
>Rybchenko <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella
><mdr@ashroe.eu>; Jerin Jacob <jerinjacobk@gmail.com>; Hemant Agrawal
><hemant.agrawal@nxp.com>; 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: [dpdk-dev] [PATCH v3 1/2] ethdev: add pre-defined meter policy
>API
>
>Cristian, Li, please remove useless context when replying.
>
>14/04/2021 06:55, Li Zhang:
>> > > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
>> > > + *   struct rte_mtr_meter_policy_params policy_1 =
>> > > + *                                   (struct
>> > > rte_mtr_meter_policy_params) {
>> > > + *           .actions[RTE_COLOR_GREEN] = NULL,
>> > > + *           .actions[RTE_COLOR_YELLOW] = NULL,
>> > > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
>> > > + *                   {
>> > > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
>> > > + *                   },
>> > > + *                   {
>> > > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
>> > > + *                   },
>> > > + *           },
>> > > + *   };
>> > > + *
>> >
>> > These two example policies should be available to be used straight
>> > away, please make them real data structures, not comments.
>
>Wait, you are giving code examples as part of doxygen?
>It's really too long, we don't do that.
>
>> > I suggest their names as: pass_color_policy_params and
>> > drop_red_policy_params.
>> >
>> Thanks. Will change the names. But it can not be real data structures, since it
>just one example define and no use code.
>> It will bring build as below:
>> error: 'drop_red_policy_params' defined but not used.
>>  User can copy these example to his .c file when it using
>rte_mtr_meter_policy_add().
>
>If you need to provide an example, we use the directory examples.
>I see rte_mtr is not implemented in any example, so it could be a later
>addition.
>
>
We want, as a rule of thumb, to provide more code snippets and not necessarily full-blown example applications. 
Where do you suggest having that?
In any case, I agree, this can be removed now to allow integration of rc1. Doc can be done afterward.
Li Zhang April 14, 2021, 8:59 a.m. UTC | #9
Hi All,

Thanks for your suggestions.
I delete the example in V6 patch.

Regards,
Li Zhang
> -----Original Message-----
> From: Asaf Penso <asafp@nvidia.com>
> Sent: Wednesday, April 14, 2021 4:47 PM
> To: NBU-Contact-Thomas Monjalon <thomas@monjalon.net>; Dumitrescu,
> Cristian <cristian.dumitrescu@intel.com>; Li Zhang <lizh@nvidia.com>
> Cc: Ori Kam <orika@nvidia.com>; Slava Ovsiienko <viacheslavo@nvidia.com>;
> Matan Azrad <matan@nvidia.com>; lironh@marvell.com; Wisam Monther
> <wisamm@nvidia.com>; Li, Xiaoyun <xiaoyun.li@intel.com>; Singh,
> Jasvinder <jasvinder.singh@intel.com>; Yigit, Ferruh
> <ferruh.yigit@intel.com>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Jerin
> Jacob <jerinjacobk@gmail.com>; Hemant Agrawal
> <hemant.agrawal@nxp.com>; 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: [dpdk-dev] [PATCH v3 1/2] ethdev: add pre-defined meter policy
> API
> 
> >-----Original Message-----
> >From: dev <dev-bounces@dpdk.org> On Behalf Of Thomas Monjalon
> >Sent: Wednesday, April 14, 2021 11:02 AM
> >To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Li Zhang
> ><lizh@nvidia.com>
> >Cc: Ori Kam <orika@nvidia.com>; Slava Ovsiienko
> ><viacheslavo@nvidia.com>; Matan Azrad <matan@nvidia.com>;
> >lironh@marvell.com; Wisam Monther <wisamm@nvidia.com>; Li, Xiaoyun
> ><xiaoyun.li@intel.com>; Singh, Jasvinder <jasvinder.singh@intel.com>;
> >Yigit, Ferruh <ferruh.yigit@intel.com>; Andrew Rybchenko
> ><andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Jerin
> >Jacob <jerinjacobk@gmail.com>; Hemant Agrawal
> <hemant.agrawal@nxp.com>;
> >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: [dpdk-dev] [PATCH v3 1/2] ethdev: add pre-defined meter
> >policy API
> >
> >Cristian, Li, please remove useless context when replying.
> >
> >14/04/2021 06:55, Li Zhang:
> >> > > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED -
> DROP
> >> > > + *   struct rte_mtr_meter_policy_params policy_1 =
> >> > > + *                                   (struct
> >> > > rte_mtr_meter_policy_params) {
> >> > > + *           .actions[RTE_COLOR_GREEN] = NULL,
> >> > > + *           .actions[RTE_COLOR_YELLOW] = NULL,
> >> > > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> >> > > + *                   {
> >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
> >> > > + *                   },
> >> > > + *                   {
> >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> >> > > + *                   },
> >> > > + *           },
> >> > > + *   };
> >> > > + *
> >> >
> >> > These two example policies should be available to be used straight
> >> > away, please make them real data structures, not comments.
> >
> >Wait, you are giving code examples as part of doxygen?
> >It's really too long, we don't do that.
> >
> >> > I suggest their names as: pass_color_policy_params and
> >> > drop_red_policy_params.
> >> >
> >> Thanks. Will change the names. But it can not be real data
> >> structures, since it
> >just one example define and no use code.
> >> It will bring build as below:
> >> error: 'drop_red_policy_params' defined but not used.
> >>  User can copy these example to his .c file when it using
> >rte_mtr_meter_policy_add().
> >
> >If you need to provide an example, we use the directory examples.
> >I see rte_mtr is not implemented in any example, so it could be a later
> >addition.
> >
> >
> We want, as a rule of thumb, to provide more code snippets and not
> necessarily full-blown example applications.
> Where do you suggest having that?
> In any case, I agree, this can be removed now to allow integration of rc1.
> Doc can be done afterward.
Thomas Monjalon April 14, 2021, 9:04 a.m. UTC | #10
14/04/2021 10:47, Asaf Penso:
> From: Thomas Monjalon
> >Cristian, Li, please remove useless context when replying.
> >
> >14/04/2021 06:55, Li Zhang:
> >> > > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
> >> > > + *   struct rte_mtr_meter_policy_params policy_1 =
> >> > > + *                                   (struct
> >> > > rte_mtr_meter_policy_params) {
> >> > > + *           .actions[RTE_COLOR_GREEN] = NULL,
> >> > > + *           .actions[RTE_COLOR_YELLOW] = NULL,
> >> > > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> >> > > + *                   {
> >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
> >> > > + *                   },
> >> > > + *                   {
> >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> >> > > + *                   },
> >> > > + *           },
> >> > > + *   };
> >> > > + *
> >> >
> >> > These two example policies should be available to be used straight
> >> > away, please make them real data structures, not comments.
> >
> >Wait, you are giving code examples as part of doxygen?
> >It's really too long, we don't do that.
> >
> >> > I suggest their names as: pass_color_policy_params and
> >> > drop_red_policy_params.
> >> >
> >> Thanks. Will change the names. But it can not be real data structures, since it
> >just one example define and no use code.
> >> It will bring build as below:
> >> error: 'drop_red_policy_params' defined but not used.
> >>  User can copy these example to his .c file when it using
> >rte_mtr_meter_policy_add().
> >
> >If you need to provide an example, we use the directory examples.
> >I see rte_mtr is not implemented in any example, so it could be a later
> >addition.
> >
> >
> We want, as a rule of thumb, to provide more code snippets and not necessarily full-blown example applications. 
> Where do you suggest having that?

In the examples directory, adding small functions.
Dumitrescu, Cristian April 14, 2021, 2 p.m. UTC | #11
> >14/04/2021 06:55, Li Zhang:
> >> > > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED -
> DROP
> >> > > + *   struct rte_mtr_meter_policy_params policy_1 =
> >> > > + *                                   (struct
> >> > > rte_mtr_meter_policy_params) {
> >> > > + *           .actions[RTE_COLOR_GREEN] = NULL,
> >> > > + *           .actions[RTE_COLOR_YELLOW] = NULL,
> >> > > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> >> > > + *                   {
> >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
> >> > > + *                   },
> >> > > + *                   {
> >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> >> > > + *                   },
> >> > > + *           },
> >> > > + *   };
> >> > > + *
> >> >
> >> > These two example policies should be available to be used straight
> >> > away, please make them real data structures, not comments.
> >
> >Wait, you are giving code examples as part of doxygen?
> >It's really too long, we don't do that.
> >
> >> > I suggest their names as: pass_color_policy_params and
> >> > drop_red_policy_params.
> >> >
> >> Thanks. Will change the names. But it can not be real data structures,
> since it
> >just one example define and no use code.
> >> It will bring build as below:
> >> error: 'drop_red_policy_params' defined but not used.
> >>  User can copy these example to his .c file when it using
> >rte_mtr_meter_policy_add().
> >

Although these could be looked at as examples, they are really more than examples: they are expected to be frequent policies that users would require, so it would be good to have them with the API itself.

Li, I agree we cannot instantiate structs in the header file, how about we place them as macros in the header file:

#define rte_mtr_policy_pass_color struct { \
...

#define rte_mtr_policy_drop_red struct { \
...

Regards,
Cristian
Li Zhang April 14, 2021, 4:21 p.m. UTC | #12
Hi Cristian,

Thank you for giving suggestion.
Will add in V7 patch.

Regards,
Li Zhang
> -----Original Message-----
> From: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>
> Sent: Wednesday, April 14, 2021 10:01 PM
> To: Asaf Penso <asafp@nvidia.com>; NBU-Contact-Thomas Monjalon
> <thomas@monjalon.net>; Li Zhang <lizh@nvidia.com>
> Cc: Ori Kam <orika@nvidia.com>; Slava Ovsiienko
> <viacheslavo@nvidia.com>; Matan Azrad <matan@nvidia.com>;
> lironh@marvell.com; Wisam Monther <wisamm@nvidia.com>; Li, Xiaoyun
> <xiaoyun.li@intel.com>; Singh, Jasvinder <jasvinder.singh@intel.com>; Yigit,
> Ferruh <ferruh.yigit@intel.com>; Andrew Rybchenko
> <andrew.rybchenko@oktetlabs.ru>; Ray Kinsella <mdr@ashroe.eu>; Jerin
> Jacob <jerinjacobk@gmail.com>; Hemant Agrawal
> <hemant.agrawal@nxp.com>; 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: [dpdk-dev] [PATCH v3 1/2] ethdev: add pre-defined meter policy
> API
> 
> External email: Use caution opening links or attachments
> 
> 
> > >14/04/2021 06:55, Li Zhang:
> > >> > > + * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED -
> > DROP
> > >> > > + *   struct rte_mtr_meter_policy_params policy_1 =
> > >> > > + *                                   (struct
> > >> > > rte_mtr_meter_policy_params) {
> > >> > > + *           .actions[RTE_COLOR_GREEN] = NULL,
> > >> > > + *           .actions[RTE_COLOR_YELLOW] = NULL,
> > >> > > + *           .actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
> > >> > > + *                   {
> > >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_DROP,
> > >> > > + *                   },
> > >> > > + *                   {
> > >> > > + *                           .type = RTE_FLOW_ACTION_TYPE_END,
> > >> > > + *                   },
> > >> > > + *           },
> > >> > > + *   };
> > >> > > + *
> > >> >
> > >> > These two example policies should be available to be used
> > >> > straight away, please make them real data structures, not comments.
> > >
> > >Wait, you are giving code examples as part of doxygen?
> > >It's really too long, we don't do that.
> > >
> > >> > I suggest their names as: pass_color_policy_params and
> > >> > drop_red_policy_params.
> > >> >
> > >> Thanks. Will change the names. But it can not be real data
> > >> structures,
> > since it
> > >just one example define and no use code.
> > >> It will bring build as below:
> > >> error: 'drop_red_policy_params' defined but not used.
> > >>  User can copy these example to his .c file when it using
> > >rte_mtr_meter_policy_add().
> > >
> 
> Although these could be looked at as examples, they are really more than
> examples: they are expected to be frequent policies that users would require,
> so it would be good to have them with the API itself.
> 
> Li, I agree we cannot instantiate structs in the header file, how about we
> place them as macros in the header file:
> 
> #define rte_mtr_policy_pass_color struct { \ ...
> 
> #define rte_mtr_policy_drop_red struct { \ ...
> 
> Regards,
> Cristian
diff mbox series

Patch

diff --git a/app/test-flow-perf/main.c b/app/test-flow-perf/main.c
index 0aef767350..c1f38cbec5 100644
--- a/app/test-flow-perf/main.c
+++ b/app/test-flow-perf/main.c
@@ -921,13 +921,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 f44116b087..fae79d4c85 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 113b37cddc..1b1b4368f6 100644
--- a/doc/guides/rel_notes/release_21_05.rst
+++ b/doc/guides/rel_notes/release_21_05.rst
@@ -161,7 +161,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_create()``, ``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..2a05a85cdb 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 create */
+static int
+pmd_mtr_meter_policy_create(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_create = pmd_mtr_meter_policy_create,
+	.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 6cc57136ac..d4fd36dd0e 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..9b03cf1d50 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 create */
+int
+rte_mtr_meter_policy_create(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_create)(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..9f6f5e1a45 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,136 @@  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.
+ *
+ * Two common examples to define meter policy action list:
+ * Example #1: GREEN - GREEN, YELLOW - YELLOW, RED - RED
+ *	struct rte_mtr_meter_policy_params policy_0 =
+ *					(struct rte_mtr_meter_policy_params) {
+ *		.actions[RTE_COLOR_GREEN] = (struct rte_flow_action[]) {
+ *			{
+ *				.type = RTE_FLOW_ACTION_TYPE_METER_COLOR,
+ *				.conf = &(struct rte_flow_action_meter_color) {
+ *					.color = RTE_COLOR_GREEN,
+ *				},
+ *			},
+ *			{
+ *				.type = RTE_FLOW_ACTION_TYPE_END,
+ *			},
+ *		},
+ *		.actions[RTE_COLOR_YELLOW] = (struct rte_flow_action[]) {
+ *			{
+ *				.type = RTE_FLOW_ACTION_TYPE_METER_COLOR,
+ *				.conf = &(struct rte_flow_action_meter_color) {
+ *					.color = RTE_COLOR_YELLOW,
+ *				},
+ *			},
+ *			{
+ *			.type = RTE_FLOW_ACTION_TYPE_END,
+ *			},
+ *		},
+ *		.actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
+ *			{
+ *				.type = RTE_FLOW_ACTION_TYPE_METER_COLOR,
+ *				.conf = &(struct rte_flow_action_meter_color) {
+ *					.color = RTE_COLOR_RED,
+ *				},
+ *			},
+ *			{
+ *				.type = RTE_FLOW_ACTION_TYPE_END,
+ *			},
+ *		},
+ *	};
+ *
+ * Example #2: GREEN - Do nothing, YELLOW - Do nothing, RED - DROP
+ *	struct rte_mtr_meter_policy_params policy_1 =
+ *					(struct rte_mtr_meter_policy_params) {
+ *		.actions[RTE_COLOR_GREEN] = NULL,
+ *		.actions[RTE_COLOR_YELLOW] = NULL,
+ *		.actions[RTE_COLOR_RED] = (struct rte_flow_action[]) {
+ *			{
+ *				.type = RTE_FLOW_ACTION_TYPE_DROP,
+ *			},
+ *			{
+ *				.type = RTE_FLOW_ACTION_TYPE_END,
+ *			},
+ *		},
+ *	};
+ *
+ * @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_create(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 +711,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 +726,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 +751,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..462a1e862c 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_create_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 create */
+	rte_mtr_meter_policy_create_t meter_policy_create;
+
+	/** 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..0045baff8c 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_create;
+	rte_mtr_meter_policy_delete;
+	rte_mtr_meter_policy_update;
+	rte_mtr_meter_policy_validate;
 };
 
 INTERNAL {