diff --git a/Documentation/howto/dpdk.rst b/Documentation/howto/dpdk.rst
index 04609b20bd21..02fc568770ee 100644
--- a/Documentation/howto/dpdk.rst
+++ b/Documentation/howto/dpdk.rst
@@ -401,10 +401,11 @@ Supported actions for hardware offload are:
 - Modification of IPv6 (set_field:<ADDR>->ipv6_src/ipv6_dst/mod_nw_ttl).
 - Clone/output (tnl_push and output) for encapsulating over a tunnel.
 - Tunnel pop, for packets received on physical ports.
+- Meter.
 
 .. note::
-  Tunnel offloads are experimental APIs in DPDK. In order to enable it,
-  compile with -DALLOW_EXPERIMENTAL_API.
+  Tunnel offloads and Meter offloads are experimental APIs in DPDK. To enable
+  these features, compile with -DALLOW_EXPERIMENTAL_API.
 
 Multiprocess
 ------------
diff --git a/lib/netdev-offload-provider.h b/lib/netdev-offload-provider.h
index 9108856d18d1..b02531a0f813 100644
--- a/lib/netdev-offload-provider.h
+++ b/lib/netdev-offload-provider.h
@@ -98,27 +98,42 @@ struct netdev_flow_api {
      * and the configuration in 'config'. On failure, a non-zero error code is
      * returned.
      *
+     * If the datapath is netdev, the api needs the param struct netdev *,
+     * If the datapath is system, the param struct netdev* is unused and
+     * should be NULL.
+     *
      * The meter id specified through 'config->meter_id' is ignored. */
-    int (*meter_set)(ofproto_meter_id meter_id,
+    int (*meter_set)(struct netdev *,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_config *config);
 
     /* Queries HW for meter stats with the given 'meter_id'. Store the stats
      * of dropped packets to band 0. On failure, a non-zero error code is
      * returned.
      *
+     * If the datapath is netdev, the api needs the param struct netdev *,
+     * If the datapath is system, the param struct netdev* is unused and
+     * should be NULL.
+     *
      * Note that the 'stats' structure is already initialized, and only the
      * available statistics should be incremented, not replaced. Those fields
      * are packet_in_count, byte_in_count and band[]->byte_count and
      * band[]->packet_count. */
-    int (*meter_get)(ofproto_meter_id meter_id,
+    int (*meter_get)(struct netdev *,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats);
 
     /* Removes meter 'meter_id' from HW. Store the stats of dropped packets to
      * band 0. On failure, a non-zero error code is returned.
      *
+     * If the datapath is netdev, the api needs the param struct netdev *,
+     * If the datapath is system, the param struct netdev* is unused and
+     * should be NULL.
+     *
      * 'stats' may be passed in as NULL if no stats are needed, See the above
      * function for additional details on the 'stats' usage. */
-    int (*meter_del)(ofproto_meter_id meter_id,
+    int (*meter_del)(struct netdev *,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats);
 
     /* Initializies the netdev flow api.
diff --git a/lib/netdev-offload-tc.c b/lib/netdev-offload-tc.c
index ce7f8ad97306..6a965f4d366b 100644
--- a/lib/netdev-offload-tc.c
+++ b/lib/netdev-offload-tc.c
@@ -2892,7 +2892,8 @@ meter_free_police_index(uint32_t police_index)
 }
 
 static int
-meter_tc_set_policer(ofproto_meter_id meter_id,
+meter_tc_set_policer(struct netdev *netdev OVS_UNUSED,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_config *config)
 {
     uint32_t police_index;
@@ -2946,7 +2947,8 @@ meter_tc_set_policer(ofproto_meter_id meter_id,
 }
 
 static int
-meter_tc_get_policer(ofproto_meter_id meter_id,
+meter_tc_get_policer(struct netdev *netdev OVS_UNUSED,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats)
 {
     uint32_t police_index;
@@ -2965,7 +2967,8 @@ meter_tc_get_policer(ofproto_meter_id meter_id,
 }
 
 static int
-meter_tc_del_policer(ofproto_meter_id meter_id,
+meter_tc_del_policer(struct netdev *netdev OVS_UNUSED,
+                     ofproto_meter_id meter_id,
                      struct ofputil_meter_stats *stats)
 {
     uint32_t police_index;
diff --git a/lib/netdev-offload.c b/lib/netdev-offload.c
index 4592262bd34e..ae38fb7b2fec 100644
--- a/lib/netdev-offload.c
+++ b/lib/netdev-offload.c
@@ -206,7 +206,7 @@ meter_offload_set(ofproto_meter_id meter_id,
 
     CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
         if (rfa->flow_api->meter_set) {
-            int ret = rfa->flow_api->meter_set(meter_id, config);
+            int ret = rfa->flow_api->meter_set(NULL, meter_id, config);
             if (ret) {
                 VLOG_DBG_RL(&rl, "Failed setting meter %u for flow api %s, "
                             "error %d", meter_id.uint32, rfa->flow_api->type,
@@ -225,7 +225,7 @@ meter_offload_get(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
 
     CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
         if (rfa->flow_api->meter_get) {
-            int ret = rfa->flow_api->meter_get(meter_id, stats);
+            int ret = rfa->flow_api->meter_get(NULL, meter_id, stats);
             if (ret) {
                 VLOG_DBG_RL(&rl, "Failed getting meter %u for flow api %s, "
                             "error %d", meter_id.uint32, rfa->flow_api->type,
@@ -244,7 +244,7 @@ meter_offload_del(ofproto_meter_id meter_id, struct ofputil_meter_stats *stats)
 
     CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
         if (rfa->flow_api->meter_del) {
-            int ret = rfa->flow_api->meter_del(meter_id, stats);
+            int ret = rfa->flow_api->meter_del(NULL, meter_id, stats);
             if (ret) {
                 VLOG_DBG_RL(&rl, "Failed deleting meter %u for flow api %s, "
                             "error %d", meter_id.uint32, rfa->flow_api->type,
@@ -895,3 +895,132 @@ netdev_set_flow_api_enabled(const struct smap *ovs_other_config)
         }
     }
 }
+struct dpdk_meter_aux {
+    struct ofputil_meter_config *config;
+    struct ofputil_meter_stats *stats;
+    ofproto_meter_id meter_id;
+    odp_port_t odp_port;
+};
+
+static bool
+dpdk_meter_set_cb(struct netdev *netdev,
+               odp_port_t odp_port,
+               void *aux_)
+{
+    struct netdev_registered_flow_api *rfa;
+    struct dpdk_meter_aux *aux = aux_;
+    ofproto_meter_id meter_id;
+    int ret;
+
+    meter_id = aux->meter_id;
+    CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
+        if (rfa->flow_api->meter_set) {
+            ret = rfa->flow_api->meter_set(netdev, meter_id, aux->config);
+            if (ret) {
+                VLOG_DBG_RL(&rl, "Failed setting meter %u for flow api %s with"
+                            " port number %u, error %d", meter_id.uint32,
+                            rfa->flow_api->type, odp_port, ret);
+            }
+        }
+    }
+
+    return 0;
+}
+
+void
+dpdk_meter_offload_set(const char *dpif_type,
+                       ofproto_meter_id meter_id,
+                       struct ofputil_meter_config *config)
+{
+    struct dpdk_meter_aux aux = {
+        .meter_id = meter_id,
+        .config = config,
+    };
+    netdev_ports_traverse(dpif_type, dpdk_meter_set_cb, &aux);
+}
+
+static bool
+dpdk_meter_get_cb(struct netdev *netdev,
+               odp_port_t odp_port,
+               void *aux_)
+{
+    struct ofputil_meter_stats *stats, offload_stats;
+    struct netdev_registered_flow_api *rfa;
+    struct dpdk_meter_aux *aux = aux_;
+    ofproto_meter_id meter_id;
+    int ret;
+
+    memset(&offload_stats, 0, sizeof(struct ofputil_meter_stats));
+    meter_id = aux->meter_id;
+    stats = aux->stats;
+    CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
+        if (rfa->flow_api->meter_get) {
+            ret = rfa->flow_api->meter_get(netdev, meter_id, &offload_stats);
+            if (ret) {
+                VLOG_DBG_RL(&rl, "Failed getting meter %u for flow api %s with"
+                            " port number %u, error %d", meter_id.uint32,
+                            rfa->flow_api->type, odp_port, ret);
+            }
+        }
+    }
+
+    if (!offload_stats.byte_in_count && !offload_stats.packet_in_count) {
+           return 0;
+    }
+    stats->byte_in_count += offload_stats.byte_in_count;
+    stats->packet_in_count += offload_stats.packet_in_count;
+
+    return 0;
+}
+
+void
+dpdk_meter_offload_get(const char *dpif_type,
+                       ofproto_meter_id meter_id,
+                       struct ofputil_meter_stats *stats)
+{
+    struct dpdk_meter_aux aux = {
+        .meter_id = meter_id,
+        .stats = stats,
+    };
+    netdev_ports_traverse(dpif_type, dpdk_meter_get_cb, &aux);
+}
+
+static bool
+dpdk_meter_del_cb(struct netdev *netdev,
+               odp_port_t odp_port,
+               void *aux_)
+{
+    struct netdev_registered_flow_api *rfa;
+    struct ofputil_meter_stats *stats;
+    struct dpdk_meter_aux *aux = aux_;
+    ofproto_meter_id meter_id;
+    int ret;
+
+    meter_id = aux->meter_id;
+    stats = aux->stats;
+    CMAP_FOR_EACH (rfa, cmap_node, &netdev_flow_apis) {
+        if (rfa->flow_api->meter_del) {
+            ret = rfa->flow_api->meter_del(netdev, meter_id, stats);
+            if (ret) {
+                VLOG_DBG_RL(&rl, "Failed deleting meter %u for flow api %s"
+                            " with port number %u, error %d", meter_id.uint32,
+                            rfa->flow_api->type, odp_port, ret);
+            }
+        }
+    }
+
+    return 0;
+}
+
+void
+dpdk_meter_offload_del(const char *dpif_type,
+                       ofproto_meter_id meter_id,
+                       struct ofputil_meter_stats *stats)
+{
+    struct dpdk_meter_aux aux = {
+        .meter_id = meter_id,
+        .stats = stats,
+    };
+
+    netdev_ports_traverse(dpif_type, dpdk_meter_del_cb, &aux);
+}
diff --git a/lib/netdev-offload.h b/lib/netdev-offload.h
index edc843cd99a3..e53f70a277b3 100644
--- a/lib/netdev-offload.h
+++ b/lib/netdev-offload.h
@@ -161,6 +161,15 @@ int netdev_ports_get_n_flows(const char *dpif_type,
 void meter_offload_set(ofproto_meter_id, struct ofputil_meter_config *);
 int meter_offload_get(ofproto_meter_id, struct ofputil_meter_stats *);
 int meter_offload_del(ofproto_meter_id, struct ofputil_meter_stats *);
+void dpdk_meter_offload_set(const char *dpif_type,
+                            ofproto_meter_id meter_id,
+                            struct ofputil_meter_config *config);
+void dpdk_meter_offload_del(const char *dpif_type,
+                            ofproto_meter_id meter_id_,
+                            struct ofputil_meter_stats *stats);
+void dpdk_meter_offload_get(const char *dpif_type,
+                            ofproto_meter_id meter_id_,
+                            struct ofputil_meter_stats *stats);
 
 #ifdef  __cplusplus
 }
