diff --git a/lib/librte_ethdev/rte_flow.h b/lib/librte_ethdev/rte_flow.h
index 5f38aa7fa4..6d2b86592d 100644
--- a/lib/librte_ethdev/rte_flow.h
+++ b/lib/librte_ethdev/rte_flow.h
@@ -2480,6 +2480,13 @@ struct rte_flow_action_port_id {
 	uint32_t id; /**< DPDK port ID. */
 };
 
+/**
+ * Opaque type returned after successfully creating a meter.
+ *
+ * This handle can be used to manage the related meter (e.g. to destroy it).
+ */
+struct rte_mtr;
+
 /**
  * RTE_FLOW_ACTION_TYPE_METER
  *
@@ -2489,7 +2496,7 @@ struct rte_flow_action_port_id {
  * next item with their color set by the MTR object.
  */
 struct rte_flow_action_meter {
-	uint32_t mtr_id; /**< MTR object ID created with rte_mtr_create(). */
+	struct rte_mtr *mtr; /**< MTR object created with rte_mtr_create(). */
 };
 
 /**
diff --git a/lib/librte_ethdev/rte_mtr.c b/lib/librte_ethdev/rte_mtr.c
index fccec3760b..e407c6f956 100644
--- a/lib/librte_ethdev/rte_mtr.c
+++ b/lib/librte_ethdev/rte_mtr.c
@@ -57,6 +57,19 @@ rte_mtr_ops_get(uint16_t port_id, struct rte_mtr_error *error)
 	ops->func;					\
 })
 
+#define RTE_MTR_FUNC_PTR(port_id, func)			\
+({							\
+	const struct rte_mtr_ops *ops =			\
+		rte_mtr_ops_get(port_id, error);	\
+	if (ops == NULL)				\
+		return NULL;				\
+							\
+	if (ops->func == NULL)				\
+		return NULL;				\
+							\
+	ops->func;					\
+})
+
 /* MTR capabilities get */
 int
 rte_mtr_capabilities_get(uint16_t port_id,
@@ -69,26 +82,25 @@ rte_mtr_capabilities_get(uint16_t port_id,
 }
 
 /* MTR meter profile add */
-int
+struct rte_mtr_profile *
 rte_mtr_meter_profile_add(uint16_t port_id,
-	uint32_t meter_profile_id,
 	struct rte_mtr_meter_profile *profile,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
-	return RTE_MTR_FUNC(port_id, meter_profile_add)(dev,
-		meter_profile_id, profile, error);
+	return RTE_MTR_FUNC_PTR(port_id, meter_profile_add)(dev,
+		profile, error);
 }
 
 /** MTR meter profile delete */
 int
 rte_mtr_meter_profile_delete(uint16_t port_id,
-	uint32_t meter_profile_id,
+	struct rte_mtr_profile *profile,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, meter_profile_delete)(dev,
-		meter_profile_id, error);
+		profile, error);
 }
 
 /* MTR meter policy validate */
@@ -103,126 +115,123 @@ rte_mtr_meter_policy_validate(uint16_t port_id,
 }
 
 /* MTR meter policy add */
-int
+struct rte_mtr_policy *
 rte_mtr_meter_policy_add(uint16_t port_id,
-	uint32_t policy_id,
 	const struct rte_flow_action *actions[RTE_COLORS],
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
-	return RTE_MTR_FUNC(port_id, meter_policy_add)(dev,
-		policy_id, actions, error);
+	return RTE_MTR_FUNC_PTR(port_id, meter_policy_add)(dev,
+		actions, error);
 }
 
 /** MTR meter policy delete */
 int
 rte_mtr_meter_policy_delete(uint16_t port_id,
-	uint32_t policy_id,
+	struct rte_mtr_policy *policy,
 	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);
+		policy, error);
 }
 
 /** MTR object create */
-int
+struct rte_mtr *
 rte_mtr_create(uint16_t port_id,
-	uint32_t mtr_id,
 	struct rte_mtr_params *params,
 	int shared,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
-	return RTE_MTR_FUNC(port_id, create)(dev,
-		mtr_id, params, shared, error);
+	return RTE_MTR_FUNC_PTR(port_id, create)(dev, params, shared, error);
 }
 
 /** MTR object destroy */
 int
 rte_mtr_destroy(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, destroy)(dev,
-		mtr_id, error);
+		mtr, error);
 }
 
 /** MTR object meter enable */
 int
 rte_mtr_meter_enable(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, meter_enable)(dev,
-		mtr_id, error);
+		mtr, error);
 }
 
 /** MTR object meter disable */
 int
 rte_mtr_meter_disable(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, meter_disable)(dev,
-		mtr_id, error);
+		mtr, error);
 }
 
 /** MTR object meter profile update */
 int
 rte_mtr_meter_profile_update(uint16_t port_id,
-	uint32_t mtr_id,
-	uint32_t meter_profile_id,
+	struct rte_mtr *mtr,
+	struct rte_mtr_profile *profile,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, meter_profile_update)(dev,
-		mtr_id, meter_profile_id, error);
+		mtr, profile, error);
 }
 
 /** MTR object meter policy update */
 int
 rte_mtr_meter_policy_update(uint16_t port_id,
-	uint32_t mtr_id,
-	uint32_t meter_policy_id,
+	struct rte_mtr *mtr,
+	struct rte_mtr_policy *policy,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, meter_policy_update)(dev,
-		mtr_id, meter_policy_id, error);
+		mtr, policy, error);
 }
 
 /** MTR object meter DSCP table update */
 int
 rte_mtr_meter_dscp_table_update(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	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, meter_dscp_table_update)(dev,
-		mtr_id, dscp_table, error);
+		mtr, dscp_table, error);
 }
 
 /** MTR object enabled stats update */
 int
 rte_mtr_stats_update(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	uint64_t stats_mask,
 	struct rte_mtr_error *error)
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, stats_update)(dev,
-		mtr_id, stats_mask, error);
+		mtr, stats_mask, error);
 }
 
 /** MTR object stats read */
 int
 rte_mtr_stats_read(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_stats *stats,
 	uint64_t *stats_mask,
 	int clear,
@@ -230,5 +239,5 @@ rte_mtr_stats_read(uint16_t port_id,
 {
 	struct rte_eth_dev *dev = &rte_eth_devices[port_id];
 	return RTE_MTR_FUNC(port_id, stats_read)(dev,
-		mtr_id, stats, stats_mask, clear, error);
+		mtr, stats, stats_mask, clear, error);
 }
diff --git a/lib/librte_ethdev/rte_mtr.h b/lib/librte_ethdev/rte_mtr.h
index 07961f2777..2b20e55079 100644
--- a/lib/librte_ethdev/rte_mtr.h
+++ b/lib/librte_ethdev/rte_mtr.h
@@ -181,8 +181,8 @@ struct rte_mtr_meter_profile {
  * @see enum rte_mtr_stats_type
  */
 struct rte_mtr_params {
-	/** Meter profile ID. */
-	uint32_t meter_profile_id;
+	/** Meter profile. */
+	struct rte_mtr_profile *profile;
 
 	/** Meter input color in case of MTR object chaining. When non-zero: if
 	 * a previous MTR object is enabled in the same flow, then the color
@@ -221,8 +221,8 @@ struct rte_mtr_params {
 	 */
 	uint64_t stats_mask;
 
-	/** Meter policy ID. */
-	uint32_t meter_policy_id;
+	/** Meter policy. */
+	struct rte_mtr_policy *policy;
 };
 
 /**
@@ -395,28 +395,32 @@ rte_mtr_capabilities_get(uint16_t port_id,
 	struct rte_mtr_capabilities *cap,
 	struct rte_mtr_error *error);
 
+/**
+ * Opaque type returned after successfully creating a profile.
+ *
+ * This handle can be used to manage the related profile (e.g. to destroy it).
+ */
+struct rte_mtr_profile;
+
 /**
  * Meter profile add
  *
- * Create a new meter profile with ID set to *meter_profile_id*. The new profile
+ * Create a new meter profile. The new profile
  * is used to create one or several MTR objects.
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
- * @param[in] meter_profile_id
- *   ID for the new meter profile. Needs to be unused by any of the existing
- *   meter profiles added for the current port.
  * @param[in] profile
  *   Meter profile parameters. Needs to be pre-allocated and valid.
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
  * @return
- *   0 on success, non-zero error code otherwise.
+ *   A valid handle in case of success, NULL otherwise and rte_errno is set
+ *   to the positive version of one of the error codes.
  */
 __rte_experimental
-int
+struct rte_mtr_profile *
 rte_mtr_meter_profile_add(uint16_t port_id,
-	uint32_t meter_profile_id,
 	struct rte_mtr_meter_profile *profile,
 	struct rte_mtr_error *error);
 
@@ -428,8 +432,8 @@ rte_mtr_meter_profile_add(uint16_t port_id,
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
- * @param[in] meter_profile_id
- *   Meter profile ID. Needs to be the valid.
+ * @param[in] profile
+ *   Meter profile pointer. Needs to be the valid.
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
  * @return
@@ -438,16 +442,15 @@ rte_mtr_meter_profile_add(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_profile_delete(uint16_t port_id,
-	uint32_t meter_profile_id,
+	struct rte_mtr_profile *profile,
 	struct rte_mtr_error *error);
 
 /**
- * Policy id 0 is default policy.
- * Action per color as below:
- * green - no action, yellow - no action, red - drop
- * It can be used without creating it by the rte_mtr_meter_policy_add function.
+ * Opaque type returned after successfully creating a policy.
+ *
+ * This handle can be used to manage the related policy (e.g. to destroy it).
  */
-#define RTE_MTR_DEFAULT_POLICY_ID 0
+struct rte_mtr_policy;
 
 /**
  * Check whether a meter policy can be created on a given port.
@@ -478,7 +481,6 @@ rte_mtr_meter_profile_delete(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_policy_validate(uint16_t port_id,
-	uint32_t policy_id,
 	const struct rte_flow_action *actions[RTE_COLORS],
 	struct rte_mtr_error *error);
 
@@ -490,8 +492,6 @@ rte_mtr_meter_policy_validate(uint16_t port_id,
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
- * @param[in] policy_id
- *   Policy identifier for the new meter policy.
  * @param[in] actions
  *   Associated actions per color.
  *   list NULL is legal and means no special action.
@@ -499,12 +499,12 @@ rte_mtr_meter_policy_validate(uint16_t port_id,
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
  * @return
- *   0 on success, non-zero error code otherwise.
+ *   A valid handle in case of success, NULL otherwise and rte_errno is set
+ *   to the positive version of one of the error codes.
  */
 __rte_experimental
-int
+struct rte_mtr_policy *
 rte_mtr_meter_policy_add(uint16_t port_id,
-	uint32_t policy_id,
 	const struct rte_flow_action *actions[RTE_COLORS],
 	struct rte_mtr_error *error);
 
@@ -516,8 +516,8 @@ rte_mtr_meter_policy_add(uint16_t port_id,
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
- * @param[in] policy_id
- *   Policy identifier.
+ * @param[in] policy
+ *   Policy pointer. Needs to be valid.
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
  * @return
@@ -526,20 +526,28 @@ rte_mtr_meter_policy_add(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_policy_delete(uint16_t port_id,
-	uint32_t policy_id,
+	struct rte_mtr_policy *policy,
 	struct rte_mtr_error *error);
 
+/**
+ * Opaque type returned after successfully creating a meter.
+ *
+ * This handle can be used to manage the related meter (e.g. to destroy it).
+ */
+struct rte_mtr;
+
 /**
  * MTR object create
  *
  * Create a new MTR object for the current port. This object is run as part of
  * associated flow action for traffic metering and policing.
+ * Policy pointer NULL is default policy.
+ * Action per color as below:
+ * green - no action, yellow - no action, red - drop
+ * It can be used without creating it by the rte_mtr_meter_policy_add function.
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
- * @param[in] mtr_id
- *   MTR object ID. Needs to be unused by any of the existing MTR objects.
- *   created for the current port.
  * @param[in] params
  *   MTR object params. Needs to be pre-allocated and valid.
  * @param[in] shared
@@ -548,14 +556,14 @@ rte_mtr_meter_policy_delete(uint16_t port_id,
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
  * @return
- *   0 on success, non-zero error code otherwise.
+ *   A valid handle in case of success, NULL otherwise and rte_errno is set
+ *   to the positive version of one of the error codes.
  *
  * @see enum rte_flow_action_type::RTE_FLOW_ACTION_TYPE_METER
  */
 __rte_experimental
-int
+struct rte_mtr *
 rte_mtr_create(uint16_t port_id,
-	uint32_t mtr_id,
 	struct rte_mtr_params *params,
 	int shared,
 	struct rte_mtr_error *error);
@@ -568,8 +576,8 @@ rte_mtr_create(uint16_t port_id,
  *
  * @param[in] port_id
  *   The port identifier of the Ethernet device.
- * @param[in] mtr_id
- *   MTR object ID. Needs to be valid.
+ * @param[in] mtr
+ *   MTR pointer. Needs to be valid.
  *   created for the current port.
  * @param[out] error
  *   Error details. Filled in only on error, when not NULL.
@@ -579,7 +587,7 @@ rte_mtr_create(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_destroy(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error);
 
 /**
@@ -607,7 +615,7 @@ rte_mtr_destroy(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_disable(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error);
 
 /**
@@ -629,7 +637,7 @@ rte_mtr_meter_disable(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_enable(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error);
 
 /**
@@ -649,8 +657,8 @@ rte_mtr_meter_enable(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_profile_update(uint16_t port_id,
-	uint32_t mtr_id,
-	uint32_t meter_profile_id,
+	struct rte_mtr *mtr,
+	struct rte_mtr_profile *profile,
 	struct rte_mtr_error *error);
 
 /**
@@ -660,8 +668,6 @@ rte_mtr_meter_profile_update(uint16_t port_id,
  *   The port identifier of the Ethernet device.
  * @param[in] mtr_id
  *   MTR object ID. Needs to be valid.
- * @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
@@ -670,8 +676,8 @@ rte_mtr_meter_profile_update(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_policy_update(uint16_t port_id,
-	uint32_t mtr_id,
-	uint32_t meter_policy_id,
+	struct rte_mtr *mtr,
+	struct rte_mtr_policy *policy,
 	struct rte_mtr_error *error);
 
 /**
@@ -695,7 +701,7 @@ rte_mtr_meter_policy_update(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_meter_dscp_table_update(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	enum rte_color *dscp_table,
 	struct rte_mtr_error *error);
 
@@ -720,7 +726,7 @@ rte_mtr_meter_dscp_table_update(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_stats_update(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	uint64_t stats_mask,
 	struct rte_mtr_error *error);
 
@@ -752,7 +758,7 @@ rte_mtr_stats_update(uint16_t port_id,
 __rte_experimental
 int
 rte_mtr_stats_read(uint16_t port_id,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_stats *stats,
 	uint64_t *stats_mask,
 	int clear,
diff --git a/lib/librte_ethdev/rte_mtr_driver.h b/lib/librte_ethdev/rte_mtr_driver.h
index 1ad8fb4c40..d7a8853b51 100644
--- a/lib/librte_ethdev/rte_mtr_driver.h
+++ b/lib/librte_ethdev/rte_mtr_driver.h
@@ -30,82 +30,80 @@ typedef int (*rte_mtr_capabilities_get_t)(struct rte_eth_dev *dev,
 	struct rte_mtr_error *error);
 /**< @internal MTR capabilities get */
 
-typedef int (*rte_mtr_meter_profile_add_t)(struct rte_eth_dev *dev,
-	uint32_t meter_profile_id,
+typedef struct rte_mtr_profile *(*rte_mtr_meter_profile_add_t)
+	(struct rte_eth_dev *dev,
 	struct rte_mtr_meter_profile *profile,
 	struct rte_mtr_error *error);
 /**< @internal MTR meter profile add */
 
 typedef int (*rte_mtr_meter_profile_delete_t)(struct rte_eth_dev *dev,
-	uint32_t meter_profile_id,
+	struct rte_mtr_profile *profile,
 	struct rte_mtr_error *error);
 /**< @internal MTR meter profile delete */
 
 typedef int (*rte_mtr_meter_policy_validate_t)(struct rte_eth_dev *dev,
-	uint32_t policy_id,
 	const struct rte_flow_action *actions[RTE_COLORS],
 	struct rte_mtr_error *error);
 /**< @internal MTR meter policy validate */
 
-typedef int (*rte_mtr_meter_policy_add_t)(struct rte_eth_dev *dev,
-	uint32_t policy_id,
+typedef struct rte_mtr_policy *(*rte_mtr_meter_policy_add_t)
+	(struct rte_eth_dev *dev,
 	const struct rte_flow_action *actions[RTE_COLORS],
 	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_policy *policy,
 	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,
+typedef struct rte_mtr *(*rte_mtr_create_t)(struct rte_eth_dev *dev,
 	struct rte_mtr_params *params,
 	int shared,
 	struct rte_mtr_error *error);
 /**< @internal MTR object create */
 
 typedef int (*rte_mtr_destroy_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error);
 /**< @internal MTR object destroy */
 
 typedef int (*rte_mtr_meter_enable_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error);
 /**< @internal MTR object meter enable */
 
 typedef int (*rte_mtr_meter_disable_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_error *error);
 /**< @internal MTR object meter disable */
 
 typedef int (*rte_mtr_meter_profile_update_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
-	uint32_t meter_profile_id,
+	struct rte_mtr *mtr,
+	struct rte_mtr_profile *profile,
 	struct rte_mtr_error *error);
 /**< @internal MTR object meter profile update */
 
 typedef int (*rte_mtr_meter_policy_update_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
-	uint32_t meter_policy_id,
+	struct rte_mtr *mtr,
+	struct rte_mtr_policy *policy,
 	struct rte_mtr_error *error);
 /**< @internal MTR object meter policy update */
 
 typedef int (*rte_mtr_meter_dscp_table_update_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	enum rte_color *dscp_table,
 	struct rte_mtr_error *error);
 /**< @internal MTR object meter DSCP table update */
 
 typedef int (*rte_mtr_stats_update_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	uint64_t stats_mask,
 	struct rte_mtr_error *error);
 /**< @internal MTR object enabled stats update */
 
 typedef int (*rte_mtr_stats_read_t)(struct rte_eth_dev *dev,
-	uint32_t mtr_id,
+	struct rte_mtr *mtr,
 	struct rte_mtr_stats *stats,
 	uint64_t *stats_mask,
 	int clear,
