Thank you Ben,

Regards
Anju
-----Original Message-----
From: Ben Pfaff [mailto:b...@ovn.org] 
Sent: Friday, January 18, 2019 10:35 AM
To: Anju Thomas <anju.tho...@ericsson.com>
Cc: d...@openvswitch.org; Rohith Basavaraja <rohith.basavar...@gmail.com>; 
Keshav Gupta <keshugup...@gmail.com>
Subject: Re: [PATCH v6] Improved Packet Drop Statistics in OVS

Yes.  Thank you.  I'll review it tomorrow.

On Fri, Jan 18, 2019 at 04:54:51AM +0000, Anju Thomas wrote:
> Hi Ben,
> Were you able to apply this patch successfully?
> Regards
> Anju
> 
> -----Original Message-----
> From: Anju Thomas [mailto:anju.tho...@ericsson.com] 
> Sent: Thursday, January 17, 2019 10:19 AM
> To: d...@openvswitch.org
> Cc: Anju Thomas <anju.tho...@ericsson.com>; Rohith Basavaraja 
> <rohith.basavar...@gmail.com>; Keshav Gupta <keshugup...@gmail.com>
> Subject: [PATCH v6] Improved Packet Drop Statistics in OVS
> 
> Currently OVS maintains explicit packet drop/error counters only on port
>     level. Packets that are dropped as part of normal OpenFlow processing are
>     counted in flow stats of “drop” flows or as table misses in table stats.
>     These can only be interpreted by controllers that know the semantics of
>     the configured OpenFlow pipeline. Without that knowledge, it is impossible
>     for an OVS user to obtain e.g. the total number of packets dropped due to
>     OpenFlow rules.
> 
>     Furthermore, there are numerous other reasons for which packets can be
>     dropped by OVS slow path that are not related to the OpenFlow pipeline.
>     The generated datapath flow entries include a drop action to avoid further
>     expensive upcalls to the slow path, but subsequent packets dropped by the
>     datapath are not accounted anywhere.
> 
>     Finally, the datapath itself drops packets in certain error situations.
>     Also, these drops are today not accounted for.
> 
>     This makes it difficult for OVS users to monitor packet drop in an OVS
>     instance and to alert a management system in case of a unexpected increase
>     of such drops. Also OVS trouble-shooters face difficulties in analysing
>     packet drops.
> 
>     With this patch we implement following changes to address the issues
>     mentioned above.
> 
>     1. Account and categorize all the packet drops in OVS.
>     2. Account & classify “drop” action packet drops according to the drop
>        reason.
>     3. Identify and account all the silent packet drop scenarios.
>     4. Display these drops in ovs-appctl coverage/show
>     5. Modified ovs-appctl dpcls/dump-flows and ovs-appctl dpif/dump-flows
>        to print drop reason along with drop action
> 
>     A detailed presentation on this was presented at OvS conference 2017 and
>     link for the corresponding presentation is available at:
>     
> https://www.slideshare.net/LF_OpenvSwitch/lfovs17troubleshooting-the-data-plane-in-ovs-82280329
> 
>     Sample ovs-appctl dpcls/dump-flows & ovs-appctl dpif/dump-flows 
> displaying drop reason along with drop action.
> 
>      The idea is to use the coverage infrastructure to maintain the drops
> 
>     $ ovs-appctl dpctl/dump-flows netdev at ovs-netdev
>     flow-dump from pmd on cpu core: 0
>     
> recirc_id(0),in_port(5),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
>  packets:12, bytes:1176, used:0.884s, actions:drop:recursion too deep
> 
>     $ ovs-appctl dpif/dump-flows br-int
>     
> recirc_id(0),in_port(5),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
>  packets:25, bytes:2450, used:5.008s, actions:drop:recursion too deep
>     recirc_id(0),in_port(5),packet_type(ns=0,id=0),eth_type(0x0806), 
> packets:7, bytes:294, used:0.009s, actions:drop:recursion too deep
> 
>    In subsequent commits, we are planning to see if we can use this 
> infrastructure to create a
>    wrapper to clear and display counters as well.
> 
> Co-authored-by: Rohith Basavaraja <rohith.basavar...@gmail.com>
> Co-authored-by: Keshav Gupta <keshugup...@gmail.com>
> Signed-off-by: Anju Thomas <anju.tho...@ericsson.com>
> Signed-off-by: Rohith Basavaraja <rohith.basavar...@gmail.com>
> Signed-off-by: Keshav Gupta <keshugup...@gmail.com>
> ---
>  datapath/linux/compat/include/linux/openvswitch.h |  51 ++++++
>  lib/coverage.c                                    |   6 +-
>  lib/coverage.h                                    |   3 +-
>  lib/dpif-netdev.c                                 | 105 +++++++++++-
>  lib/dpif.c                                        |  10 +-
>  lib/dpif.h                                        |   3 +
>  lib/netdev-dpdk.c                                 |   4 +
>  lib/odp-execute.c                                 |  50 ++++--
>  lib/odp-execute.h                                 |  10 +-
>  lib/odp-util.c                                    |  54 +++++-
>  ofproto/ofproto-dpif-ipfix.c                      |   1 +
>  ofproto/ofproto-dpif-sflow.c                      |   1 +
>  ofproto/ofproto-dpif-upcall.c                     |   3 +-
>  ofproto/ofproto-dpif-xlate.c                      |  64 +++++++
>  ofproto/ofproto-dpif-xlate.h                      |   4 +
>  ofproto/ofproto-dpif.c                            |  11 +-
>  ofproto/ofproto-dpif.h                            |   8 +-
>  tests/automake.mk                                 |   3 +-
>  tests/bundle.at                                   |   2 +-
>  tests/classifier.at                               |  10 +-
>  tests/dpif-netdev.at                              |  17 +-
>  tests/drop-stats.at                               | 197 
> ++++++++++++++++++++++
>  tests/ofproto-dpif.at                             | 118 ++++++-------
>  tests/ovs-ofctl.at                                |   2 +-
>  tests/packet-type-aware.at                        |  17 +-
>  tests/testsuite.at                                |   1 +
>  tests/tunnel-push-pop.at                          |  26 ++-
>  tests/tunnel.at                                   |  21 ++-
>  28 files changed, 695 insertions(+), 107 deletions(-)
>  create mode 100644 tests/drop-stats.at
> 
> diff --git a/datapath/linux/compat/include/linux/openvswitch.h 
> b/datapath/linux/compat/include/linux/openvswitch.h
> index 9b087f1..b66b46f 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).
> @@ -938,6 +988,7 @@ enum ovs_action_attr {
>       OVS_ACTION_ATTR_POP_NSH,      /* No argument. */
>       OVS_ACTION_ATTR_METER,        /* u32 meter number. */
>       OVS_ACTION_ATTR_CLONE,        /* Nested OVS_CLONE_ATTR_*.  */
> +        OVS_ACTION_ATTR_DROP,         /* explicit drop action. */
>  
>  #ifndef __KERNEL__
>       OVS_ACTION_ATTR_TUNNEL_PUSH,   /* struct ovs_action_push_tnl*/
> diff --git a/lib/coverage.c b/lib/coverage.c
> index 6cef826..c9acc37 100644
> --- a/lib/coverage.c
> +++ b/lib/coverage.c
> @@ -32,9 +32,7 @@ VLOG_DEFINE_THIS_MODULE(coverage);
>  static struct coverage_counter **coverage_counters = NULL;
>  static size_t n_coverage_counters = 0;
>  static size_t allocated_coverage_counters = 0;
> -
> -static struct ovs_mutex coverage_mutex = OVS_MUTEX_INITIALIZER;
> -
> +struct ovs_mutex coverage_mutex = OVS_MUTEX_INITIALIZER;
>  DEFINE_STATIC_PER_THREAD_DATA(long long int, coverage_clear_time, LLONG_MIN);
>  static long long int coverage_run_time = LLONG_MIN;
>  
> @@ -52,7 +50,7 @@ coverage_counter_register(struct coverage_counter* counter)
>      if (n_coverage_counters >= allocated_coverage_counters) {
>          coverage_counters = x2nrealloc(coverage_counters,
>                                         &allocated_coverage_counters,
> -                                       sizeof(struct coverage_counter*));
> +                                       sizeof(struct coverage_counter *));
>      }
>      coverage_counters[n_coverage_counters++] = counter;
>  }
> diff --git a/lib/coverage.h b/lib/coverage.h
> index dea990e..45b1dbd 100644
> --- a/lib/coverage.h
> +++ b/lib/coverage.h
> @@ -54,7 +54,8 @@ struct coverage_counter {
>      unsigned int hr[HR_AVG_LEN];
>  };
>  
> -void coverage_counter_register(struct coverage_counter*);
> +extern struct ovs_mutex coverage_mutex;
> +void coverage_counter_register(struct coverage_counter *);
>  
>  /* Defines COUNTER.  There must be exactly one such definition at file scope
>   * within a program. */
> diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
> index be529b6..8749cba 100644
> --- a/lib/dpif-netdev.c
> +++ b/lib/dpif-netdev.c
> @@ -100,6 +100,30 @@ enum { MAX_METERS = 65536 };    /* Maximum number of 
> meters. */
>  enum { MAX_BANDS = 8 };         /* Maximum number of bands / meter. */
>  enum { N_METER_LOCKS = 64 };    /* Maximum number of meters. */
>  
> +
> +COVERAGE_DEFINE(drop_action_of_pipeline);
> +COVERAGE_DEFINE(drop_action_bridge_not_found);
> +COVERAGE_DEFINE(drop_action_recursion_too_deep);
> +COVERAGE_DEFINE(drop_action_too_many_resubmit);
> +COVERAGE_DEFINE(drop_action_stack_too_deep);
> +COVERAGE_DEFINE(drop_action_no_recirculation_context);
> +COVERAGE_DEFINE(drop_action_recirculation_conflict);
> +COVERAGE_DEFINE(drop_action_too_many_mpls_labels);
> +COVERAGE_DEFINE(drop_action_invalid_tunnel_metadata);
> +COVERAGE_DEFINE(drop_action_unsupported_packet_type);
> +COVERAGE_DEFINE(drop_action_congestion);
> +COVERAGE_DEFINE(drop_action_forwarding_disabled);
> +COVERAGE_DEFINE(dp_meter_drop);
> +COVERAGE_DEFINE(dp_upcall_error_drop);
> +COVERAGE_DEFINE(dp_lock_error_drop);
> +COVERAGE_DEFINE(dp_userspace_action_error_drop);
> +COVERAGE_DEFINE(dp_tunnel_push_error_drop);
> +COVERAGE_DEFINE(dp_tunnel_pop_error_drop);
> +COVERAGE_DEFINE(dp_recirc_error_drop);
> +COVERAGE_DEFINE(dp_invalid_port_drop);
> +COVERAGE_DEFINE(dp_invalid_tnl_port_drop);
> +COVERAGE_DEFINE(rx_invalid_packet_drop);
> +
>  /* Protects against changes to 'dp_netdevs'. */
>  static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER;
>  
> @@ -829,7 +853,6 @@ static inline bool
>  pmd_perf_metrics_enabled(const struct dp_netdev_pmd_thread *pmd);
>  static void queue_netdev_flow_del(struct dp_netdev_pmd_thread *pmd,
>                                    struct dp_netdev_flow *flow);
> -
>  static void
>  emc_cache_init(struct emc_cache *flow_cache)
>  {
> @@ -1388,6 +1411,7 @@ dpif_netdev_init(void)
>      return 0;
>  }
>  
> +
>  static int
>  dpif_netdev_enumerate(struct sset *all_dps,
>                        const struct dpif_class *dpif_class)
> @@ -5563,7 +5587,7 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct 
> dp_packet_batch *packets_,
>              band = &meter->bands[exceeded_band[j]];
>              band->packet_count += 1;
>              band->byte_count += dp_packet_size(packet);
> -
> +            COVERAGE_INC(dp_meter_drop);
>              dp_packet_delete(packet);
>          } else {
>              /* Meter accepts packet. */
> @@ -6320,6 +6344,7 @@ dfc_processing(struct dp_netdev_pmd_thread *pmd,
>  
>          if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) {
>              dp_packet_delete(packet);
> +            COVERAGE_INC(rx_invalid_packet_drop);
>              continue;
>          }
>  
> @@ -6446,6 +6471,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd,
>                               put_actions);
>      if (OVS_UNLIKELY(error && error != ENOSPC)) {
>          dp_packet_delete(packet);
> +        COVERAGE_INC(dp_upcall_error_drop);
>          return error;
>      }
>  
> @@ -6577,6 +6603,7 @@ 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);
> +                COVERAGE_INC(dp_lock_error_drop);
>                  upcall_fail_cnt++;
>              }
>          }
> @@ -6846,10 +6873,59 @@ dp_execute_userspace_action(struct 
> dp_netdev_pmd_thread *pmd,
>                                    actions->data, actions->size);
>      } else if (should_steal) {
>          dp_packet_delete(packet);
> +        COVERAGE_INC(dp_userspace_action_error_drop);
>      }
>  }
>  
>  static void
> +dp_update_drop_action_counter_cb(enum ovs_drop_reason drop_reason,
> +                          int delta)
> +    OVS_NO_THREAD_SAFETY_ANALYSIS
> +{
> +   switch (drop_reason) {
> +   case OVS_DROP_REASON_OF_PIPELINE:
> +        COVERAGE_ADD(drop_action_of_pipeline, delta);
> +        break;
> +   case OVS_DROP_REASON_BRIDGE_NOT_FOUND:
> +        COVERAGE_ADD(drop_action_bridge_not_found, delta);
> +        break;
> +   case OVS_DROP_REASON_RECURSION_TOO_DEEP:
> +        COVERAGE_ADD(drop_action_recursion_too_deep, delta);
> +        break;
> +   case OVS_DROP_REASON_TOO_MANY_RESUBMITS:
> +        COVERAGE_ADD(drop_action_too_many_resubmit, delta);
> +        break;
> +   case OVS_DROP_REASON_STACK_TOO_DEEP:
> +        COVERAGE_ADD(drop_action_stack_too_deep, delta);
> +        break;
> +   case OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT:
> +        COVERAGE_ADD(drop_action_no_recirculation_context, delta);
> +        break;
> +   case OVS_DROP_REASON_RECIRCULATION_CONFLICT:
> +        COVERAGE_ADD(drop_action_recirculation_conflict, delta);
> +        break;
> +   case OVS_DROP_REASON_TOO_MANY_MPLS_LABELS:
> +        COVERAGE_ADD(drop_action_too_many_mpls_labels, delta);
> +        break;
> +   case OVS_DROP_REASON_INVALID_TUNNEL_METADATA:
> +        COVERAGE_ADD(drop_action_invalid_tunnel_metadata, delta);
> +        break;
> +   case OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE:
> +        COVERAGE_ADD(drop_action_unsupported_packet_type, delta);
> +        break;
> +   case OVS_DROP_REASON_CONGESTION:
> +        COVERAGE_ADD(drop_action_congestion, delta);
> +        break;
> +   case OVS_DROP_REASON_FORWARDING_DISABLED:
> +        COVERAGE_ADD(drop_action_forwarding_disabled, delta);
> +        break;
> +   case OVS_DROP_REASON_MAX:
> +   default:
> +        VLOG_ERR("Invalid Drop reason type:%d",drop_reason);
> +   }
> +}
> +
> +static void
>  dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
>                const struct nlattr *a, bool should_steal)
>      OVS_NO_THREAD_SAFETY_ANALYSIS
> @@ -6860,6 +6936,7 @@ 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;
>  
>      switch ((enum ovs_action_attr)type) {
>      case OVS_ACTION_ATTR_OUTPUT:
> @@ -6901,6 +6978,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> *packets_,
>                  dp_packet_batch_add(&p->output_pkts, packet);
>              }
>              return;
> +        } else {
> +            COVERAGE_ADD(dp_invalid_port_drop, packets_->count);
>          }
>          break;
>  
> @@ -6910,10 +6989,13 @@ 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. */
> +            COVERAGE_ADD(dp_tunnel_push_error_drop, packets_->count);
>              break;
>          }
>          dp_packet_batch_apply_cutlen(packets_);
> -        push_tnl_action(pmd, a, packets_);
> +        if (push_tnl_action(pmd, a, packets_)) {
> +            COVERAGE_ADD(dp_tunnel_push_error_drop, packets_->count);
> +        }
>          return;
>  
>      case OVS_ACTION_ATTR_TUNNEL_POP:
> @@ -6933,7 +7015,12 @@ 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) {
> +                    COVERAGE_ADD(dp_tunnel_pop_error_drop, packet_dropped);
> +                }
>                  if (dp_packet_batch_is_empty(packets_)) {
>                      return;
>                  }
> @@ -6947,7 +7034,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> *packets_,
>                  dp_netdev_recirculate(pmd, packets_);
>                  (*depth)--;
>                  return;
> +            } else {
> +                COVERAGE_ADD(dp_invalid_tnl_port_drop, packets_->count);
>              }
> +        } else {
> +            COVERAGE_ADD(dp_recirc_error_drop, packets_->count);
>          }
>          break;
>  
> @@ -6991,6 +7082,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> *packets_,
>              fat_rwlock_unlock(&dp->upcall_rwlock);
>  
>              return;
> +        } else {
> +            COVERAGE_ADD(dp_lock_error_drop, packets_->count);
>          }
>          break;
>  
> @@ -7013,6 +7106,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch 
> *packets_,
>              (*depth)--;
>  
>              return;
> +        } else {
> +            COVERAGE_ADD(dp_recirc_error_drop, packets_->count);
>          }
>  
>          VLOG_WARN("Packet dropped. Max recirculation depth exceeded.");
> @@ -7167,6 +7262,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();
>      }
> @@ -7183,7 +7279,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_action_counter_cb);
>  }
>  
>  struct dp_netdev_ct_dump {
> diff --git a/lib/dpif.c b/lib/dpif.c
> index e35f111..21f9f54 100644
> --- a/lib/dpif.c
> +++ b/lib/dpif.c
> @@ -1273,6 +1273,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();
> @@ -1295,7 +1296,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;
>  }
>  
> @@ -1879,6 +1880,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,
> @@ -1976,3 +1983,4 @@ dpif_meter_del(struct dpif *dpif, ofproto_meter_id 
> meter_id,
>      }
>      return error;
>  }
> +
> diff --git a/lib/dpif.h b/lib/dpif.h
> index 475d5a6..e799da8 100644
> --- a/lib/dpif.h
> +++ b/lib/dpif.h
> @@ -888,6 +888,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 320422b..0c3bc9c 100644
> --- a/lib/netdev-dpdk.c
> +++ b/lib/netdev-dpdk.c
> @@ -2395,6 +2395,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 3b6890e..c0db93f 100644
> --- a/lib/odp-execute.c
> +++ b/lib/odp-execute.c
> @@ -25,6 +25,7 @@
>  #include <stdlib.h>
>  #include <string.h>
>  
> +#include "coverage.h"
>  #include "dp-packet.h"
>  #include "dpif.h"
>  #include "netlink.h"
> @@ -37,6 +38,10 @@
>  #include "csum.h"
>  #include "conntrack.h"
>  
> +COVERAGE_DEFINE(dp_sample_error_drop);
> +COVERAGE_DEFINE(dp_nsh_decap_error_drop);
> +
> +
>  /* Masked copy of an ethernet address. 'src' is already properly masked. */
>  static void
>  ether_addr_copy_masked(struct eth_addr *dst, const struct eth_addr src,
> @@ -575,7 +580,9 @@ 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_action_counter_cb
> +                     dp_update_drop_action_counter)
>  {
>      const struct nlattr *subactions = NULL;
>      const struct nlattr *a;
> @@ -589,6 +596,7 @@ 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) {
> +                    COVERAGE_ADD(dp_sample_error_drop, 1);
>                      dp_packet_delete(packet);
>                  }
>                  return;
> @@ -616,13 +624,16 @@ 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_action_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_action_counter_cb
> +                      dp_update_drop_action_counter)
>  {
>      if (!steal) {
>          /* The 'actions' may modify the packet, but the modification
> @@ -634,11 +645,12 @@ 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);
> -    }
> -    else {
> +                        nl_attr_get_size(actions), dp_execute_action,
> +                        dp_update_drop_action_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_action_counter);
>      }
>  }
>  
> @@ -673,6 +685,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,12 +712,15 @@ 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_action_counter_cb
> +                       dp_update_drop_action_counter)
>  {
>      struct dp_packet *packet;
>      const struct nlattr *a;
>      unsigned int left;
>  
> +
>      NL_ATTR_FOR_EACH_UNSAFE (a, left, actions, actions_len) {
>          int type = nl_attr_type(a);
>          bool last_action = (left <= NLA_ALIGN(a->nla_len));
> @@ -822,7 +838,8 @@ 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_action_counter);
>              }
>  
>              if (last_action) {
> @@ -845,7 +862,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_action_counter);
>              if (last_action) {
>                  /* We do not need to free the packets. odp_execute_clone() 
> has
>                   * stolen them.  */
> @@ -889,6 +907,7 @@ odp_execute_actions(void *dp, struct dp_packet_batch 
> *batch, bool steal,
>                  if (pop_nsh(packet)) {
>                      dp_packet_batch_refill(batch, packet, i);
>                  } else {
> +                    COVERAGE_INC(dp_nsh_decap_error_drop);
>                      dp_packet_delete(packet);
>                  }
>              }
> @@ -900,6 +919,17 @@ 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_action_counter) {
> +                 dp_update_drop_action_counter(drop_reason, 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..a84ecbb 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_action_counter_cb) (
> +                                           enum  ovs_drop_reason drop_reason,
> +                                           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,7 @@ 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_action_counter_cb
> +                             dp_update_drop_action_counter_cb);
>  #endif
> diff --git a/lib/odp-util.c b/lib/odp-util.c
> index 0491bed..9754fd5 100644
> --- a/lib/odp-util.c
> +++ b/lib/odp-util.c
> @@ -131,6 +131,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:
> @@ -345,6 +346,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)
> @@ -1181,6 +1225,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:
> @@ -2427,8 +2474,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 7da3175..69ed7b8 100644
> --- a/ofproto/ofproto-dpif-sflow.c
> +++ b/ofproto/ofproto-dpif-sflow.c
> @@ -1222,6 +1222,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-upcall.c b/ofproto/ofproto-dpif-upcall.c
> index dc30824..b1ce2ec 100644
> --- a/ofproto/ofproto-dpif-upcall.c
> +++ b/ofproto/ofproto-dpif-upcall.c
> @@ -1154,7 +1154,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)
>  {
> @@ -1244,6 +1244,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
> diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
> index 839fddd..32c4edf 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);
>  
> @@ -5921,6 +5957,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)
>  {
> @@ -7383,6 +7430,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;
> @@ -7415,6 +7466,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) {
> @@ -7522,6 +7574,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 0a5a528..bb3f9ff 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 14fe6fc..609226a 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -827,6 +827,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.
> @@ -1397,6 +1403,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);
> @@ -5776,6 +5784,7 @@ ofproto_unixctl_dpif_set_dp_features(struct 
> unixctl_conn *conn,
>      ds_destroy(&ds);
>  }
>  
> +
>  static void
>  ofproto_unixctl_init(void)
>  {
> @@ -5809,7 +5818,7 @@ ofproto_unixctl_init(void)
>      unixctl_command_register("dpif/set-dp-features", "bridge", 1, 3 ,
>                               ofproto_unixctl_dpif_set_dp_features, NULL);
>  }
> -
> 
> +
>  static odp_port_t
>  ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
>  {
> 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 92d56b2..22b4722 100644
> --- a/tests/automake.mk
> +++ b/tests/automake.mk
> @@ -108,7 +108,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
>  
>  EXTRA_DIST += $(FUZZ_REGRESSION_TESTS)
>  FUZZ_REGRESSION_TESTS = \
> diff --git a/tests/bundle.at b/tests/bundle.at
> index 0a4eadc..33fe249 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 6915d43..08349f6 100644
> --- a/tests/dpif-netdev.at
> +++ b/tests/dpif-netdev.at
> @@ -1,4 +1,4 @@
> -AT_BANNER([dpif-netdev])
> +T_BANNER([dpif-netdev])
>  
>  m4_divert_push([PREPARE_TESTS])
>  [
> @@ -281,6 +281,7 @@ type=drop rate=1 burst_size=2
>  ])
>  
>  ovs-appctl time/warp 5000
> +sleep 10
>  AT_CHECK([ovs-appctl netdev-dummy/receive p7 
> 'in_port(7),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)'
>  --len 60])
>  AT_CHECK([ovs-appctl netdev-dummy/receive p7 
> 'in_port(7),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)'
>  --len 60])
>  AT_CHECK([ovs-appctl netdev-dummy/receive p7 
> 'in_port(7),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)'
>  --len 60])
> @@ -291,7 +292,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),packet_type(ns=0,id=0),
>  AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),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.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>  --len 60])
>  AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),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.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>  --len 60])
>  AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),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.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>  --len 60])
> -sleep 1  # wait for forwarders process packets
> +# wait for forwarders process packets
>  
>  # Meter 1 is measuring packets, allowing one packet per second with
>  # bursts of one packet, so 4 out of 5 packets should hit the drop
> @@ -320,7 +321,8 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),packet_type(ns=0,id=0),
>  AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),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.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>  --len 60])
>  AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),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.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>  --len 60])
>  AT_CHECK([ovs-appctl netdev-dummy/receive p8 
> 'in_port(8),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.3,dst=10.0.0.4,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'
>  --len 60])
> -sleep 1  # wait for forwarders process packets
> +
> +sleep 10  # wait for forwarders process packets
>  
>  # Meter 1 is measuring packets, allowing one packet per second with
>  # bursts of one packet, so all 5 of the new packets should hit the drop
> @@ -337,6 +339,15 @@ meter:2 flow_count:1 packet_in_count:10 
> byte_in_count:600 duration:0.0s bands:
>  0: packet_count:5 byte_count:300
>  ])
>  
> +ovs-appctl time/warp 5000
> +sleep 10
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "dp_meter_drop" | cut -d':' -f2|sed 's/ //'
> +], [0], [dnl
> +14
> +])
> +
>  AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | 
> strip_xout_keep_actions], [0], [dnl
>  
> recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
>  actions:meter(0),7
>  
> recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
>  actions:8
> diff --git a/tests/drop-stats.at b/tests/drop-stats.at
> new file mode 100644
> index 0000000..be8b8ae
> --- /dev/null
> +++ b/tests/drop-stats.at
> @@ -0,0 +1,197 @@
> +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
> +])
> +
> +sleep 1
> +
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "drop_action_of_pipeline" | cut -d':' 
> -f2|sed 's/ //'
> +], [0], [dnl
> +3
> +])
> +
> +
> +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])
> +
> +sleep 1
> +
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "drop_action_of_pipeline" | cut -d':' 
> -f2|sed 's/ //'
> +], [0], [dnl
> +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])
> +
> +sleep 1
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "drop_action_recursion_too_deep" | cut -d':' 
> -f2|sed 's/ //'
> +], [0], [dnl
> +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)'
> +
> +sleep 1
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "drop_action_too_many_resubmit" | cut -d':' 
> -f2|sed 's/ //'
> +], [0], [dnl
> +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)'
> +
> +sleep 1
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "drop_action_stack_too_deep" | cut -d':' 
> -f2|sed 's/ //'
> +], [0], [dnl
> +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])
> +
> +sleep 1
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "drop_action_too_many_mpls_labels" | cut 
> -d':' -f2|sed 's/ //'
> +], [0], [dnl
> +1
> +])
> +
> +
> +OVS_VSWITCHD_STOP(["/|WARN|/d"])
> +AT_CLEANUP
> diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
> index ded2ef0..298aa9a 100644
> --- a/tests/ofproto-dpif.at
> +++ b/tests/ofproto-dpif.at
> @@ -3496,51 +3496,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" \
> @@ -3555,8 +3555,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" \
> @@ -3573,16 +3573,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"
> @@ -4322,11 +4322,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
> @@ -4404,8 +4404,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
> @@ -5751,7 +5751,7 @@ bridge("br0")
>  
>  Final flow: <cleared>
>  Megaflow: <cleared>
> -Datapath actions: drop
> +Datapath actions: drop:pipeline-drop
>  ])
>  
>  dnl Now, try again without megaflows:
> @@ -5772,7 +5772,7 @@ bridge("br0")
>  
>  Final flow: <cleared>
>  Megaflow: <cleared>
> -Datapath actions: drop
> +Datapath actions: drop:pipeline-drop
>  ])
>  
>  OVS_VSWITCHD_STOP
> @@ -7066,7 +7066,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"])
> @@ -7158,7 +7158,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
> @@ -7832,21 +7832,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
> @@ -7869,7 +7869,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
> @@ -8617,11 +8617,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])
> @@ -9348,7 +9348,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
> @@ -9377,16 +9377,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
> @@ -9711,7 +9711,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)
> @@ -10398,7 +10398,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])
> @@ -10490,7 +10490,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 6ae3470..cd19d41 100644
> --- a/tests/ovs-ofctl.at
> +++ b/tests/ovs-ofctl.at
> @@ -2999,7 +2999,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..7c1b551 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,14 @@ 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 coverage/show | grep "drop_action_unsupported_packet_type" | cut 
> -d':' -f2|sed 's/ //'
> +], [0], [dnl
> +2
>  ])
>  
>  # Encap(ethernet) on Ethernet frame -> should be droped
> @@ -587,7 +594,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 +616,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 +777,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 b840dbf..922ba48 100644
> --- a/tests/testsuite.at
> +++ b/tests/testsuite.at
> @@ -82,3 +82,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..385c114 100644
> --- a/tests/tunnel-push-pop.at
> +++ b/tests/tunnel-push-pop.at
> @@ -447,6 +447,27 @@ 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 netdev-dummy/receive p0 
> 'aa55aa550000001b213cab6408004500007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
> +
> +ovs-appctl time/warp 1200
> +
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "dp_tunnel_pop_error_drop" | cut -d':' 
> -f2|sed 's/ //'
> +], [0], [dnl
> +1
> +])
> +
> +
> +AT_CHECK([ovs-appctl netdev-dummy/receive p0 
> 'aa55aa550000001b213cab6408004503007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
> +ovs-appctl time/warp 1200
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "drop_action_congestion" | cut -d':' -f2|sed 
> 's/ //'
> +], [0], [dnl
> +1
> +])
> +
>  dnl Check GREL3 only accepts non-fragmented packets?
>  AT_CHECK([ovs-appctl netdev-dummy/receive p0 
> 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c0101025820000800000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
>  
> @@ -455,7 +476,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 +531,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 55fb1d3..3646c06 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 netdev-dummy/receive p2 
> 'aa55aa550001f8bc124434b6080045000054ba20000040018486010103580101037001004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637'])
> +sleep 2
> +
> +AT_CHECK([
> +ovs-appctl coverage/show | grep "dp_invalid_port_drop" | cut -d':' -f2|sed 
> 's/ //'
> +], [0], [dnl
> +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
> -- 
> 1.9.1
> 
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to