[ovs-dev] [PATCH v2] Improved Packet Drop Statistics in OVS
Raymond Burkholder
ray at oneunified.net
Thu Sep 6 14:18:07 UTC 2018
Looks interesting.
In the list of file changes, should there be a doc update for the new
commands, changes to existing output, as well as a news entry?
On 2018-09-06 8:01 a.m., Keshav Gupta wrote:
> 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. Have new cli command to display consolidated packet drop output
> 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
>
> In the subsequent commits plan to add the corresponding tests.
>
> Sample ovs-appctl dpcls/dump-flows & ovs-appctl dpif/dump-flows
> displaying drop reason along with drop action.
> ---------------------------------------------------------------
>
> $ 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
>
> Sample drop stats summary 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
>
> Sample detailed drop stats output.
> ---------------------------------
> $ 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 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
>
> Drop stats clear command.
> ---------------------------------
> $ ovs-appctl dpif/clear-drop-stats
> $ ovs-appctl dpif/show-drop-stats
> netdev:
> rx-drops :0
> dataplane-processing-drops :0
> drop action :0
> upcall drops :0
> dp error drops :0
> tx-drops :0
>
>
> Original author of this patch is Rohith Basavaraja <rohith.basavaraja at gmail.com>
> As our SMTP server does not allow him to put in From list putting him as co-author.
>
> Co-authored-by: Rohith Basavaraja <rohith.basavaraja at gmail.com>
> Co-authored-by: Anju Thomas <anju.thomas at ericsson.com>
> Signed-off-by: Rohith Basavaraja <rohith.basavaraja at gmail.com>
> Signed-off-by: Keshav Gupta <keshav.gupta at ericsson.com>
> Signed-off-by: Anju Thomas <anju.thomas at ericsson.com>
> ---
> datapath/linux/compat/include/linux/openvswitch.h | 51 ++++++
> lib/dpif-netdev-perf.c | 50 +++++
> lib/dpif-netdev-perf.h | 52 ++++++
> lib/dpif-netdev.c | 128 ++++++++++++-
> lib/dpif-netlink.c | 2 +
> lib/dpif-provider.h | 7 +
> lib/dpif.c | 191 ++++++++++++++++++-
> lib/dpif.h | 64 ++++++-
> lib/netdev-dpdk.c | 4 +
> lib/odp-execute.c | 50 ++++-
> lib/odp-execute.h | 9 +-
> lib/odp-util.c | 53 +++++-
> ofproto/ofproto-dpif-ipfix.c | 1 +
> ofproto/ofproto-dpif-sflow.c | 1 +
> ofproto/ofproto-dpif-upcall.c | 4 +-
> ofproto/ofproto-dpif-xlate.c | 64 +++++++
> ofproto/ofproto-dpif-xlate.h | 4 +
> ofproto/ofproto-dpif.c | 88 +++++++++
> ofproto/ofproto-dpif.h | 8 +-
> tests/automake.mk | 3 +-
> tests/bundle.at | 2 +-
> tests/classifier.at | 10 +-
> tests/dpif-netdev.at | 6 +
> tests/drop-stats.at | 212 ++++++++++++++++++++++
> tests/ofproto-dpif.at | 120 ++++++------
> tests/ovs-ofctl.at | 2 +-
> tests/packet-type-aware.at | 16 +-
> tests/testsuite.at | 1 +
> tests/tunnel-push-pop.at | 23 ++-
> tests/tunnel.at | 21 ++-
> 30 files changed, 1149 insertions(+), 98 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 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..9b3b9e4 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,29 @@ pmd_perf_stats_clear(struct pmd_perf_stats *s)
> }
> }
>
> +void
> +pmd_perf_drop_stats_clear(struct pmd_perf_stats *s)
> +{
> + int i;
> +
> + for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
> + atomic_read_relaxed(&s->drop_counters.n.rx_drops[i],
> + &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],
> + &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],
> + &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],
> + &s->drop_counters.zero.tx_drops[i]);
> + }
> +}
> +
> /* 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..3f6dfa9 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 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..bd8c9f5 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,48 @@ 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)";
> + 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 +1217,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 +2458,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-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..e1ce027 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 *);
>
> +uint32_t 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..258f32f 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,82 @@ 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 (int 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[],
> + 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 +5903,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 at 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 at 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 at 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 at 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 at 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
More information about the dev
mailing list