diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h
index aaeb034..679fac9 100644
--- a/datapath/linux/compat/include/linux/openvswitch.h
+++ b/datapath/linux/compat/include/linux/openvswitch.h
@@ -819,6 +819,56 @@ struct ovs_action_push_eth {
 };
 
 /**
+ * enum ovs_drop_reason - Reasons for installing %OVS_ACTION_ATTR_DROP. 
+ * @OVS_DROP_REASON_OF_PIPELINE: Explicit drop action in the pipeline.
+ * @OVS_DROP_REASON_BRIDGE_NOT_FOUND: Xlation error generated due to
+ * unable to determine bridge.
+ * @OVS_DROP_REASON_RECURSION_TOO_DEEP: Xlation error generated due to
+ * recursion reached maximum depth.
+ * @OVS_DROP_REASON_TOO_MANY_RESUBMITS: Xlation error generated due to
+ * too many resubmits.
+ * @OVS_DROP_REASON_STACK_TOO_DEEP: Xlation error generated due to stack
+ * too deep.
+ * @OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT: Xlation error generated
+ * due to no recirculation context.
+ * @OVS_DROP_REASON_RECIRCULATION_CONFLICT: Xlation error generated due to
+ * conflict in recirculation context.
+ * @OVS_DROP_REASON_TOO_MANY_MPLS_LABELS: Xlation error generated due to 
+ * too many mpls labels.
+ * @OVS_DROP_REASON_INVALID_TUNNEL_METADATA: Xlation error generated due to
+ * invalid tunnel metadata.
+ * @OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE: Xlation error generated due to
+ * unsupported packet type.
+ * @OVS_DROP_REASON_CONGESTION: Xlation error generated due to ecn mismatch
+ * during tunnel decapsulation.
+ * @OVS_DROP_REASON_FORWARDING_DISABLED: Xlation error generated due to
+ * forwarding is disabled.
+ */
+enum ovs_drop_reason {
+    OVS_DROP_REASON_OF_PIPELINE = 0,
+    OVS_DROP_REASON_BRIDGE_NOT_FOUND,
+    OVS_DROP_REASON_RECURSION_TOO_DEEP,
+    OVS_DROP_REASON_TOO_MANY_RESUBMITS,
+    OVS_DROP_REASON_STACK_TOO_DEEP,
+    OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT,
+    OVS_DROP_REASON_RECIRCULATION_CONFLICT,
+    OVS_DROP_REASON_TOO_MANY_MPLS_LABELS,
+    OVS_DROP_REASON_INVALID_TUNNEL_METADATA,
+    OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE,
+    OVS_DROP_REASON_CONGESTION,
+    OVS_DROP_REASON_FORWARDING_DISABLED,
+    OVS_DROP_REASON_MAX,
+};
+
+/*
+ * struct ovs_action_drop - %OVS_ACTION_ATTR_DROP action argument.
+ * @drop_reason: Reason for installing drop action.
+ */
+struct ovs_action_drop {
+    enum ovs_drop_reason drop_reason;    
+};
+
+/**
  * enum ovs_nat_attr - Attributes for %OVS_CT_ATTR_NAT.
  *
  * @OVS_NAT_ATTR_SRC: Flag for Source NAT (mangle source address/port).
@@ -935,6 +985,7 @@ enum ovs_action_attr {
 	OVS_ACTION_ATTR_PUSH_NSH,     /* Nested OVS_NSH_KEY_ATTR_*. */
 	OVS_ACTION_ATTR_POP_NSH,      /* No argument. */
 	OVS_ACTION_ATTR_METER,         /* u32 meter number. */
+        OVS_ACTION_ATTR_DROP,         /* explicit drop action. */
 
 #ifndef __KERNEL__
 	OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
diff --git a/lib/dpif-netdev-perf.c b/lib/dpif-netdev-perf.c
index 13f1010..56ca9c6 100644
--- a/lib/dpif-netdev-perf.c
+++ b/lib/dpif-netdev-perf.c
@@ -388,6 +388,33 @@ pmd_perf_read_counters(struct pmd_perf_stats *s,
     }
 }
 
+void
+pmd_perf_read_drop_counters(struct pmd_perf_stats *s,
+                            struct dpif_dp_drop_stats *drop_stats)
+{
+    uint64_t val;
+    int i;
+
+    for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.rx_drops[i], &val);
+        drop_stats->rx_drops[i] += val - s->drop_counters.zero.rx_drops[i];
+    }
+    for (i = 0; i < OVS_DROP_REASON_MAX; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.drop_action_drops[i], &val);
+        drop_stats->drop_action_drops[i] += val -
+                                s->drop_counters.zero.drop_action_drops[i];
+    }
+    for (i = 0; i < DPIF_DP_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.dp_drops[i], &val);
+        drop_stats->dp_drops[i] += val - s->drop_counters.zero.dp_drops[i];
+    }
+    for (i = 0; i < DPIF_TX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.tx_drops[i], &val);
+        drop_stats->tx_drops[i] += val - s->drop_counters.zero.tx_drops[i];
+    }
+
+}
+
 /* This function clears the PMD performance counters from within the PMD
  * thread or from another thread when the PMD thread is not executing its
  * poll loop. */
@@ -438,6 +465,41 @@ pmd_perf_stats_clear(struct pmd_perf_stats *s)
     }
 }
 
+void
+pmd_perf_drop_stats_clear(struct pmd_perf_stats *s)
+{
+    int i;
+    uint64_t rx_drops;
+    uint64_t drop_action_drops;
+    uint64_t dp_drops;
+    uint64_t tx_drops;
+
+    for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.rx_drops[i],
+                            &rx_drops);
+        atomic_store_relaxed(&s->drop_counters.zero.rx_drops[i],
+                             rx_drops);
+    }
+    for (i = 0; i < OVS_DROP_REASON_MAX; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.drop_action_drops[i],
+                            &drop_action_drops);
+        atomic_store_relaxed(&s->drop_counters.zero.drop_action_drops[i],
+                             drop_action_drops);
+    }
+    for (i = 0; i < DPIF_DP_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.dp_drops[i],
+                            &dp_drops);
+        atomic_store_relaxed(&s->drop_counters.zero.dp_drops[i],
+                             dp_drops);
+    }
+    for (i = 0; i < DPIF_TX_MAX_DROP; i++) {
+        atomic_read_relaxed(&s->drop_counters.n.tx_drops[i],
+                            &tx_drops);
+        atomic_store_relaxed(&s->drop_counters.zero.tx_drops[i],
+                             tx_drops);
+    }
+}
+
 /* Functions recording PMD metrics per iteration. */
 
 void
diff --git a/lib/dpif-netdev-perf.h b/lib/dpif-netdev-perf.h
index 299d52a..af54dfc 100644
--- a/lib/dpif-netdev-perf.h
+++ b/lib/dpif-netdev-perf.h
@@ -33,6 +33,7 @@
 #include "timeval.h"
 #include "unixctl.h"
 #include "util.h"
+#include "dpif.h"
 
 #ifdef  __cplusplus
 extern "C" {
@@ -91,6 +92,21 @@ struct pmd_counters {
     uint64_t zero[PMD_N_STATS];         /* Value at last _clear().  */
 };
 
+/* Drop statistics maintained at per PMD level.
+ * It uses the same update/clear frame work used for other pmd_counters. */
+struct pmd_drop_stats {
+    atomic_uint64_t rx_drops[DPIF_RX_MAX_DROP];
+    atomic_uint64_t drop_action_drops[OVS_DROP_REASON_MAX];
+    atomic_uint64_t dp_drops[DPIF_DP_MAX_DROP];
+    atomic_uint64_t tx_drops[DPIF_TX_MAX_DROP];
+};
+
+struct pmd_drop_counters {
+    struct pmd_drop_stats n;      /* Value since _init(). */
+    struct pmd_drop_stats zero;   /* Value at last _clear().  */
+};
+
+
 /* Data structure to collect statistical distribution of an integer measurement
  * type in form of a histogram. The wall[] array contains the inclusive
  * upper boundaries of the bins, while the bin[] array contains the actual
@@ -160,6 +176,8 @@ struct pmd_perf_stats {
     struct cycle_timer *cur_timer;
     /* Set of PMD counters with their zero offsets. */
     struct pmd_counters counters;
+    /* Set of PMD drop counters with their zero offsets. */
+    struct pmd_drop_counters drop_counters;
     /* Statistics of the current iteration. */
     struct iter_stats current;
     /* Totals for the current millisecond. */
@@ -277,6 +295,12 @@ void pmd_perf_stats_clear_lock(struct pmd_perf_stats *s);
 void pmd_perf_read_counters(struct pmd_perf_stats *s,
                             uint64_t stats[PMD_N_STATS]);
 
+void pmd_perf_drop_stats_init(struct pmd_perf_stats *s);
+void pmd_perf_drop_stats_clear(struct pmd_perf_stats *s);
+void pmd_perf_read_drop_counters(struct pmd_perf_stats *s,
+                                 struct dpif_dp_drop_stats *drops);
+
+
 /* PMD performance counters are updated lock-less. For real PMDs
  * they are only updated from the PMD thread itself. In the case of the
  * NON-PMD they might be updated from multiple threads, but we can live
@@ -398,6 +422,34 @@ void pmd_perf_log_set_cmd(struct unixctl_conn *conn,
                           int argc, const char *argv[],
                           void *aux OVS_UNUSED);
 
+static inline void
+pmd_perf_update_drop_counter(struct pmd_perf_stats *s,
+                             struct dpif_drop_counter *cntr, int delta)
+{
+    unsigned long val;
+    switch (cntr->type) {
+        case DPIF_DROP_TYPE_RX:
+            atomic_add_relaxed(&s->drop_counters.n.rx_drops[cntr->counter.rx],
+                               delta, &val);
+            break;
+        case DPIF_DROP_TYPE_DP:
+            atomic_add_relaxed(&s->drop_counters.n.dp_drops[cntr->counter.dp],
+                               delta, &val);
+            break;
+        case DPIF_DROP_TYPE_DA:
+            atomic_add_relaxed(
+                      &s->drop_counters.n.drop_action_drops[cntr->counter.da],
+                      delta, &val);
+            break;
+        case DPIF_DROP_TYPE_TX:
+            atomic_add_relaxed(&s->drop_counters.n.tx_drops[cntr->counter.tx],
+                               delta, &val);
+            break;
+        OVS_NOT_REACHED();
+    }
+}
+
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 807a462..5c5e39e 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1368,6 +1368,46 @@ dpif_netdev_init(void)
 }
 
 static int
+dpif_netdev_get_drop_stats(const struct dpif *dpif,
+                           struct dpif_dp_drop_stats *drop_stats)
+{
+    struct dp_netdev *dp = get_dp_netdev(dpif);
+    struct dp_netdev_pmd_thread *pmd;
+    struct dp_netdev_port *port;
+    struct netdev_stats stats;
+
+    memset(drop_stats, 0 , sizeof(*drop_stats));
+    CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
+        pmd_perf_read_drop_counters(&pmd->perf_stats, drop_stats);
+    }
+    ovs_mutex_lock(&dp->port_mutex);
+    HMAP_FOR_EACH (port, node, &dp->ports) {
+        if (!netdev_is_pmd(port->netdev)) {
+            continue;
+        }
+
+        port->netdev->netdev_class->get_stats(port->netdev,
+                                              &stats);
+        drop_stats->iface_rx_drops += stats.rx_dropped;
+        drop_stats->iface_tx_drops += stats.tx_dropped;
+    }
+    ovs_mutex_unlock(&dp->port_mutex);
+
+    return 0;
+}
+
+static int
+dpif_netdev_clear_drop_stats(const struct dpif *dpif)
+{
+    struct dp_netdev *dp = get_dp_netdev(dpif);
+    struct dp_netdev_pmd_thread *pmd;
+    CMAP_FOR_EACH (pmd, node, &dp->poll_threads) {
+        pmd_perf_drop_stats_clear(&pmd->perf_stats);
+    }
+    return 0;
+}
+
+static int
 dpif_netdev_enumerate(struct sset *all_dps,
                       const struct dpif_class *dpif_class)
 {
@@ -5027,7 +5067,8 @@ dpif_netdev_meter_get_features(const struct dpif * dpif OVS_UNUSED,
 /* Applies the meter identified by 'meter_id' to 'packets_'.  Packets
  * that exceed a band are dropped in-place. */
 static void
-dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
+dp_netdev_run_meter(struct dp_netdev_pmd_thread *pmd,
+                    struct dp_netdev *dp, struct dp_packet_batch *packets_,
                     uint32_t meter_id, long long int now)
 {
     struct dp_meter *meter;
@@ -5150,12 +5191,16 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct dp_packet_batch *packets_,
     size_t j;
     DP_PACKET_BATCH_REFILL_FOR_EACH (j, cnt, packet, packets_) {
         if (exceeded_band[j] >= 0) {
+            struct dpif_drop_counter cntr;
             /* Meter drop packet. */
             band = &meter->bands[exceeded_band[j]];
             band->packet_count += 1;
             band->byte_count += dp_packet_size(packet);
 
             dp_packet_delete(packet);
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_METER_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
         } else {
             /* Meter accepts packet. */
             dp_packet_batch_refill(packets_, packet, j);
@@ -5896,6 +5941,7 @@ dfc_processing(struct dp_netdev_pmd_thread *pmd,
     bool smc_enable_db;
     size_t map_cnt = 0;
     bool batch_enable = true;
+    struct dpif_drop_counter cntr;
 
     atomic_read_relaxed(&pmd->dp->smc_enable_db, &smc_enable_db);
     atomic_read_relaxed(&pmd->dp->emc_insert_min, &cur_min);
@@ -5909,6 +5955,9 @@ dfc_processing(struct dp_netdev_pmd_thread *pmd,
 
         if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) {
             dp_packet_delete(packet);
+            cntr.type = DPIF_DROP_TYPE_RX;
+            cntr.counter.rx = DPIF_RX_INVALID_PACKET_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
             continue;
         }
 
@@ -6022,6 +6071,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
     ovs_u128 ufid;
     int error;
     uint64_t cycles = cycles_counter_update(&pmd->perf_stats);
+    struct dpif_drop_counter cntr;
 
     match.tun_md.valid = false;
     miniflow_expand(&key->mf, &match.flow);
@@ -6035,6 +6085,9 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
                              put_actions);
     if (OVS_UNLIKELY(error && error != ENOSPC)) {
         dp_packet_delete(packet);
+        cntr.type = DPIF_DROP_TYPE_DP;
+        cntr.counter.dp = DPIF_DP_UPCALL_ERROR_DROP;
+        pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
         return error;
     }
 
@@ -6110,6 +6163,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
     int upcall_ok_cnt = 0, upcall_fail_cnt = 0;
     int lookup_cnt = 0, add_lookup_cnt;
     bool any_miss;
+    struct dpif_drop_counter cntr;
 
     for (size_t i = 0; i < cnt; i++) {
         /* Key length is needed in all the cases, hash computed on demand. */
@@ -6166,6 +6220,9 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd,
         DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) {
             if (OVS_UNLIKELY(!rules[i])) {
                 dp_packet_delete(packet);
+                cntr.type = DPIF_DROP_TYPE_DP;
+                cntr.counter.dp = DPIF_DP_UPCALL_LOCK_ERROR_DROP;
+                pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
                 upcall_fail_cnt++;
             }
         }
@@ -6423,6 +6480,7 @@ dp_execute_userspace_action(struct dp_netdev_pmd_thread *pmd,
 {
     struct dp_packet_batch b;
     int error;
+    struct dpif_drop_counter cntr;
 
     ofpbuf_clear(actions);
 
@@ -6435,10 +6493,23 @@ dp_execute_userspace_action(struct dp_netdev_pmd_thread *pmd,
                                   actions->data, actions->size);
     } else if (should_steal) {
         dp_packet_delete(packet);
+        cntr.type = DPIF_DROP_TYPE_DP;
+        cntr.counter.dp = DPIF_DP_USER_SPACE_ACTION_ERROR_DROP;
+        pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr, 1);
     }
 }
 
 static void
+dp_update_drop_counter_cb(void *aux_, struct dpif_drop_counter *cntr,
+                       int delta)
+    OVS_NO_THREAD_SAFETY_ANALYSIS
+{
+    struct dp_netdev_execute_aux *aux = aux_;
+    struct dp_netdev_pmd_thread *pmd = aux->pmd;
+    pmd_perf_update_drop_counter(&pmd->perf_stats, cntr, delta);
+}
+
+static void
 dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
               const struct nlattr *a, bool should_steal)
     OVS_NO_THREAD_SAFETY_ANALYSIS
@@ -6449,6 +6520,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
     struct dp_netdev *dp = pmd->dp;
     int type = nl_attr_type(a);
     struct tx_port *p;
+    uint32_t packet_count, packet_dropped;
+    struct dpif_drop_counter cntr;
 
     switch ((enum ovs_action_attr)type) {
     case OVS_ACTION_ATTR_OUTPUT:
@@ -6490,6 +6563,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
                 dp_packet_batch_add(&p->output_pkts, packet);
             }
             return;
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_INVALID_PORT_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                          packets_->count);
         }
         break;
 
@@ -6499,10 +6577,19 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
              * the ownership of these packets. Thus, we can avoid performing
              * the action, because the caller will not use the result anyway.
              * Just break to free the batch. */
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_TUNNEL_PUSH_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
             break;
         }
         dp_packet_batch_apply_cutlen(packets_);
-        push_tnl_action(pmd, a, packets_);
+        if (push_tnl_action(pmd, a, packets_)) {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_TUNNEL_PUSH_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
+        }
         return;
 
     case OVS_ACTION_ATTR_TUNNEL_POP:
@@ -6522,7 +6609,16 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
 
                 dp_packet_batch_apply_cutlen(packets_);
 
+                packet_count = packets_->count;
                 netdev_pop_header(p->port->netdev, packets_);
+                packet_dropped = packet_count - packets_->count;
+                if (packet_dropped) {
+                    cntr.type = DPIF_DROP_TYPE_DP;
+                    cntr.counter.dp = DPIF_DP_TUNNEL_POP_ERROR_DROP;
+                    pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                                 packet_dropped);
+                }
+
                 if (dp_packet_batch_is_empty(packets_)) {
                     return;
                 }
@@ -6536,7 +6632,17 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
                 dp_netdev_recirculate(pmd, packets_);
                 (*depth)--;
                 return;
+            } else {
+                cntr.type = DPIF_DROP_TYPE_DP;
+                cntr.counter.dp = DPIF_DP_INVALID_TNL_PORT_DROP;
+                pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
             }
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_RECIRC_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
         }
         break;
 
@@ -6580,6 +6686,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
             fat_rwlock_unlock(&dp->upcall_rwlock);
 
             return;
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_UPCALL_LOCK_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                             packets_->count);
         }
         break;
 
@@ -6602,6 +6713,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
             (*depth)--;
 
             return;
+        } else {
+            cntr.type = DPIF_DROP_TYPE_DP;
+            cntr.counter.dp = DPIF_DP_RECIRC_ERROR_DROP;
+            pmd_perf_update_drop_counter(&pmd->perf_stats, &cntr,
+                                         packets_->count);
         }
 
         VLOG_WARN("Packet dropped. Max recirculation depth exceeded.");
@@ -6736,7 +6852,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
     }
 
     case OVS_ACTION_ATTR_METER:
-        dp_netdev_run_meter(pmd->dp, packets_, nl_attr_get_u32(a),
+        dp_netdev_run_meter(pmd, pmd->dp, packets_, nl_attr_get_u32(a),
                             pmd->ctx.now);
         break;
 
@@ -6756,6 +6872,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
     case OVS_ACTION_ATTR_PUSH_NSH:
     case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_CT_CLEAR:
+    case OVS_ACTION_ATTR_DROP:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
     }
@@ -6772,7 +6889,8 @@ dp_netdev_execute_actions(struct dp_netdev_pmd_thread *pmd,
     struct dp_netdev_execute_aux aux = { pmd, flow };
 
     odp_execute_actions(&aux, packets, should_steal, actions,
-                        actions_len, dp_execute_cb);
+                        actions_len, dp_execute_cb,
+                        dp_update_drop_counter_cb);
 }
 
 struct dp_netdev_ct_dump {
@@ -6875,6 +6993,8 @@ const struct dpif_class dpif_netdev_class = {
     dpif_netdev_run,
     dpif_netdev_wait,
     dpif_netdev_get_stats,
+    dpif_netdev_get_drop_stats,
+    dpif_netdev_clear_drop_stats,
     dpif_netdev_port_add,
     dpif_netdev_port_del,
     dpif_netdev_port_set_config,
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index e6d5a6e..458991b 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -3466,6 +3466,8 @@ const struct dpif_class dpif_netlink_class = {
     dpif_netlink_run,
     NULL,                       /* wait */
     dpif_netlink_get_stats,
+    NULL,
+    NULL,
     dpif_netlink_port_add,
     dpif_netlink_port_del,
     NULL,                       /* port_set_config */
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 873b6e3..8e04daa 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -156,6 +156,13 @@ struct dpif_class {
     /* Retrieves statistics for 'dpif' into 'stats'. */
     int (*get_stats)(const struct dpif *dpif, struct dpif_dp_stats *stats);
 
+    /* Retrieves drop statistics for 'dpif' into 'drop_stats'. */
+    int (*get_drop_stats)(const struct dpif *dpif,
+                          struct dpif_dp_drop_stats *drop_stats);
+
+    /* Clears drop statistics for 'dpif'. */
+    int (*clear_drop_stats)(const struct dpif *dpif);
+
     /* Adds 'netdev' as a new port in 'dpif'.  If '*port_no' is not
      * ODPP_NONE, attempts to use that as the port's port number.
      *
diff --git a/lib/dpif.c b/lib/dpif.c
index d799f97..be62665 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -538,6 +538,38 @@ dpif_get_dp_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
     return error;
 }
 
+/* Retrieves drop statistics for 'dpif' into 'drop_stats'.  Returns 0
+ * if successful, otherwise a positive errno value. */
+int
+dpif_get_dp_drop_stats(const struct dpif *dpif,
+                  struct dpif_dp_drop_stats *drop_stats)
+{
+    int error = 0;
+    if (dpif->dpif_class->get_drop_stats) {
+        error = dpif->dpif_class->get_drop_stats(dpif, drop_stats);
+        if (error) {
+            memset(drop_stats, 0, sizeof *drop_stats);
+        }
+        log_operation(dpif, "get_drop_stats", error);
+    } else {
+        log_operation(dpif, "get_drop_stats not supported", error);
+    }
+    return error;
+}
+
+/* Clears drop statistics in 'dpif' into 'drop_stats'. */
+int
+dpif_clear_dp_drop_stats(const struct dpif *dpif)
+{
+    int error = 0;
+    if (dpif->dpif_class->clear_drop_stats) {
+        error = dpif->dpif_class->clear_drop_stats(dpif);
+    } else {
+        log_operation(dpif, "clear_drop_stats not supported", error);
+    }
+    return error;
+}
+
 const char *
 dpif_port_open_type(const char *datapath_type, const char *port_type)
 {
@@ -1280,6 +1312,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
     case OVS_ACTION_ATTR_PUSH_NSH:
     case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_CT_CLEAR:
+    case OVS_ACTION_ATTR_DROP:
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
         OVS_NOT_REACHED();
@@ -1302,7 +1335,7 @@ dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute)
 
     dp_packet_batch_init_packet(&pb, execute->packet);
     odp_execute_actions(&aux, &pb, false, execute->actions,
-                        execute->actions_len, dpif_execute_helper_cb);
+                        execute->actions_len, dpif_execute_helper_cb, NULL);
     return aux.error;
 }
 
@@ -1875,6 +1908,12 @@ dpif_supports_tnl_push_pop(const struct dpif *dpif)
     return dpif_is_netdev(dpif);
 }
 
+bool
+dpif_supports_explicit_drop_action(const struct dpif *dpif)
+{
+    return dpif_is_netdev(dpif);
+}
+
 /* Meters */
 void
 dpif_meter_get_features(const struct dpif *dpif,
@@ -1972,3 +2011,153 @@ dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
     }
     return error;
 }
+
+static void
+dpif_show_drop_stats(struct ds *reply,
+                    struct dpif_dp_drop_stats *drop_stats)
+{
+    uint64_t rx_drops,tx_drops,dp_drops,drop_action_drops;
+    int i;
+
+    rx_drops = 0;
+    tx_drops = 0;
+    dp_drops = 0;
+    drop_action_drops = 0;
+    for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
+        rx_drops += drop_stats->rx_drops[i];
+    }
+    for (i = 0; i < OVS_DROP_REASON_MAX; i++) {
+        drop_action_drops += drop_stats->drop_action_drops[i];
+    }
+    for (i = 0; i < DPIF_DP_MAX_DROP; i++) {
+        dp_drops += drop_stats->dp_drops[i];
+    }
+    for (i = 0; i < DPIF_TX_MAX_DROP; i++) {
+        tx_drops += drop_stats->tx_drops[i];
+    }
+    dp_drops += drop_action_drops;
+    rx_drops += drop_stats->iface_rx_drops;
+    tx_drops += drop_stats->iface_tx_drops;
+
+    ds_put_format(reply, "%-28s:%-12"PRIu64"\n", "rx-drops", rx_drops);
+    ds_put_format(reply, "%-28s:%-12"PRIu64"\n",
+                  "dataplane-processing-drops", dp_drops);
+    ds_put_format(reply, "     %-23s:%-12"PRIu64"\n", "drop action",
+                  drop_action_drops);
+    ds_put_format(reply, "     %-23s:%-12"PRIu64"\n", "upcall drops",
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP] +
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+    ds_put_format(reply, "     %-23s:%-12"PRIu64"\n", "dp error drops",
+                  dp_drops -
+                  drop_action_drops -
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP] -
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+    ds_put_format(reply, "%-28s:%-12"PRIu64"\n", "tx-drops",
+                  tx_drops);
+}
+
+static void
+dpif_show_drop_stats_detail(struct ds *reply,
+                    struct dpif_dp_drop_stats *drop_stats)
+{
+    uint32_t idx = 0;
+    ds_put_format(reply, "rx-drops: \n");
+    ds_put_format(reply, "%-7s %-38s %-12s\n", "[IDX]", "Drop Reason",
+                  "Packets");
+    ds_put_format(reply, "-------  ------------------------------------- "
+                         "------------\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "interface & policer", drop_stats->iface_rx_drops);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "parsing error/invalid packet",
+                  drop_stats->rx_drops[DPIF_RX_INVALID_PACKET_DROP]);
+    ds_put_format(reply, "dataplane-processing-drops: \n");
+    ds_put_format(reply, "\"drop\" action:\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "pipeline drop",
+                  drop_stats->drop_action_drops[OVS_DROP_REASON_OF_PIPELINE]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+              "bridge not found",
+              drop_stats->drop_action_drops[OVS_DROP_REASON_BRIDGE_NOT_FOUND]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+            "recursion too deep",
+            drop_stats->drop_action_drops[OVS_DROP_REASON_RECURSION_TOO_DEEP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+            "too many resubmits",
+            drop_stats->drop_action_drops[OVS_DROP_REASON_TOO_MANY_RESUBMITS]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "stack too deep",
+             drop_stats->drop_action_drops[OVS_DROP_REASON_STACK_TOO_DEEP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+      "no recirculation context",
+      drop_stats->drop_action_drops[OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+        "recirculation conflict",
+        drop_stats->drop_action_drops[OVS_DROP_REASON_RECIRCULATION_CONFLICT]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+          "too many mpls labels",
+          drop_stats->drop_action_drops[OVS_DROP_REASON_TOO_MANY_MPLS_LABELS]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+       "invalid tunnel metadata",
+       drop_stats->drop_action_drops[OVS_DROP_REASON_INVALID_TUNNEL_METADATA]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+       "unsupported packet type",
+       drop_stats->drop_action_drops[OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+              "ecn mismatch at tunnel decapsulation",
+               drop_stats->drop_action_drops[OVS_DROP_REASON_CONGESTION]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+           "forwarding disabled (stp/rstp)",
+           drop_stats->drop_action_drops[OVS_DROP_REASON_FORWARDING_DISABLED]);
+    ds_put_format(reply, "upcall drops:\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "upcall lock contention drop",
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "upcall error drops",
+                  drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP]);
+    ds_put_format(reply, "dp error drops:\n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "tunnel pop action errors",
+                  drop_stats->dp_drops[DPIF_DP_TUNNEL_POP_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "tunnel push action errors",
+                  drop_stats->dp_drops[DPIF_DP_TUNNEL_PUSH_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "nsh decap errors",
+                  drop_stats->dp_drops[DPIF_DP_NSH_DECAP_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "recirculation errors",
+                  drop_stats->dp_drops[DPIF_DP_RECIRC_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "sampling error",
+                         drop_stats->dp_drops[DPIF_DP_SAMPLE_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "meter drop",
+                         drop_stats->dp_drops[DPIF_DP_METER_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "user space action error",
+                  drop_stats->dp_drops[DPIF_DP_USER_SPACE_ACTION_ERROR_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "invalid port",
+                         drop_stats->dp_drops[DPIF_DP_INVALID_PORT_DROP]);
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "invalid tunnel port",
+                  drop_stats->dp_drops[DPIF_DP_INVALID_TNL_PORT_DROP]);
+    ds_put_format(reply, "tx-drops: \n");
+    ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+                  "interface & policer", drop_stats->iface_tx_drops);
+}
+
+int
+dpif_show_drop_stats_support(struct dpif *dpif, bool detail, struct ds *reply)
+{
+    struct dpif_dp_drop_stats drop_stats;
+    int error = 0;
+    error = dpif_get_dp_drop_stats(dpif, &drop_stats);
+    if (error) {
+        return error;
+    }
+    if (detail) {
+        dpif_show_drop_stats_detail(reply, &drop_stats);
+    } else {
+        dpif_show_drop_stats(reply, &drop_stats);
+    }
+    return 0;
+}
diff --git a/lib/dpif.h b/lib/dpif.h
index bbdc3eb..dbc1afd 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -778,6 +778,66 @@ enum dpif_upcall_type {
     DPIF_N_UC_TYPES
 };
 
+/* Drop counter types */
+enum dpif_drop_type {
+    DPIF_DROP_TYPE_RX,      /* Rx drops */
+    DPIF_DROP_TYPE_DP,      /* Data path processing drops */
+    DPIF_DROP_TYPE_TX,      /* Tx drops */
+    DPIF_DROP_TYPE_DA,      /* Drop action drops */
+};
+
+/* Rx drop counters */
+enum dpif_rx_drops {
+    DPIF_RX_INVALID_PACKET_DROP = 0,
+    DPIF_RX_MAX_DROP,
+};
+
+/* Tx drop counters */
+enum dpif_tx_drops {
+    DPIF_TX_MAX_DROP,
+};
+
+/* Data path processing drop counters */
+enum dpif_dp_drops {
+    DPIF_DP_METER_DROP = 0,
+    DPIF_DP_UPCALL_ERROR_DROP,
+    DPIF_DP_UPCALL_LOCK_ERROR_DROP,
+    DPIF_DP_USER_SPACE_ACTION_ERROR_DROP,
+    DPIF_DP_TUNNEL_PUSH_ERROR_DROP,
+    DPIF_DP_TUNNEL_POP_ERROR_DROP,
+    DPIF_DP_SAMPLE_ERROR_DROP,
+    DPIF_DP_NSH_DECAP_ERROR_DROP,
+    DPIF_DP_RECIRC_ERROR_DROP,
+    DPIF_DP_INVALID_PORT_DROP,
+    DPIF_DP_INVALID_TNL_PORT_DROP,
+    DPIF_DP_MAX_DROP,
+};
+
+/* Structure used to define any drop counter */
+struct dpif_drop_counter {
+    enum dpif_drop_type type;
+    union {
+        enum dpif_rx_drops   rx;
+        enum dpif_dp_drops   dp;
+        enum ovs_drop_reason da;
+        enum dpif_tx_drops   tx;
+    } counter;
+};
+
+/* Drop statistics for a dpif as a whole.*/
+struct dpif_dp_drop_stats {
+    uint64_t iface_rx_drops;
+    uint64_t rx_drops[DPIF_RX_MAX_DROP];
+    uint64_t drop_action_drops[OVS_DROP_REASON_MAX];
+    uint64_t dp_drops[DPIF_DP_MAX_DROP];
+    uint64_t iface_tx_drops;
+    uint64_t tx_drops[DPIF_TX_MAX_DROP];
+};
+
+int dpif_get_dp_drop_stats(const struct dpif *, struct dpif_dp_drop_stats *);
+int dpif_clear_dp_drop_stats(const struct dpif *);
+
+
 const char *dpif_upcall_type_to_string(enum dpif_upcall_type);
 
 /* A packet passed up from the datapath to userspace.
@@ -888,7 +948,9 @@ int dpif_get_pmds_for_port(const struct dpif * dpif, odp_port_t port_no,
 
 char *dpif_get_dp_version(const struct dpif *);
 bool dpif_supports_tnl_push_pop(const struct dpif *);
-
+bool dpif_supports_explicit_drop_action(const struct dpif *);
+int dpif_show_drop_stats_support(struct dpif *dpif, bool detail,
+                                 struct ds *reply);
 /* Log functions. */
 struct vlog_module;
 
diff --git a/lib/netdev-dpdk.c b/lib/netdev-dpdk.c
index f91aa27..cf98e54 100644
--- a/lib/netdev-dpdk.c
+++ b/lib/netdev-dpdk.c
@@ -2358,6 +2358,10 @@ netdev_dpdk_send__(struct netdev_dpdk *dev, int qid,
                    bool concurrent_txq)
 {
     if (OVS_UNLIKELY(!(dev->flags & NETDEV_UP))) {
+        int batch_cnt = dp_packet_batch_size(batch);
+        rte_spinlock_lock(&dev->stats_lock);
+        dev->stats.tx_dropped += batch_cnt;
+        rte_spinlock_unlock(&dev->stats_lock);
         dp_packet_delete_batch(batch, true);
         return;
     }
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 5831d1f..d0acee0 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -575,12 +575,14 @@ odp_execute_masked_set_action(struct dp_packet *packet,
 static void
 odp_execute_sample(void *dp, struct dp_packet *packet, bool steal,
                    const struct nlattr *action,
-                   odp_execute_cb dp_execute_action)
+                   odp_execute_cb dp_execute_action,
+                   odp_update_drop_counter_cb dp_update_drop_counter)
 {
     const struct nlattr *subactions = NULL;
     const struct nlattr *a;
     struct dp_packet_batch pb;
     size_t left;
+    struct dpif_drop_counter cntr;
 
     NL_NESTED_FOR_EACH_UNSAFE (a, left, action) {
         int type = nl_attr_type(a);
@@ -589,6 +591,11 @@ odp_execute_sample(void *dp, struct dp_packet *packet, bool steal,
         case OVS_SAMPLE_ATTR_PROBABILITY:
             if (random_uint32() >= nl_attr_get_u32(a)) {
                 if (steal) {
+                    if (dp_update_drop_counter) {
+                        cntr.type = DPIF_DROP_TYPE_DP;
+                        cntr.counter.dp = DPIF_DP_SAMPLE_ERROR_DROP;
+                        dp_update_drop_counter(dp, &cntr, 1);
+                    }
                     dp_packet_delete(packet);
                 }
                 return;
@@ -616,13 +623,15 @@ odp_execute_sample(void *dp, struct dp_packet *packet, bool steal,
     }
     dp_packet_batch_init_packet(&pb, packet);
     odp_execute_actions(dp, &pb, true, nl_attr_get(subactions),
-                        nl_attr_get_size(subactions), dp_execute_action);
+                        nl_attr_get_size(subactions), dp_execute_action,
+                        dp_update_drop_counter);
 }
 
 static void
 odp_execute_clone(void *dp, struct dp_packet_batch *batch, bool steal,
                    const struct nlattr *actions,
-                   odp_execute_cb dp_execute_action)
+                   odp_execute_cb dp_execute_action,
+                   odp_update_drop_counter_cb dp_update_drop_counter)
 {
     if (!steal) {
         /* The 'actions' may modify the packet, but the modification
@@ -634,11 +643,13 @@ odp_execute_clone(void *dp, struct dp_packet_batch *batch, bool steal,
         dp_packet_batch_clone(&clone_pkt_batch, batch);
         dp_packet_batch_reset_cutlen(batch);
         odp_execute_actions(dp, &clone_pkt_batch, true, nl_attr_get(actions),
-                        nl_attr_get_size(actions), dp_execute_action);
+                        nl_attr_get_size(actions), dp_execute_action,
+                        dp_update_drop_counter);
     }
     else {
         odp_execute_actions(dp, batch, true, nl_attr_get(actions),
-                            nl_attr_get_size(actions), dp_execute_action);
+                            nl_attr_get_size(actions), dp_execute_action,
+                            dp_update_drop_counter);
     }
 }
 
@@ -673,6 +684,7 @@ requires_datapath_assistance(const struct nlattr *a)
     case OVS_ACTION_ATTR_PUSH_NSH:
     case OVS_ACTION_ATTR_POP_NSH:
     case OVS_ACTION_ATTR_CT_CLEAR:
+    case OVS_ACTION_ATTR_DROP:
         return false;
 
     case OVS_ACTION_ATTR_UNSPEC:
@@ -699,11 +711,14 @@ requires_datapath_assistance(const struct nlattr *a)
 void
 odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
                     const struct nlattr *actions, size_t actions_len,
-                    odp_execute_cb dp_execute_action)
+                    odp_execute_cb dp_execute_action,
+                    odp_update_drop_counter_cb dp_update_drop_counter)
 {
     struct dp_packet *packet;
     const struct nlattr *a;
     unsigned int left;
+    struct dpif_drop_counter cntr;
+
 
     NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
         int type = nl_attr_type(a);
@@ -822,7 +837,7 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
         case OVS_ACTION_ATTR_SAMPLE:
             DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
                 odp_execute_sample(dp, packet, steal && last_action, a,
-                                   dp_execute_action);
+                                   dp_execute_action, dp_update_drop_counter);
             }
 
             if (last_action) {
@@ -845,7 +860,8 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
 
         case OVS_ACTION_ATTR_CLONE:
             odp_execute_clone(dp, batch, steal && last_action, a,
-                                                dp_execute_action);
+                                         dp_execute_action,
+                                         dp_update_drop_counter);
             if (last_action) {
                 /* We do not need to free the packets. odp_execute_clone() has
                  * stolen them.  */
@@ -889,6 +905,11 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
                 if (pop_nsh(packet)) {
                     dp_packet_batch_refill(batch, packet, i);
                 } else {
+                    if (dp_update_drop_counter) {
+                        cntr.type = DPIF_DROP_TYPE_DP;
+                        cntr.counter.dp = DPIF_DP_NSH_DECAP_ERROR_DROP;
+                        dp_update_drop_counter(dp, &cntr, 1);
+                    }
                     dp_packet_delete(packet);
                 }
             }
@@ -900,6 +921,19 @@ odp_execute_actions(void *dp, struct dp_packet_batch *batch, bool steal,
             }
             break;
 
+        case OVS_ACTION_ATTR_DROP: {
+            const struct ovs_action_drop *drop_action = nl_attr_get(a);
+            enum ovs_drop_reason drop_reason = drop_action->drop_reason;
+            if ((drop_reason < OVS_DROP_REASON_MAX) &&
+                 dp_update_drop_counter) {
+                 cntr.type = DPIF_DROP_TYPE_DA;
+                 cntr.counter.da = drop_reason;
+                 dp_update_drop_counter(dp, &cntr, batch->count);
+            }
+            dp_packet_delete_batch(batch, steal);
+            return;
+        }
+
         case OVS_ACTION_ATTR_OUTPUT:
         case OVS_ACTION_ATTR_TUNNEL_PUSH:
         case OVS_ACTION_ATTR_TUNNEL_POP:
diff --git a/lib/odp-execute.h b/lib/odp-execute.h
index a3578a5..8684227 100644
--- a/lib/odp-execute.h
+++ b/lib/odp-execute.h
@@ -22,6 +22,8 @@
 #include <stddef.h>
 #include <stdint.h>
 #include "openvswitch/types.h"
+#include "ovs-atomic.h"
+#include "dpif.h"
 
 struct nlattr;
 struct dp_packet;
@@ -31,6 +33,10 @@ struct dp_packet_batch;
 typedef void (*odp_execute_cb)(void *dp, struct dp_packet_batch *batch,
                                const struct nlattr *action, bool should_steal);
 
+typedef void (*odp_update_drop_counter_cb) (void *aux_,
+                                           struct dpif_drop_counter *cntr,
+                                           int delta);
+
 /* Actions that need to be executed in the context of a datapath are handed
  * to 'dp_execute_action', if non-NULL.  Currently this is called only for
  * actions OVS_ACTION_ATTR_OUTPUT and OVS_ACTION_ATTR_USERSPACE so
@@ -38,5 +44,6 @@ typedef void (*odp_execute_cb)(void *dp, struct dp_packet_batch *batch,
 void odp_execute_actions(void *dp, struct dp_packet_batch *batch,
                          bool steal,
                          const struct nlattr *actions, size_t actions_len,
-                         odp_execute_cb dp_execute_action);
+                         odp_execute_cb dp_execute_action,
+                         odp_update_drop_counter_cb dp_update_drop_counter_cb);
 #endif
diff --git a/lib/odp-util.c b/lib/odp-util.c
index cf62550..aeb8ef3 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -124,6 +124,7 @@ odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_CLONE: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE;
     case OVS_ACTION_ATTR_POP_NSH: return 0;
+    case OVS_ACTION_ATTR_DROP: return sizeof(struct ovs_action_drop);
 
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
@@ -338,6 +339,49 @@ format_nsh_key_mask(struct ds *ds, const struct ovs_key_nsh *key,
     }
 }
 
+static const char *
+dropreason_str(enum ovs_drop_reason reason)
+{
+    switch (reason) {
+    case OVS_DROP_REASON_OF_PIPELINE:
+        return "pipeline-drop";
+    case OVS_DROP_REASON_BRIDGE_NOT_FOUND:
+        return "bridge not found";
+    case OVS_DROP_REASON_RECURSION_TOO_DEEP:
+        return "recursion too deep";
+    case OVS_DROP_REASON_TOO_MANY_RESUBMITS:
+        return "too many resubmits";
+    case OVS_DROP_REASON_STACK_TOO_DEEP:
+        return "stack too deep";
+    case OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT:
+        return "no recirculation context";
+    case OVS_DROP_REASON_RECIRCULATION_CONFLICT:
+        return "recirculation conflict";
+    case OVS_DROP_REASON_TOO_MANY_MPLS_LABELS:
+        return "too many mpls labels";
+    case OVS_DROP_REASON_INVALID_TUNNEL_METADATA:
+        return "invalid tunnel metadata";
+    case OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE:
+        return "unsupported packet type";
+    case OVS_DROP_REASON_CONGESTION:
+        return "ecn mismatch at tunnel decapsulation";
+    case OVS_DROP_REASON_FORWARDING_DISABLED:
+        return "forwarding disabled (stp/rstp)";
+    case OVS_DROP_REASON_MAX:
+    default:
+        return "unknown reason";
+    }
+    return "unknown reason";
+}
+
+static void
+format_odp_drop_action(struct ds *ds,
+                      const struct ovs_action_drop *drop_action)
+{
+    ds_put_format(ds, "drop:%s",
+                  dropreason_str(drop_action->drop_reason));
+}
+
 static void
 format_odp_push_nsh_action(struct ds *ds,
                            const struct nsh_hdr *nsh_hdr)
@@ -1174,6 +1218,9 @@ format_odp_action(struct ds *ds, const struct nlattr *a,
     case OVS_ACTION_ATTR_POP_NSH:
         ds_put_cstr(ds, "pop_nsh()");
         break;
+    case OVS_ACTION_ATTR_DROP:
+        format_odp_drop_action(ds, nl_attr_get(a));
+        break;
     case OVS_ACTION_ATTR_UNSPEC:
     case __OVS_ACTION_ATTR_MAX:
     default:
@@ -2412,8 +2459,13 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
                         struct ofpbuf *actions)
 {
     size_t old_size;
+    struct ovs_action_drop drop_action;
 
-    if (!strcasecmp(s, "drop")) {
+    if ((!strcasecmp(s, "drop") ||
+        !strcasecmp(s, "drop:pipeline-drop"))) {
+        drop_action.drop_reason = OVS_DROP_REASON_OF_PIPELINE;
+        nl_msg_put_unspec(actions, OVS_ACTION_ATTR_DROP,
+                          &drop_action, sizeof drop_action);
         return 0;
     }
 
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index 4029806..1d23a5a 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -3015,6 +3015,7 @@ dpif_ipfix_read_actions(const struct flow *flow,
         case OVS_ACTION_ATTR_PUSH_NSH:
         case OVS_ACTION_ATTR_POP_NSH:
         case OVS_ACTION_ATTR_UNSPEC:
+        case OVS_ACTION_ATTR_DROP:
         case __OVS_ACTION_ATTR_MAX:
         default:
             break;
diff --git a/ofproto/ofproto-dpif-sflow.c b/ofproto/ofproto-dpif-sflow.c
index d17d7a8..28d025d 100644
--- a/ofproto/ofproto-dpif-sflow.c
+++ b/ofproto/ofproto-dpif-sflow.c
@@ -1221,6 +1221,7 @@ dpif_sflow_read_actions(const struct flow *flow,
         case OVS_ACTION_ATTR_PUSH_NSH:
         case OVS_ACTION_ATTR_POP_NSH:
         case OVS_ACTION_ATTR_UNSPEC:
+        case OVS_ACTION_ATTR_DROP:
         case __OVS_ACTION_ATTR_MAX:
         default:
             break;
diff --git a/ofproto/ofproto-dpif-unixctl.man b/ofproto/ofproto-dpif-unixctl.man
index bbf7fbb..ae107b9 100644
--- a/ofproto/ofproto-dpif-unixctl.man
+++ b/ofproto/ofproto-dpif-unixctl.man
@@ -32,3 +32,62 @@ underlying datapath implementation (e.g., kernel datapath module).
 This command is primarily useful for debugging Open vSwitch.  As
 discussed in \fBdpif/dump\-flows\fR, these entries are
 not OpenFlow flow entries.
+.IP "\fBdpif/show\-drop\-stats\fR [\fB\--detail\fR]"
+Prints the dataplane drops for Open vSwitch datapath.
+With [\fB\--detail\fR], it shows the detailed classified drop.
+
+This command is primarily useful for debugging dataplane drops.
+It helps in indentifying the reason of packet drop.
+.IP
+[currently supported for netdev datapath only]
+
+ Sample output:
+ $ovs-appctl dpif/show-drop-stats
+      netdev:
+      rx-drops                    :0
+      dataplane-processing-drops  :59
+           drop action            :59
+           upcall drops           :0
+           dp error drops         :0
+      tx-drops                    :0
+ $ovs-appctl dpif/show-drop-stats --detail
+      netdev:
+      rx-drops:
+      [IDX]   Drop Reason                            Packets
+      -------  ------------------------------------- ------------
+      0       interface & policer                    0
+      1       parsing error/invalid packet           0
+      dataplane-processing-drops:
+      "drop" action:
+      2       pipeline drop                          0
+      3       bridge not found                       0
+      4       recursion too deep                     68
+      5       too many resubmits                     0
+      6       stack too deep                         0
+      7       no recirculation context               0
+      8       recirculation conflict                 0
+      9       too many mpls labels                   0
+      10      invalid tunnel metadata                0
+      11      unsupported packet type                0
+      12      ecn mismatch at tunnel decapsulation   0
+      13      forwarding disabled (stp/rstp)         0
+      upcall drops:
+      14      upcall lock contention drop            0
+      15      upcall error drops                     0
+      dp error drops:
+      16      tunnel pop action errors               0
+      17      tunnel push action errors              0
+      18      nsh decap errors                       0
+      19      recirculation errors                   0
+      20      sampling error                         0
+      21      meter drop                             0
+      22      user space action error                0
+      23      invalid port                           0
+      24      invalid tunnel port                    0
+      tx-drops:
+      25      interface & policer                    0
+
+.IP "\fBdpif/clear\-drop\-stats\fR"
+Clears the drop stats displayed in dpif/show-drop-stats command.
+.IP
+[currently supported for netdev datapath only]
diff --git a/ofproto/ofproto-dpif-upcall.c b/ofproto/ofproto-dpif-upcall.c
index 6222207..f102050 100644
--- a/ofproto/ofproto-dpif-upcall.c
+++ b/ofproto/ofproto-dpif-upcall.c
@@ -1119,7 +1119,7 @@ upcall_receive(struct upcall *upcall, const struct dpif_backer *backer,
     return 0;
 }
 
-static void
+static enum xlate_error
 upcall_xlate(struct udpif *udpif, struct upcall *upcall,
              struct ofpbuf *odp_actions, struct flow_wildcards *wc)
 {
@@ -1209,6 +1209,7 @@ upcall_xlate(struct udpif *udpif, struct upcall *upcall,
     if (upcall->type == MISS_UPCALL) {
         upcall->ukey = ukey_create_from_upcall(upcall, wc);
     }
+    return xerr;
 }
 
 static void
@@ -1279,6 +1280,7 @@ upcall_cb(const struct dp_packet *packet, const struct flow *flow, ovs_u128 *ufi
 
     upcall.fitness = ODP_FIT_PERFECT;
     error = process_upcall(udpif, &upcall, actions, wc);
+
     if (error) {
         goto out;
     }
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index e26f6c8..9c396fb 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -444,10 +444,46 @@ const char *xlate_strerror(enum xlate_error error)
         return "Invalid tunnel metadata";
     case XLATE_UNSUPPORTED_PACKET_TYPE:
         return "Unsupported packet type";
+    case XLATE_CONGESTION_DROP:
+        return "CONGESTION DROP";
+    case XLATE_FORWARDING_DISABLED:
+        return "Forwarding is disabled";
+
     }
     return "Unknown error";
 }
 
+enum ovs_drop_reason  xlate_error_to_drop_reason(enum xlate_error error)
+{
+     switch (error) {
+        case XLATE_OK:
+            return OVS_DROP_REASON_OF_PIPELINE;
+        case XLATE_BRIDGE_NOT_FOUND:
+            return OVS_DROP_REASON_BRIDGE_NOT_FOUND;
+        case XLATE_RECURSION_TOO_DEEP:
+            return OVS_DROP_REASON_RECURSION_TOO_DEEP;
+        case XLATE_TOO_MANY_RESUBMITS:
+            return OVS_DROP_REASON_TOO_MANY_RESUBMITS;
+        case XLATE_STACK_TOO_DEEP:
+            return OVS_DROP_REASON_STACK_TOO_DEEP;
+        case XLATE_NO_RECIRCULATION_CONTEXT:
+            return OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT;
+        case XLATE_RECIRCULATION_CONFLICT:
+            return OVS_DROP_REASON_RECIRCULATION_CONFLICT;
+        case XLATE_TOO_MANY_MPLS_LABELS:
+            return OVS_DROP_REASON_TOO_MANY_MPLS_LABELS;
+        case XLATE_INVALID_TUNNEL_METADATA:
+            return OVS_DROP_REASON_INVALID_TUNNEL_METADATA;
+        case XLATE_UNSUPPORTED_PACKET_TYPE:
+            return OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE;
+        case XLATE_CONGESTION_DROP:
+            return OVS_DROP_REASON_CONGESTION;
+        case XLATE_FORWARDING_DISABLED:
+            return OVS_DROP_REASON_MAX;
+     }
+     return OVS_DROP_REASON_OF_PIPELINE;
+}
+
 static void xlate_action_set(struct xlate_ctx *ctx);
 static void xlate_commit_actions(struct xlate_ctx *ctx);
 
@@ -5856,6 +5892,17 @@ put_ct_label(const struct flow *flow, struct ofpbuf *odp_actions,
 }
 
 static void
+put_drop_action(struct ofpbuf *odp_actions, enum xlate_error error)
+{
+    struct ovs_action_drop drop_action;
+
+    drop_action.drop_reason = xlate_error_to_drop_reason(error);
+    nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_DROP,
+                          &drop_action, sizeof drop_action);
+
+}
+
+static void
 put_ct_helper(struct xlate_ctx *ctx,
               struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc)
 {
@@ -7318,6 +7365,10 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
         }
         size_t sample_actions_len = ctx.odp_actions->size;
 
+        if (!tnl_process_ecn(flow)) {
+            ctx.error = XLATE_CONGESTION_DROP;
+        }
+
         if (tnl_process_ecn(flow)
             && (!in_port || may_receive(in_port, &ctx))) {
             const struct ofpact *ofpacts;
@@ -7350,6 +7401,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out *xout)
                 ctx.odp_actions->size = sample_actions_len;
                 ctx_cancel_freeze(&ctx);
                 ofpbuf_clear(&ctx.action_set);
+                ctx.error = XLATE_FORWARDING_DISABLED;
             }
 
             if (!ctx.freezing) {
@@ -7457,6 +7509,18 @@ exit:
             ofpbuf_clear(xin->odp_actions);
         }
     }
+
+    /*
+     * If we are going to install "drop" action, check whether
+     * datapath supports explicit "drop"action. If datapath
+     * supports explicit "drop"action then install the "drop"
+     * action containing the drop reason.
+     */
+    if (xin->odp_actions && !xin->odp_actions->size &&
+         ovs_explicit_drop_action_supported(ctx.xbridge->ofproto)) {
+        put_drop_action(xin->odp_actions, ctx.error);
+    }
+
     return ctx.error;
 }
 
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 2cbb3c9..6773004 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -216,12 +216,16 @@ enum xlate_error {
     XLATE_TOO_MANY_MPLS_LABELS,
     XLATE_INVALID_TUNNEL_METADATA,
     XLATE_UNSUPPORTED_PACKET_TYPE,
+    XLATE_CONGESTION_DROP,
+    XLATE_FORWARDING_DISABLED,
 };
 
 const char *xlate_strerror(enum xlate_error error);
 
 enum xlate_error xlate_actions(struct xlate_in *, struct xlate_out *);
 
+enum ovs_drop_reason xlate_error_to_drop_reason(enum xlate_error error);
+
 void xlate_in_init(struct xlate_in *, struct ofproto_dpif *, ovs_version_t,
                    const struct flow *, ofp_port_t in_port, struct rule_dpif *,
                    uint16_t tcp_flags, const struct dp_packet *packet,
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 0a0c69a..942deeb 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -828,6 +828,12 @@ ovs_native_tunneling_is_on(struct ofproto_dpif *ofproto)
         && atomic_count_get(&ofproto->backer->tnl_count);
 }
 
+bool
+ovs_explicit_drop_action_supported(struct ofproto_dpif *ofproto)
+{
+    return ofproto->backer->rt_support.explicit_drop_action;
+}
+
 /* Tests whether 'backer''s datapath supports recirculation.  Only newer
  * datapaths support OVS_KEY_ATTR_RECIRC_ID in keys.  We need to disable some
  * features on older datapaths that don't support this feature.
@@ -1398,6 +1404,8 @@ check_support(struct dpif_backer *backer)
     backer->rt_support.ct_eventmask = check_ct_eventmask(backer);
     backer->rt_support.ct_clear = check_ct_clear(backer);
     backer->rt_support.max_hash_alg = check_max_dp_hash_alg(backer);
+    backer->rt_support.explicit_drop_action =
+        dpif_supports_explicit_drop_action(backer->dpif);
 
     /* Flow fields. */
     backer->rt_support.odp.ct_state = check_ct_state(backer);
@@ -5788,6 +5796,83 @@ ofproto_unixctl_dpif_set_dp_features(struct unixctl_conn *conn,
 }
 
 static void
+ofproto_unixctl_dpif_show_drop_stats(struct unixctl_conn *conn,
+                                int argc OVS_UNUSED, const char *argv[],
+                                void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    int error = 0;
+    int i;
+    const struct shash_node **backers;
+    struct dpif_backer *backer;
+    bool detail = false;
+
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "--detail")) {
+            detail = true;
+        }
+    }
+
+    ds_init(&ds);
+    backers = shash_sort(&all_dpif_backers);
+    for (i = 0; i < shash_count(&all_dpif_backers); i++) {
+        backer = (struct dpif_backer *)backers[i]->data;
+        if (dpif_supports_explicit_drop_action(backer->dpif)) {
+            ds_put_format(&ds, "%s:\n", backer->type);
+            error = dpif_show_drop_stats_support(backer->dpif,
+                                             detail, &ds);
+            if (error) {
+                break;
+            }
+        }
+    }
+    if (error) {
+        ds_clear(&ds);
+        ds_put_format(&ds, "dpif/show-drop-stats failed");
+        unixctl_command_reply_error(conn, ds_cstr(&ds));
+    } else {
+        unixctl_command_reply(conn, ds_cstr(&ds));
+    }
+    free(backers);
+    ds_destroy(&ds);
+}
+
+
+static void
+ofproto_unixctl_dpif_clear_drop_stats(struct unixctl_conn *conn,
+                                int argc OVS_UNUSED,
+                                const char *argv[] OVS_UNUSED,
+                                void *aux OVS_UNUSED)
+{
+    struct ds ds = DS_EMPTY_INITIALIZER;
+    int error = 0;
+    int i;
+    const struct shash_node **backers;
+    struct dpif_backer *backer;
+
+    ds_init(&ds);
+    backers = shash_sort(&all_dpif_backers);
+    for (i = 0; i < shash_count(&all_dpif_backers) ; i++) {
+        backer = (struct dpif_backer *)backers[i]->data;
+        if (dpif_supports_explicit_drop_action(backer->dpif)) {
+            error = dpif_clear_dp_drop_stats(backer->dpif);
+            if (error) {
+                break;
+            }
+        }
+    }
+    if (error) {
+        ds_clear(&ds);
+        ds_put_format(&ds, "dpif/clear-drop-stats failed");
+        unixctl_command_reply_error(conn, ds_cstr(&ds));
+    } else {
+        unixctl_command_reply(conn, ds_cstr(&ds));
+    }
+    free(backers);
+    ds_destroy(&ds);
+}
+
+static void
 ofproto_unixctl_init(void)
 {
     static bool registered;
@@ -5819,6 +5904,10 @@ ofproto_unixctl_init(void)
                              ofproto_unixctl_dpif_dump_flows, NULL);
     unixctl_command_register("dpif/set-dp-features", "bridge", 1, 3 ,
                              ofproto_unixctl_dpif_set_dp_features, NULL);
+    unixctl_command_register("dpif/show-drop-stats", "[--detail]", 0, 1,
+                             ofproto_unixctl_dpif_show_drop_stats, NULL);
+    unixctl_command_register("dpif/clear-drop-stats", "", 0, 0,
+                              ofproto_unixctl_dpif_clear_drop_stats, NULL);
 }
 
 static odp_port_t
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 1a404c8..9162ba0 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -106,6 +106,7 @@ struct rule_dpif *rule_dpif_lookup_from_table(struct ofproto_dpif *,
                                               bool honor_table_miss,
                                               struct xlate_cache *);
 
+
 void rule_dpif_credit_stats(struct rule_dpif *,
                             const struct dpif_flow_stats *);
 
@@ -192,7 +193,10 @@ struct group_dpif *group_dpif_lookup(struct ofproto_dpif *,
     DPIF_SUPPORT_FIELD(bool, ct_clear, "Conntrack clear")                   \
                                                                             \
     /* Highest supported dp_hash algorithm. */                              \
-    DPIF_SUPPORT_FIELD(size_t, max_hash_alg, "Max dp_hash algorithm")
+    DPIF_SUPPORT_FIELD(size_t, max_hash_alg, "Max dp_hash algorithm")       \
+                                                                            \
+    /* True if the datapath supports explicit drop action. */               \
+    DPIF_SUPPORT_FIELD(bool, explicit_drop_action, "Explicit Drop action")
 
 /* Stores the various features which the corresponding backer supports. */
 struct dpif_backer_support {
@@ -361,4 +365,6 @@ int ofproto_dpif_delete_internal_flow(struct ofproto_dpif *, struct match *,
 
 bool ovs_native_tunneling_is_on(struct ofproto_dpif *);
 
+bool ovs_explicit_drop_action_supported(struct ofproto_dpif *);
+
 #endif /* ofproto-dpif.h */
diff --git a/tests/automake.mk b/tests/automake.mk
index b29a37e..391b6ee 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -106,7 +106,8 @@ TESTSUITE_AT = \
 	tests/ovn-controller-vtep.at \
 	tests/mcast-snooping.at \
 	tests/packet-type-aware.at \
-	tests/nsh.at
+	tests/nsh.at \
+	tests/drop-stats.at
 
 SYSTEM_KMOD_TESTSUITE_AT = \
 	tests/system-common-macros.at \
diff --git a/tests/bundle.at b/tests/bundle.at
index 40dfbea..deb54ba 100644
--- a/tests/bundle.at
+++ b/tests/bundle.at
@@ -241,7 +241,7 @@ AT_CHECK([tail -1 stdout], [0],
 AT_CHECK([ovs-ofctl mod-port br0 p2 down])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=LOCAL,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-ofctl mod-port br0 p1 up])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=LOCAL,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:06'], [0], [stdout])
diff --git a/tests/classifier.at b/tests/classifier.at
index 86f872d..a7378a7 100644
--- a/tests/classifier.at
+++ b/tests/classifier.at
@@ -50,12 +50,12 @@ Datapath actions: 1
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=11.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,ip,in_port=1,nw_dst=11.0.0.0/8,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
@@ -88,7 +88,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-vsctl set Flow_Table t0 prefixes=ipv6_label], [0])
@@ -103,7 +103,7 @@ AT_CHECK([ovs-vsctl set Flow_Table t0 prefixes=nw_dst], [0])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=192.168.0.0/16,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
@@ -113,7 +113,7 @@ Datapath actions: 1
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=80'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,tcp,in_port=1,nw_dst=10.1.2.15,nw_frag=no,tp_dst=80
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=10.1.2.15,nw_proto=6,nw_tos=0,nw_ttl=128,tp_src=8,tp_dst=79'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at
index fff395d..bea2430 100644
--- a/tests/dpif-netdev.at
+++ b/tests/dpif-netdev.at
@@ -249,6 +249,12 @@ meter:2 flow_count:1 packet_in_count:5 byte_in_count:300 duration:0.0s bands:
 0: packet_count:1 byte_count:60
 ])
 
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "meter drop" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+21 meter drop 5
+])
+
 # Advance time by 1/2 second
 ovs-appctl time/warp 500
 
diff --git a/tests/drop-stats.at b/tests/drop-stats.at
new file mode 100644
index 0000000..36f09ad
--- /dev/null
+++ b/tests/drop-stats.at
@@ -0,0 +1,212 @@
+AT_BANNER([drop-stats])
+
+AT_SETUP([drop-stats - cli tests])
+
+OVS_VSWITCHD_START([dnl
+    set bridge br0 datapath_type=dummy \
+        protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \
+    add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1])
+
+AT_DATA([flows.txt], [dnl
+table=0,in_port=1,actions=drop
+])
+
+AT_CHECK([
+    ovs-ofctl del-flows br0
+    ovs-ofctl -Oopenflow13 add-flows br0 flows.txt
+    ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions
+], [0], [dnl
+ in_port=1 actions=drop
+])
+
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+    ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/used:[[0-9]].[[0-9]]*s/used:0.0/' | sort], [0],
+[flow-dump from non-dpdk interfaces:
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:2, bytes:196, used:0.0, actions:drop:pipeline-drop
+])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "pipeline drop" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+2 pipeline drop 3
+])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+dummy:
+rx-drops :0
+dataplane-processing-drops :3
+ drop action :3
+ upcall drops :0
+ dp error drops :0
+tx-drops :0
+])
+
+
+AT_CHECK([ovs-appctl dpif/clear-drop-stats])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+dummy:
+rx-drops :0
+dataplane-processing-drops :0
+ drop action :0
+ upcall drops :0
+ dp error drops :0
+tx-drops :0
+])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "pipeline drop" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+2 pipeline drop 0
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
+AT_SETUP([drop-stats - pipeline and recurssion drops])
+
+OVS_VSWITCHD_START([dnl
+    set bridge br0 datapath_type=dummy \
+        protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \
+    add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
+    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])
+
+AT_DATA([flows.txt], [dnl
+table=0,in_port=1,actions=drop
+])
+
+AT_CHECK([
+    ovs-ofctl del-flows br0
+    ovs-ofctl -Oopenflow13 add-flows br0 flows.txt
+    ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions
+], [0], [dnl
+ in_port=1 actions=drop
+])
+
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "pipeline drop" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+2 pipeline drop 1
+])
+
+AT_DATA([flows.txt], [dnl
+table=0, in_port=1, actions=goto_table:1
+table=1, in_port=1, actions=goto_table:2
+table=2, in_port=1, actions=resubmit(,1)
+])
+
+AT_CHECK([
+    ovs-ofctl del-flows br0
+    ovs-ofctl -Oopenflow13 add-flows br0 flows.txt
+    ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions
+], [0], [ignore])
+
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "recursion too deep" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+4 recursion too deep 1
+])
+
+OVS_VSWITCHD_STOP(["/|WARN|/d"])
+AT_CLEANUP
+
+AT_SETUP([drop-stats - too many resubmit])
+
+OVS_VSWITCHD_START
+add_of_ports br0 1
+(for i in `seq 1 64`; do
+     j=`expr $i + 1`
+     echo "in_port=$i, actions=resubmit:$j, resubmit:$j, local"
+ done
+ echo "in_port=65, actions=local") > flows.txt
+
+AT_CHECK([
+    ovs-ofctl del-flows br0
+    ovs-ofctl -Oopenflow13 add-flows br0 flows.txt
+], [0], [ignore])
+
+ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x1234)'
+
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "too many resubmits" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+5 too many resubmits 1
+])
+
+OVS_VSWITCHD_STOP(["/|WARN|/d"])
+AT_CLEANUP
+
+
+AT_SETUP([drop-stats - stack too deep])
+OVS_VSWITCHD_START
+add_of_ports br0 1
+(for i in `seq 1 12`; do
+     j=`expr $i + 1`
+     echo "in_port=$i, actions=resubmit:$j, resubmit:$j, local"
+ done
+ push="push:NXM_NX_REG0[[]]"
+ echo "in_port=13, actions=$push,$push,$push,$push,$push,$push,$push,$push") > flows
+ AT_CHECK([ovs-ofctl add-flows br0 flows])
+
+ovs-appctl netdev-dummy/receive p1 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x1234)'
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "stack too deep" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+6 stack too deep 1
+])
+
+OVS_VSWITCHD_STOP(["/resubmits yielded over 64 kB of stack/d"])
+AT_CLEANUP
+
+AT_SETUP([drop-stats - too many mpls labels])
+
+OVS_VSWITCHD_START([dnl
+    set bridge br0 datapath_type=dummy \
+        protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \
+    add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \
+    add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2])
+
+AT_DATA([flows.txt], [dnl
+table=0, in_port=1, actions=push_mpls:0x8847, resubmit:3
+table=0, in_port=3, actions=push_mpls:0x8847, set_field:10->mpls_label, set_field:15->mpls_label,  resubmit:4
+table=0, in_port=4, actions=push_mpls:0x8847, set_field:11->mpls_label, resubmit:5
+table=0, in_port=5, actions=push_mpls:0x8847, set_field:12->mpls_label, resubmit:6
+table=0, in_port=6, actions=push_mpls:0x8847, set_field:13->mpls_label, output:2
+])
+
+AT_CHECK([
+    ovs-ofctl del-flows br0
+    ovs-ofctl -Oopenflow13 add-flows br0 flows.txt
+])
+
+AT_CHECK([
+    ovs-appctl netdev-dummy/receive p1 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
+], [0], [ignore])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "too many mpls labels" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+9 too many mpls labels 1
+])
+
+OVS_VSWITCHD_STOP(["/|WARN|/d"])
+AT_CLEANUP
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index 362c58d..1d89b00 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -713,7 +713,7 @@ AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=ff,bucket=wa
 AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=write_actions(group:1234)'])
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -3524,51 +3524,51 @@ dnl Each of these specifies an in_port by number, a VLAN VID (or "none"),
 dnl a VLAN PCP (used if the VID isn't "none") and the expected set of datapath
 dnl actions.
 for tuple in \
-        "100 none 0 drop" \
-        "100 0    0 drop" \
-        "100 0    1 drop" \
+        "100 none 0 drop:pipeline-drop" \
+        "100 0    0 drop:pipeline-drop" \
+        "100 0    1 drop:pipeline-drop" \
         "100 10   0 1,5,6,7,8,pop_vlan,2,9" \
         "100 10   1 1,5,6,7,8,pop_vlan,2,9" \
         "100 11   0 5,7" \
         "100 11   1 5,7" \
         "100 12   0 1,5,6,pop_vlan,3,4,7,8,11,12" \
         "100 12   1 1,5,6,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
-        "1  none 0 drop" \
-        "1  0    0 drop" \
-        "1  0    1 drop" \
+        "1  none 0 drop:pipeline-drop" \
+        "1  0    0 drop:pipeline-drop" \
+        "1  0    1 drop:pipeline-drop" \
         "1  10   0 5,6,7,8,100,pop_vlan,2,9" \
         "1  10   1 5,6,7,8,100,pop_vlan,2,9" \
-        "1  11   0 drop" \
-        "1  11   1 drop" \
+        "1  11   0 drop:pipeline-drop" \
+        "1  11   1 drop:pipeline-drop" \
         "1  12   0 5,6,100,pop_vlan,3,4,7,8,11,12" \
         "1  12   1 5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
         "2  none 0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "2  0    0 pop_vlan,9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "2  0    1 pop_vlan,9,push_vlan(vid=10,pcp=1),1,5,6,7,8,100" \
-        "2  10   0 drop" \
-        "2  10   1 drop" \
-        "2  11   0 drop" \
-        "2  11   1 drop" \
-        "2  12   0 drop" \
-        "2  12   1 drop" \
+        "2  10   0 drop:pipeline-drop" \
+        "2  10   1 drop:pipeline-drop" \
+        "2  11   0 drop:pipeline-drop" \
+        "2  11   1 drop:pipeline-drop" \
+        "2  12   0 drop:pipeline-drop" \
+        "2  12   1 drop:pipeline-drop" \
         "3  none 0 4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "3  0    0 pop_vlan,4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "3  0    1 8,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
-        "3  10   0 drop" \
-        "3  10   1 drop" \
-        "3  11   0 drop" \
-        "3  11   1 drop" \
-        "3  12   0 drop" \
-        "3  12   1 drop" \
+        "3  10   0 drop:pipeline-drop" \
+        "3  10   1 drop:pipeline-drop" \
+        "3  11   0 drop:pipeline-drop" \
+        "3  11   1 drop:pipeline-drop" \
+        "3  12   0 drop:pipeline-drop" \
+        "3  12   1 drop:pipeline-drop" \
         "4  none 0 3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "4  0    0 pop_vlan,3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "4  0    1 3,8,12,pop_vlan,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
-        "4  10   0 drop" \
-        "4  10   1 drop" \
-        "4  11   0 drop" \
-        "4  11   1 drop" \
-        "4  12   0 drop" \
-        "4  12   1 drop" \
+        "4  10   0 drop:pipeline-drop" \
+        "4  10   1 drop:pipeline-drop" \
+        "4  11   0 drop:pipeline-drop" \
+        "4  11   1 drop:pipeline-drop" \
+        "4  12   0 drop:pipeline-drop" \
+        "4  12   1 drop:pipeline-drop" \
         "5  none 0 2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \
         "5  0    0 pop_vlan,2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \
         "5  0    1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,6,7,8,100" \
@@ -3583,8 +3583,8 @@ for tuple in \
         "6  0    1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,5,7,8,100" \
         "6  10   0 1,5,7,8,100,pop_vlan,2,9" \
         "6  10   1 1,5,7,8,100,pop_vlan,2,9" \
-        "6  11   0 drop" \
-        "6  11   1 drop" \
+        "6  11   0 drop:pipeline-drop" \
+        "6  11   1 drop:pipeline-drop" \
         "6  12   0 1,5,100,pop_vlan,3,4,7,8,11,12" \
         "6  12   1 1,5,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
         "7  none 0 3,4,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
@@ -3601,16 +3601,16 @@ for tuple in \
         "8  0    1 3,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
         "8  10   0 1,5,6,7,100,pop_vlan,2,9" \
         "8  10   1 1,5,6,7,100,pop_vlan,2,9" \
-        "8  11   0 drop" \
-        "8  11   1 drop" \
+        "8  11   0 drop:pipeline-drop" \
+        "8  11   1 drop:pipeline-drop" \
         "8  12   0 1,5,6,100,pop_vlan,3,4,7,11,12" \
         "8  12   1 1,5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,12" \
         "9  none 0 2,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "9  10   0 10,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "9  11   0 push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
-        "10 none 0 drop" \
-        "10 0    0 drop" \
-        "10 11   0 drop" \
+        "10 none 0 drop:pipeline-drop" \
+        "10 0    0 drop:pipeline-drop" \
+        "10 11   0 drop:pipeline-drop" \
         "10 12   0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
         "11 10   0 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
         "11 10   1 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100"
@@ -4350,11 +4350,11 @@ no_flow="$base_flow,frag=no),tcp(src=12345,dst=80)"
 first_flow="$base_flow,frag=first),tcp(src=12345,dst=80)"
 later_flow="$base_flow,frag=later)"
 
-    # mode    no  first  later
+    # mode    no     first                later
 for tuple in \
-    'normal    1     5      6' \
-    'drop      1  drop   drop' \
-    'nx-match  1     2      6'
+    'normal    1     5                    6' \
+    'drop      1     drop:pipeline-drop   drop:pipeline-drop' \
+    'nx-match  1     2                    6'
 do
   set $tuple
   mode=$1
@@ -4432,8 +4432,8 @@ done
 AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
 flow-dump from non-dpdk interfaces:
 recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0, bytes:0, used:never, actions:set(tcp(dst=81)),1
-recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never, actions:drop
-recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 mode=nx-match
@@ -5711,7 +5711,7 @@ bridge("br0")
 
 Final flow: <cleared>
 Megaflow: <cleared>
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 dnl Now, try again without megaflows:
@@ -5732,7 +5732,7 @@ bridge("br0")
 
 Final flow: <cleared>
 Megaflow: <cleared>
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP
@@ -7026,7 +7026,7 @@ for i in `seq 1 3`; do
 done
 AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
 flow-dump from non-dpdk interfaces:
-packets:2, bytes:68, used:0.001s, actions:drop
+packets:2, bytes:68, used:0.001s, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP(["/sending to collector failed/d"])
@@ -7118,7 +7118,7 @@ for i in `seq 1 3`; do
 done
 AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
 flow-dump from non-dpdk interfaces:
-packets:2, bytes:68, used:0.001s, actions:drop
+packets:2, bytes:68, used:0.001s, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP(["/sending to collector failed/d
@@ -7792,21 +7792,21 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
 AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
 ovs-appctl revalidator/wait
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
-recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows br1 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl dpif/dump-flows -m br1 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP
@@ -7829,7 +7829,7 @@ m4_define([OFPROTO_DPIF_GET_FLOW],
 
    UFID=`sed -n 's/\(ufid:[[-0-9a-fA-F]]*\).*/\1/p' stdout`
    AT_CHECK([ovs-appctl dpctl/get-flow $UFID], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
 ])
 
    OVS_VSWITCHD_STOP
@@ -8577,11 +8577,11 @@ table=0 in_port=1,ip,nw_dst=10.0.0.3 actions=drop
    sleep 1
    AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
 skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:2
-skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop
+skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop:pipeline-drop
 ])
    AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_dump | grep 'packets:3'], [0], [dnl
 skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:2
-skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:drop
+skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:drop:pipeline-drop
 ])
    OVS_VSWITCHD_STOP
    AT_CLEANUP])
@@ -9312,7 +9312,7 @@ for i in 1 2 3; do
 done
 
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop:pipeline-drop
 ])
 
 # Add a flow that matches the non-presence of a vlan tag, and check
@@ -9341,16 +9341,16 @@ done
 
 AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
 recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:8, bytes:112, used:0.0s, actions:100
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), packets:2, bytes:36, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), packets:2, bytes:36, used:0.0s, actions:drop:pipeline-drop
 ])
 
 # Check that the new flow matches the CFI bit, while both vid and pcp
 # are wildcarded.
 AT_CHECK([grep '\(modify\)\|\(flow_add\)' ovs-vswitchd.log | strip_ufid ], [0], [dnl
 dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), actions:100
-dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234)
+dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:drop:pipeline-drop
 dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:100
-dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop
+dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop:pipeline-drop
 ])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
@@ -9675,7 +9675,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
 
 
 AT_CHECK([cat ovs-vswitchd.log | strip_ufid | filter_flow_install], [0], [dnl
-ct_state(+new-est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:drop
+ct_state(+new-est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:drop:pipeline-drop
 ct_state(-new+est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:1
 recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct(commit),2
 recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct,recirc(0x1)
@@ -10362,7 +10362,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
 
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,udp'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 
 AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,udp'], [0], [stdout])
@@ -10454,7 +10454,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'recirc_id(0),in_port(1),eth_type(0
 ovs-appctl time/warp 5000
 
 AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop:pipeline-drop
 ])
 
 dnl Change the flow table.  This will trigger revalidation of all the flows.
diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at
index fef6aa4..8086bbf 100644
--- a/tests/ovs-ofctl.at
+++ b/tests/ovs-ofctl.at
@@ -2987,7 +2987,7 @@ AT_CHECK([tail -1 stdout], [0],
 dnl Inbound web traffic with SYN bit without ACK or RST bits
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.2,dst=192.168.0.1,proto=6,tos=0,ttl=64,frag=no),tcp(src=80,dst=8),tcp_flags(0xfeb)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0],
-  [Datapath actions: drop
+  [Datapath actions: drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP
diff --git a/tests/packet-type-aware.at b/tests/packet-type-aware.at
index bfb47b4..a56b0ee 100644
--- a/tests/packet-type-aware.at
+++ b/tests/packet-type-aware.at
@@ -505,7 +505,7 @@ AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
 recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
-tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop
+tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
@@ -565,7 +565,13 @@ ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:unsupported packet type
+])
+
+AT_CHECK([
+    ovs-appctl dpif/show-drop-stats --detail | grep "unsupported packet type" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+11 unsupported packet type 2
 ])
 
 # Encap(ethernet) on Ethernet frame -> should be droped
@@ -587,7 +593,7 @@ ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:pipeline-drop
 ])
 
 # Encap(ethernet) on VLAN tagged Ethernet frame -> should be droped
@@ -609,7 +615,7 @@ ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:unsupported packet type
 ])
 
 OVS_VSWITCHD_STOP
@@ -770,7 +776,7 @@ ovs-appctl time/warp 1000
 AT_CHECK([
     ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
 ], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:pipeline-drop
 ])
 
 AT_CHECK([
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 690904e..01def11 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -81,3 +81,4 @@ m4_include([tests/ovn-controller-vtep.at])
 m4_include([tests/mcast-snooping.at])
 m4_include([tests/packet-type-aware.at])
 m4_include([tests/nsh.at])
+m4_include([tests/drop-stats.at])
diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at
index f717243..9073420 100644
--- a/tests/tunnel-push-pop.at
+++ b/tests/tunnel-push-pop.at
@@ -447,6 +447,24 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  7'], [0], [dnl
   port  7: rx pkts=3, bytes=252, drop=?, errs=?, frame=?, over=?, crc=?
 ])
 
+AT_CHECK([ovs-appctl dpif/clear-drop-stats])
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+
+AT_CHECK([
+ovs-appctl dpif/show-drop-stats --detail | grep "tunnel pop action" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+16 tunnel pop action errors 1
+])
+
+AT_CHECK([ovs-appctl dpif/clear-drop-stats])
+AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004503007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+
+AT_CHECK([
+ovs-appctl dpif/show-drop-stats --detail | grep "ecn mismatch" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+12 ecn mismatch at tunnel decapsulation 1
+])
+
 dnl Check GREL3 only accepts non-fragmented packets?
 AT_CHECK([ovs-appctl netdev-dummy/receive p0 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c0101025820000800000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
 
@@ -455,7 +473,7 @@ ovs-appctl time/warp 1000
 
 AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port  [[37]]' | sort], [0], [dnl
   port  3: rx pkts=3, bytes=294, drop=?, errs=?, frame=?, over=?, crc=?
-  port  7: rx pkts=4, bytes=350, drop=?, errs=?, frame=?, over=?, crc=?
+  port  7: rx pkts=5, bytes=434, drop=?, errs=?, frame=?, over=?, crc=?
 ])
 
 dnl Check decapsulation of Geneve packet with options
@@ -510,7 +528,8 @@ AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
 Listening ports:
 ])
 
-OVS_VSWITCHD_STOP
+OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d
+/ip packet has invalid checksum/d"])
 AT_CLEANUP
 
 AT_SETUP([tunnel_push_pop - packet_out])
diff --git a/tests/tunnel.at b/tests/tunnel.at
index e110a82..3d923f6 100644
--- a/tests/tunnel.at
+++ b/tests/tunnel.at
@@ -102,10 +102,12 @@ Datapath actions: set(ipv4(tos=0x3/0x3)),2
 
 dnl Tunnel CE and encapsulated packet Non-ECT
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(src=1.1.1.1,dst=2.2.2.2,tos=0x3,ttl=64,flags()),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
-AT_CHECK([tail -2 stdout], [0],
+AT_CHECK([tail -3 stdout], [0],
   [Megaflow: recirc_id=0,eth,ip,tun_id=0,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=3,tun_flags=-df-csum-key,in_port=1,nw_ecn=0,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:ecn mismatch at tunnel decapsulation
+Translation failed (CONGESTION DROP), packet is dropped.
 ])
+
 OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d"])
 AT_CLEANUP
 
@@ -193,6 +195,15 @@ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=50:54:00:00:00:
 AT_CHECK([tail -1 stdout], [0],
   [Datapath actions: set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,ttl=64,flags(df|key))),set(skb_mark(0x2)),1
 ])
+
+AT_CHECK([ovs-appctl dpif/clear-drop-stats])
+AT_CHECK([ovs-appctl netdev-dummy/receive p2 'aa55aa550001f8bc124434b6080045000054ba20000040018486010103580101037001004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
+
+AT_CHECK([
+ovs-appctl dpif/show-drop-stats --detail | grep "invalid port" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+23 invalid port 1
+])
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
@@ -364,7 +375,7 @@ Datapath actions: 4,3,5
 
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'tunnel(tun_id=0x0,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)),in_port(1),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=6,tos=0,ttl=64,frag=no),tcp(src=8,dst=9)'], [0], [stdout])
 AT_CHECK([tail -1 stdout], [0], [dnl
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 OVS_VSWITCHD_STOP
@@ -571,7 +582,7 @@ dnl receive packet from ERSPAN port with wrong v1 metadata
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x1,src=1.1.1.1,dst=2.2.2.2,ttl=64,erspan(ver=1,idx=0xabcd),flags(df|key)),in_port(3),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,ip,tun_id=0x1,tun_src=1.1.1.1,tun_dst=2.2.2.2,tun_tos=0,tun_erspan_ver=1,tun_erspan_idx=0xabcd,tun_flags=+df-csum+key,in_port=3,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 dnl receive packet from ERSPAN port with v2 metadata
@@ -585,7 +596,7 @@ dnl receive packet from ERSPAN port with wrong v2 metadata
 AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'recirc_id(0),tunnel(tun_id=0x2,src=1.1.1.2,dst=2.2.2.2,ttl=64,erspan(ver=2,dir=0,hwid=0x17),flags(df|key)),in_port(3),skb_mark(0),eth(src=50:54:00:00:00:05,dst=50:54:00:00:00:07),eth_type(0x0800),ipv4(frag=no)'], [0], [stdout])
 AT_CHECK([tail -2 stdout], [0],
   [Megaflow: recirc_id=0,eth,ip,tun_id=0x2,tun_src=1.1.1.2,tun_dst=2.2.2.2,tun_tos=0,tun_erspan_ver=2,tun_erspan_dir=0,tun_erspan_hwid=0x1,tun_flags=+df-csum+key,in_port=4,nw_frag=no
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
 ])
 
 dnl test wildcard mask: recevie all v2 regardless of its metadata
