Hi. Have you missed my "inline" comments to v8: https://mail.openvswitch.org/pipermail/ovs-dev/2019-February/356153.html ?
Best regards, Ilya Maximets. On 27.02.2019 12:22, Anju Thomas 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. Identify and account all the silent packet drop scenarios > > 2. Display these drops in ovs-appctl coverage/show > > 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 > > Co-authored-by: Rohith Basavaraja <rohith.basavar...@gmail.com> > Co-authored-by: Keshav Gupta <keshugup...@gmail.com> > Signed-off-by: Anju Thomas <anju.tho...@ericsson.com> > Signed-off-by: Rohith Basavaraja <rohith.basavar...@gmail.com> > Signed-off-by: Keshav Gupta <keshugup...@gmail.com> > --- > datapath/linux/compat/include/linux/openvswitch.h | 1 + > lib/dpif-netdev.c | 44 ++++- > lib/dpif.c | 7 + > lib/dpif.h | 3 + > lib/odp-execute.c | 81 ++++++++- > lib/odp-util.c | 9 + > ofproto/ofproto-dpif-ipfix.c | 1 + > ofproto/ofproto-dpif-sflow.c | 1 + > ofproto/ofproto-dpif-xlate.c | 103 +++++++---- > ofproto/ofproto-dpif-xlate.h | 3 + > ofproto/ofproto-dpif.c | 8 + > ofproto/ofproto-dpif.h | 7 +- > tests/automake.mk | 3 +- > tests/dpif-netdev.at | 8 + > tests/drop-stats.at | 197 > ++++++++++++++++++++++ > tests/ofproto-dpif.at | 2 +- > tests/testsuite.at | 1 + > tests/tunnel-push-pop.at | 28 ++- > tests/tunnel.at | 14 +- > 19 files changed, 475 insertions(+), 46 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 d5aa09d..e77e9c8 100644 > --- a/datapath/linux/compat/include/linux/openvswitch.h > +++ b/datapath/linux/compat/include/linux/openvswitch.h > @@ -946,6 +946,7 @@ enum ovs_action_attr { > OVS_ACTION_ATTR_POP_NSH, /* No argument. */ > OVS_ACTION_ATTR_METER, /* u32 meter number. */ > OVS_ACTION_ATTR_CLONE, /* Nested OVS_CLONE_ATTR_*. */ > + OVS_ACTION_ATTR_DROP, /* Drop action. */ > > #ifndef __KERNEL__ > OVS_ACTION_ATTR_TUNNEL_PUSH, /* struct ovs_action_push_tnl*/ > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index 77ac1d2..acc7913 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -101,6 +101,17 @@ enum { MAX_METERS = 65536 }; /* Maximum number of > meters. */ > enum { MAX_BANDS = 8 }; /* Maximum number of bands / meter. */ > enum { N_METER_LOCKS = 64 }; /* Maximum number of meters. */ > > +COVERAGE_DEFINE(datapath_drop_meter); > +COVERAGE_DEFINE(datapath_drop_upcall_error); > +COVERAGE_DEFINE(datapath_drop_lock_error); > +COVERAGE_DEFINE(datapath_drop_userspace_action_error); > +COVERAGE_DEFINE(datapath_drop_tunnel_push_error); > +COVERAGE_DEFINE(datapath_drop_tunnel_pop_error); > +COVERAGE_DEFINE(datapath_drop_recirc_error); > +COVERAGE_DEFINE(datapath_drop_invalid_port); > +COVERAGE_DEFINE(datapath_drop_invalid_tnl_port); > +COVERAGE_DEFINE(datapath_drop_rx_invalid_packet); > + > /* Protects against changes to 'dp_netdevs'. */ > static struct ovs_mutex dp_netdev_mutex = OVS_MUTEX_INITIALIZER; > > @@ -5647,6 +5658,7 @@ dp_netdev_run_meter(struct dp_netdev *dp, struct > dp_packet_batch *packets_, > band->packet_count += 1; > band->byte_count += dp_packet_size(packet); > > + COVERAGE_INC(datapath_drop_meter); > dp_packet_delete(packet); > } else { > /* Meter accepts packet. */ > @@ -6402,6 +6414,7 @@ dfc_processing(struct dp_netdev_pmd_thread *pmd, > > if (OVS_UNLIKELY(dp_packet_size(packet) < ETH_HEADER_LEN)) { > dp_packet_delete(packet); > + COVERAGE_INC(datapath_drop_rx_invalid_packet); > continue; > } > > @@ -6528,6 +6541,7 @@ handle_packet_upcall(struct dp_netdev_pmd_thread *pmd, > put_actions); > if (OVS_UNLIKELY(error && error != ENOSPC)) { > dp_packet_delete(packet); > + COVERAGE_INC(datapath_drop_upcall_error); > return error; > } > > @@ -6659,6 +6673,7 @@ fast_path_processing(struct dp_netdev_pmd_thread *pmd, > DP_PACKET_BATCH_FOR_EACH (i, packet, packets_) { > if (OVS_UNLIKELY(!rules[i])) { > dp_packet_delete(packet); > + COVERAGE_INC(datapath_drop_lock_error); > upcall_fail_cnt++; > } > } > @@ -6928,6 +6943,7 @@ dp_execute_userspace_action(struct dp_netdev_pmd_thread > *pmd, > actions->data, actions->size); > } else if (should_steal) { > dp_packet_delete(packet); > + COVERAGE_INC(datapath_drop_userspace_action_error); > } > } > > @@ -6942,6 +6958,7 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > struct dp_netdev *dp = pmd->dp; > int type = nl_attr_type(a); > struct tx_port *p; > + uint32_t packet_count, packet_dropped; > > switch ((enum ovs_action_attr)type) { > case OVS_ACTION_ATTR_OUTPUT: > @@ -6983,6 +7000,9 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > dp_packet_batch_add(&p->output_pkts, packet); > } > return; > + } else { > + COVERAGE_ADD(datapath_drop_invalid_port, > + dp_packet_batch_size(packets_)); > } > break; > > @@ -6992,10 +7012,16 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > * the ownership of these packets. Thus, we can avoid performing > * the action, because the caller will not use the result anyway. > * Just break to free the batch. */ > + COVERAGE_ADD(datapath_drop_tunnel_push_error, > + dp_packet_batch_size(packets_)); > break; > } > dp_packet_batch_apply_cutlen(packets_); > - push_tnl_action(pmd, a, packets_); > + packet_count = dp_packet_batch_size(packets_); > + if (push_tnl_action(pmd, a, packets_)) { > + COVERAGE_ADD(datapath_drop_tunnel_push_error, > + packet_count); > + } > return; > > case OVS_ACTION_ATTR_TUNNEL_POP: > @@ -7015,7 +7041,13 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > dp_packet_batch_apply_cutlen(packets_); > > + packet_count = packets_->count; > netdev_pop_header(p->port->netdev, packets_); > + packet_dropped = packet_count - packets_->count; > + if (packet_dropped) { > + COVERAGE_ADD(datapath_drop_tunnel_pop_error, > + packet_dropped); > + } > if (dp_packet_batch_is_empty(packets_)) { > return; > } > @@ -7030,6 +7062,11 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > (*depth)--; > return; > } > + COVERAGE_ADD(datapath_drop_invalid_tnl_port, > + dp_packet_batch_size(packets_)); > + } else { > + COVERAGE_ADD(datapath_drop_recirc_error, > + dp_packet_batch_size(packets_)); > } > break; > > @@ -7074,6 +7111,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > > return; > } > + COVERAGE_ADD(datapath_drop_lock_error, > + dp_packet_batch_size(packets_)); > break; > > case OVS_ACTION_ATTR_RECIRC: > @@ -7097,6 +7136,8 @@ dp_execute_cb(void *aux_, struct dp_packet_batch > *packets_, > return; > } > > + COVERAGE_ADD(datapath_drop_recirc_error, > + dp_packet_batch_size(packets_)); > VLOG_WARN("Packet dropped. Max recirculation depth exceeded."); > break; > > @@ -7249,6 +7290,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(); > } > diff --git a/lib/dpif.c b/lib/dpif.c > index 457c9bf..d75a012 100644 > --- a/lib/dpif.c > +++ b/lib/dpif.c > @@ -1269,6 +1269,7 @@ dpif_execute_helper_cb(void *aux_, struct > dp_packet_batch *packets_, > case OVS_ACTION_ATTR_POP_NSH: > case OVS_ACTION_ATTR_CT_CLEAR: > case OVS_ACTION_ATTR_UNSPEC: > + case OVS_ACTION_ATTR_DROP: > case __OVS_ACTION_ATTR_MAX: > OVS_NOT_REACHED(); > } > @@ -1874,6 +1875,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, > diff --git a/lib/dpif.h b/lib/dpif.h > index 475d5a6..e799da8 100644 > --- a/lib/dpif.h > +++ b/lib/dpif.h > @@ -888,6 +888,9 @@ int dpif_get_pmds_for_port(const struct dpif * dpif, > odp_port_t port_no, > > char *dpif_get_dp_version(const struct dpif *); > bool dpif_supports_tnl_push_pop(const struct dpif *); > +bool dpif_supports_explicit_drop_action(const struct dpif *); > +int dpif_show_drop_stats_support(struct dpif *dpif, bool detail, > + struct ds *reply); > > /* Log functions. */ > struct vlog_module; > diff --git a/lib/odp-execute.c b/lib/odp-execute.c > index 5d07133..c8ff16b 100644 > --- a/lib/odp-execute.c > +++ b/lib/odp-execute.c > @@ -25,6 +25,7 @@ > #include <stdlib.h> > #include <string.h> > > +#include "coverage.h" > #include "dp-packet.h" > #include "dpif.h" > #include "netlink.h" > @@ -36,6 +37,74 @@ > #include "util.h" > #include "csum.h" > #include "conntrack.h" > +#include "ofproto/ofproto-dpif-xlate.h" > +#include "openvswitch/vlog.h" > + > +VLOG_DEFINE_THIS_MODULE(odp_execute) > +COVERAGE_DEFINE(dp_sample_error_drop); > +COVERAGE_DEFINE(dp_nsh_decap_error_drop); > +COVERAGE_DEFINE(drop_action_of_pipeline); > +COVERAGE_DEFINE(drop_action_bridge_not_found); > +COVERAGE_DEFINE(drop_action_recursion_too_deep); > +COVERAGE_DEFINE(drop_action_too_many_resubmit); > +COVERAGE_DEFINE(drop_action_stack_too_deep); > +COVERAGE_DEFINE(drop_action_no_recirculation_context); > +COVERAGE_DEFINE(drop_action_recirculation_conflict); > +COVERAGE_DEFINE(drop_action_too_many_mpls_labels); > +COVERAGE_DEFINE(drop_action_invalid_tunnel_metadata); > +COVERAGE_DEFINE(drop_action_unsupported_packet_type); > +COVERAGE_DEFINE(drop_action_congestion); > +COVERAGE_DEFINE(drop_action_forwarding_disabled); > + > +static void > +dp_update_drop_action_counter(enum xlate_error drop_reason, > + int delta) > +{ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + > + switch (drop_reason) { > + case XLATE_OK: > + COVERAGE_ADD(drop_action_of_pipeline, delta); > + break; > + case XLATE_BRIDGE_NOT_FOUND: > + COVERAGE_ADD(drop_action_bridge_not_found, delta); > + break; > + case XLATE_RECURSION_TOO_DEEP: > + COVERAGE_ADD(drop_action_recursion_too_deep, delta); > + break; > + case XLATE_TOO_MANY_RESUBMITS: > + COVERAGE_ADD(drop_action_too_many_resubmit, delta); > + break; > + case XLATE_STACK_TOO_DEEP: > + COVERAGE_ADD(drop_action_stack_too_deep, delta); > + break; > + case XLATE_NO_RECIRCULATION_CONTEXT: > + COVERAGE_ADD(drop_action_no_recirculation_context, delta); > + break; > + case XLATE_RECIRCULATION_CONFLICT: > + COVERAGE_ADD(drop_action_recirculation_conflict, delta); > + break; > + case XLATE_TOO_MANY_MPLS_LABELS: > + COVERAGE_ADD(drop_action_too_many_mpls_labels, delta); > + break; > + case XLATE_INVALID_TUNNEL_METADATA: > + COVERAGE_ADD(drop_action_invalid_tunnel_metadata, delta); > + break; > + case XLATE_UNSUPPORTED_PACKET_TYPE: > + COVERAGE_ADD(drop_action_unsupported_packet_type, delta); > + break; > + case XLATE_CONGESTION_DROP: > + COVERAGE_ADD(drop_action_congestion, delta); > + break; > + case XLATE_FORWARDING_DISABLED: > + COVERAGE_ADD(drop_action_forwarding_disabled, delta); > + break; > + case XLATE_MAX: > + default: > + VLOG_ERR_RL(&rl, "Invalid Drop reason type:%d", drop_reason); > + } > +} > + > > /* Masked copy of an ethernet address. 'src' is already properly masked. */ > static void > @@ -621,6 +690,7 @@ odp_execute_sample(void *dp, struct dp_packet *packet, > bool steal, > case OVS_SAMPLE_ATTR_PROBABILITY: > if (random_uint32() >= nl_attr_get_u32(a)) { > if (steal) { > + COVERAGE_ADD(dp_sample_error_drop, 1); > dp_packet_delete(packet); > } > return; > @@ -705,6 +775,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: > @@ -921,6 +992,7 @@ odp_execute_actions(void *dp, struct dp_packet_batch > *batch, bool steal, > if (pop_nsh(packet)) { > dp_packet_batch_refill(batch, packet, i); > } else { > + COVERAGE_INC(dp_nsh_decap_error_drop); > dp_packet_delete(packet); > } > } > @@ -931,7 +1003,14 @@ odp_execute_actions(void *dp, struct dp_packet_batch > *batch, bool steal, > conntrack_clear(packet); > } > break; > - > + case OVS_ACTION_ATTR_DROP: { > + const enum xlate_error *drop_reason = nl_attr_get(a); > + if (*drop_reason < XLATE_MAX) { > + dp_update_drop_action_counter(*drop_reason, batch->count); > + } > + dp_packet_delete_batch(batch, steal); > + return; > + } > case OVS_ACTION_ATTR_OUTPUT: > case OVS_ACTION_ATTR_TUNNEL_PUSH: > case OVS_ACTION_ATTR_TUNNEL_POP: > diff --git a/lib/odp-util.c b/lib/odp-util.c > index e893f46..9c3acc1 100644 > --- a/lib/odp-util.c > +++ b/lib/odp-util.c > @@ -43,6 +43,7 @@ > #include "uuid.h" > #include "openvswitch/vlog.h" > #include "openvswitch/match.h" > +#include "ofproto/ofproto-dpif-xlate.h" > > VLOG_DEFINE_THIS_MODULE(odp_util); > > @@ -131,6 +132,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(enum xlate_error); > > case OVS_ACTION_ATTR_UNSPEC: > case __OVS_ACTION_ATTR_MAX: > @@ -1182,6 +1184,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: > + ds_put_cstr(ds, "drop"); > + break; > case OVS_ACTION_ATTR_UNSPEC: > case __OVS_ACTION_ATTR_MAX: > default: > @@ -2428,8 +2433,12 @@ odp_actions_from_string(const char *s, const struct > simap *port_names, > struct ofpbuf *actions) > { > size_t old_size; > + enum xlate_error drop_action; > > if (!strcasecmp(s, "drop")) { > + drop_action = XLATE_OK; > + 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 5ea1097..52b328d 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 bc4ffee..0d0a27d 100644 > --- a/ofproto/ofproto-dpif-sflow.c > +++ b/ofproto/ofproto-dpif-sflow.c > @@ -1223,6 +1223,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-xlate.c b/ofproto/ofproto-dpif-xlate.c > index acd4817..95e2f25 100644 > --- a/ofproto/ofproto-dpif-xlate.c > +++ b/ofproto/ofproto-dpif-xlate.c > @@ -444,6 +444,12 @@ 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"; > + case XLATE_MAX: > + break; > } > return "Unknown error"; > } > @@ -5921,6 +5927,14 @@ put_ct_label(const struct flow *flow, struct ofpbuf > *odp_actions, > } > > static void > +put_drop_action(struct ofpbuf *odp_actions, enum xlate_error error) > +{ > + nl_msg_put_unspec(odp_actions, OVS_ACTION_ATTR_DROP, > + &error, sizeof error); > + > +} > + > +static void > put_ct_helper(struct xlate_ctx *ctx, > struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc) > { > @@ -7383,48 +7397,51 @@ xlate_actions(struct xlate_in *xin, struct xlate_out > *xout) > } > size_t sample_actions_len = ctx.odp_actions->size; > > - if (tnl_process_ecn(flow) > - && (!in_port || may_receive(in_port, &ctx))) { > - const struct ofpact *ofpacts; > - size_t ofpacts_len; > - > - if (xin->ofpacts) { > - ofpacts = xin->ofpacts; > - ofpacts_len = xin->ofpacts_len; > - } else if (ctx.rule) { > - const struct rule_actions *actions > - = rule_get_actions(&ctx.rule->up); > - ofpacts = actions->ofpacts; > - ofpacts_len = actions->ofpacts_len; > - ctx.rule_cookie = ctx.rule->up.flow_cookie; > - } else { > - OVS_NOT_REACHED(); > - } > + if (!tnl_process_ecn(flow)) { > + ctx.error = XLATE_CONGESTION_DROP; > + } else { > + if (!in_port || may_receive(in_port, &ctx)) { > + const struct ofpact *ofpacts; > + size_t ofpacts_len; > + > + if (xin->ofpacts) { > + ofpacts = xin->ofpacts; > + ofpacts_len = xin->ofpacts_len; > + } else if (ctx.rule) { > + const struct rule_actions *actions > + = rule_get_actions(&ctx.rule->up); > + ofpacts = actions->ofpacts; > + ofpacts_len = actions->ofpacts_len; > + ctx.rule_cookie = ctx.rule->up.flow_cookie; > + } else { > + OVS_NOT_REACHED(); > + } > > - mirror_ingress_packet(&ctx); > - do_xlate_actions(ofpacts, ofpacts_len, &ctx, true, false); > - if (ctx.error) { > - goto exit; > - } > + mirror_ingress_packet(&ctx); > + do_xlate_actions(ofpacts, ofpacts_len, &ctx, true, false); > + if (ctx.error) { > + goto exit; > + } > > - /* We've let OFPP_NORMAL and the learning action look at the > - * packet, so cancel all actions and freezing if forwarding is > - * disabled. */ > - if (in_port && (!xport_stp_forward_state(in_port) || > - !xport_rstp_forward_state(in_port))) { > - ctx.odp_actions->size = sample_actions_len; > - ctx_cancel_freeze(&ctx); > - ofpbuf_clear(&ctx.action_set); > - } > + /* We've let OFPP_NORMAL and the learning action look at the > + * packet, so cancel all actions and freezing if forwarding is > + * disabled. */ > + if (in_port && (!xport_stp_forward_state(in_port) || > + !xport_rstp_forward_state(in_port))) { > + ctx.odp_actions->size = sample_actions_len; > + ctx_cancel_freeze(&ctx); > + ofpbuf_clear(&ctx.action_set); > + ctx.error = XLATE_FORWARDING_DISABLED; > + } > > - if (!ctx.freezing) { > - xlate_action_set(&ctx); > - } > - if (ctx.freezing) { > - finish_freezing(&ctx); > + if (!ctx.freezing) { > + xlate_action_set(&ctx); > + } > + if (ctx.freezing) { > + finish_freezing(&ctx); > + } > } > } > - > /* Output only fully processed packets. */ > if (!ctx.freezing > && xbridge->has_in_band > @@ -7522,6 +7539,18 @@ exit: > ofpbuf_clear(xin->odp_actions); > } > } > + > + /* > + * If we are going to install "drop" action, check whether > + * datapath supports explicit "drop"action. If datapath > + * supports explicit "drop"action then install the "drop" > + * action containing the drop reason. > + */ > + if (xin->odp_actions && !xin->odp_actions->size && > + ovs_explicit_drop_action_supported(ctx.xbridge->ofproto)) { > + put_drop_action(xin->odp_actions, ctx.error); > + } > + > return ctx.error; > } > > diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h > index 0a5a528..496bdbf 100644 > --- a/ofproto/ofproto-dpif-xlate.h > +++ b/ofproto/ofproto-dpif-xlate.h > @@ -216,6 +216,9 @@ enum xlate_error { > XLATE_TOO_MANY_MPLS_LABELS, > XLATE_INVALID_TUNNEL_METADATA, > XLATE_UNSUPPORTED_PACKET_TYPE, > + XLATE_CONGESTION_DROP, > + XLATE_FORWARDING_DISABLED, > + XLATE_MAX, > }; > > const char *xlate_strerror(enum xlate_error error); > diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c > index 50c959b..91df1b3 100644 > --- a/ofproto/ofproto-dpif.c > +++ b/ofproto/ofproto-dpif.c > @@ -827,6 +827,12 @@ ovs_native_tunneling_is_on(struct ofproto_dpif *ofproto) > && atomic_count_get(&ofproto->backer->tnl_count); > } > > +bool > +ovs_explicit_drop_action_supported(struct ofproto_dpif *ofproto) > +{ > + return ofproto->backer->rt_support.explicit_drop_action; > +} > + > /* Tests whether 'backer''s datapath supports recirculation. Only newer > * datapaths support OVS_KEY_ATTR_RECIRC_ID in keys. We need to disable some > * features on older datapaths that don't support this feature. > @@ -1397,6 +1403,8 @@ check_support(struct dpif_backer *backer) > backer->rt_support.ct_eventmask = check_ct_eventmask(backer); > backer->rt_support.ct_clear = check_ct_clear(backer); > backer->rt_support.max_hash_alg = check_max_dp_hash_alg(backer); > + backer->rt_support.explicit_drop_action = > + dpif_supports_explicit_drop_action(backer->dpif); > > /* Flow fields. */ > backer->rt_support.odp.ct_state = check_ct_state(backer); > diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h > index 1a404c8..8d8edca 100644 > --- a/ofproto/ofproto-dpif.h > +++ b/ofproto/ofproto-dpif.h > @@ -192,7 +192,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 +364,6 @@ int ofproto_dpif_delete_internal_flow(struct ofproto_dpif > *, struct match *, > > bool ovs_native_tunneling_is_on(struct ofproto_dpif *); > > +bool ovs_explicit_drop_action_supported(struct ofproto_dpif *); > + > #endif /* ofproto-dpif.h */ > diff --git a/tests/automake.mk b/tests/automake.mk > index 92d56b2..a4da75e 100644 > --- a/tests/automake.mk > +++ b/tests/automake.mk > @@ -108,7 +108,8 @@ TESTSUITE_AT = \ > tests/ovn-controller-vtep.at \ > tests/mcast-snooping.at \ > tests/packet-type-aware.at \ > - tests/nsh.at > + tests/nsh.at \ > + tests/drop-stats.at > > EXTRA_DIST += $(FUZZ_REGRESSION_TESTS) > FUZZ_REGRESSION_TESTS = \ > diff --git a/tests/dpif-netdev.at b/tests/dpif-netdev.at > index 6915d43..5221c10 100644 > --- a/tests/dpif-netdev.at > +++ b/tests/dpif-netdev.at > @@ -337,6 +337,14 @@ meter:2 flow_count:1 packet_in_count:10 > byte_in_count:600 duration:0.0s bands: > 0: packet_count:5 byte_count:300 > ]) > > +ovs-appctl time/warp 5000 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "datapath_drop_meter" | cut -d':' -f2|sed > 's/ //' > +], [0], [dnl > +14 > +]) > + > AT_CHECK([cat ovs-vswitchd.log | filter_flow_install | > strip_xout_keep_actions], [0], [dnl > > recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), > actions:meter(0),7 > > recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), > actions:8 > diff --git a/tests/drop-stats.at b/tests/drop-stats.at > new file mode 100644 > index 0000000..318bc02 > --- /dev/null > +++ b/tests/drop-stats.at > @@ -0,0 +1,197 @@ > +AT_BANNER([drop-stats]) > + > +AT_SETUP([drop-stats - cli tests]) > + > +OVS_VSWITCHD_START([dnl > + set bridge br0 datapath_type=dummy \ > + protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \ > + add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1]) > + > +AT_DATA([flows.txt], [dnl > +table=0,in_port=1,actions=drop > +]) > + > +AT_CHECK([ > + ovs-ofctl del-flows br0 > + ovs-ofctl -Oopenflow13 add-flows br0 flows.txt > + ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions > +], [0], [dnl > + in_port=1 actions=drop > +]) > + > +AT_CHECK([ > + ovs-appctl netdev-dummy/receive p1 > 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 > + ovs-appctl netdev-dummy/receive p1 > 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 > + ovs-appctl netdev-dummy/receive p1 > 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 > +], [0], [ignore]) > + > +AT_CHECK([ovs-appctl dpctl/dump-flows | sed > 's/used:[[0-9]].[[0-9]]*s/used:0.0/' | sort], [0], > +[flow-dump from non-dpdk interfaces: > +recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), > packets:2, bytes:196, used:0.0, actions:drop > +]) > + > +sleep 1 > + > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "drop_action_of_pipeline" | cut -d':' > -f2|sed 's/ //' > +], [0], [dnl > +3 > +]) > + > + > +OVS_VSWITCHD_STOP > +AT_CLEANUP > + > +AT_SETUP([drop-stats - pipeline and recurssion drops]) > + > +OVS_VSWITCHD_START([dnl > + set bridge br0 datapath_type=dummy \ > + protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \ > + add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \ > + add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) > + > +AT_DATA([flows.txt], [dnl > +table=0,in_port=1,actions=drop > +]) > + > +AT_CHECK([ > + ovs-ofctl del-flows br0 > + ovs-ofctl -Oopenflow13 add-flows br0 flows.txt > + ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions > +], [0], [dnl > + in_port=1 actions=drop > +]) > + > +AT_CHECK([ > + ovs-appctl netdev-dummy/receive p1 > 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 > +], [0], [ignore]) > + > +sleep 1 > + > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "drop_action_of_pipeline" | cut -d':' > -f2|sed 's/ //' > +], [0], [dnl > +1 > +]) > + > + > +AT_DATA([flows.txt], [dnl > +table=0, in_port=1, actions=goto_table:1 > +table=1, in_port=1, actions=goto_table:2 > +table=2, in_port=1, actions=resubmit(,1) > +]) > + > +AT_CHECK([ > + ovs-ofctl del-flows br0 > + ovs-ofctl -Oopenflow13 add-flows br0 flows.txt > + ovs-ofctl -Oopenflow13 dump-flows br0 | ofctl_strip | sort | grep actions > +], [0], [ignore]) > + > +AT_CHECK([ > + ovs-appctl netdev-dummy/receive p1 > 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 > +], [0], [ignore]) > + > +sleep 1 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "drop_action_recursion_too_deep" | cut -d':' > -f2|sed 's/ //' > +], [0], [dnl > +1 > +]) > + > + > +OVS_VSWITCHD_STOP(["/|WARN|/d"]) > +AT_CLEANUP > + > +AT_SETUP([drop-stats - too many resubmit]) > + > +OVS_VSWITCHD_START > +add_of_ports br0 1 > +(for i in `seq 1 64`; do > + j=`expr $i + 1` > + echo "in_port=$i, actions=resubmit:$j, resubmit:$j, local" > + done > + echo "in_port=65, actions=local") > flows.txt > + > +AT_CHECK([ > + ovs-ofctl del-flows br0 > + ovs-ofctl -Oopenflow13 add-flows br0 flows.txt > +], [0], [ignore]) > + > +ovs-appctl netdev-dummy/receive p1 > 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x1234)' > + > +sleep 1 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "drop_action_too_many_resubmit" | cut -d':' > -f2|sed 's/ //' > +], [0], [dnl > +1 > +]) > + > +OVS_VSWITCHD_STOP(["/|WARN|/d"]) > +AT_CLEANUP > + > + > +AT_SETUP([drop-stats - stack too deep]) > +OVS_VSWITCHD_START > +add_of_ports br0 1 > +(for i in `seq 1 12`; do > + j=`expr $i + 1` > + echo "in_port=$i, actions=resubmit:$j, resubmit:$j, local" > + done > + push="push:NXM_NX_REG0[[]]" > + echo "in_port=13, actions=$push,$push,$push,$push,$push,$push,$push,$push") > > flows > + AT_CHECK([ovs-ofctl add-flows br0 flows]) > + > +ovs-appctl netdev-dummy/receive p1 > 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x1234)' > + > +sleep 1 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "drop_action_stack_too_deep" | cut -d':' > -f2|sed 's/ //' > +], [0], [dnl > +1 > +]) > + > + > +OVS_VSWITCHD_STOP(["/resubmits yielded over 64 kB of stack/d"]) > +AT_CLEANUP > + > +AT_SETUP([drop-stats - too many mpls labels]) > + > +OVS_VSWITCHD_START([dnl > + set bridge br0 datapath_type=dummy \ > + protocols=OpenFlow10,OpenFlow13,OpenFlow14,OpenFlow15 -- \ > + add-port br0 p1 -- set Interface p1 type=dummy ofport_request=1 -- \ > + add-port br0 p2 -- set Interface p2 type=dummy ofport_request=2]) > + > +AT_DATA([flows.txt], [dnl > +table=0, in_port=1, actions=push_mpls:0x8847, resubmit:3 > +table=0, in_port=3, actions=push_mpls:0x8847, set_field:10->mpls_label, > set_field:15->mpls_label, resubmit:4 > +table=0, in_port=4, actions=push_mpls:0x8847, set_field:11->mpls_label, > resubmit:5 > +table=0, in_port=5, actions=push_mpls:0x8847, set_field:12->mpls_label, > resubmit:6 > +table=0, in_port=6, actions=push_mpls:0x8847, set_field:13->mpls_label, > output:2 > +]) > + > +AT_CHECK([ > + ovs-ofctl del-flows br0 > + ovs-ofctl -Oopenflow13 add-flows br0 flows.txt > +]) > + > +AT_CHECK([ > + ovs-appctl netdev-dummy/receive p1 > 1e2ce92a669e3a6dd2099cab0800450000548a53400040011addc0a80a0ac0a80a1e08006f200a4d0001fc509a58000000002715020000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637 > +], [0], [ignore]) > + > +sleep 1 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "drop_action_too_many_mpls_labels" | cut > -d':' -f2|sed 's/ //' > +], [0], [dnl > +1 > +]) > + > + > +OVS_VSWITCHD_STOP(["/|WARN|/d"]) > +AT_CLEANUP > diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at > index ded2ef0..2c8cdce 100644 > --- a/tests/ofproto-dpif.at > +++ b/tests/ofproto-dpif.at > @@ -9384,7 +9384,7 @@ > recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp= > # are wildcarded. > AT_CHECK([grep '\(modify\)\|\(flow_add\)' ovs-vswitchd.log | strip_ufid ], > [0], [dnl > dpif_netdev|DBG|flow_add: > recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), actions:100 > -dpif|DBG|dummy@ovs-dummy: put[[modify]] > skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234) > +dpif|DBG|dummy@ovs-dummy: put[[modify]] > skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), > actions:drop > dpif|DBG|dummy@ovs-dummy: put[[modify]] > skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), > actions:100 > dpif_netdev|DBG|flow_add: > recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), > actions:drop > ]) > diff --git a/tests/testsuite.at b/tests/testsuite.at > index b840dbf..922ba48 100644 > --- a/tests/testsuite.at > +++ b/tests/testsuite.at > @@ -82,3 +82,4 @@ m4_include([tests/ovn-controller-vtep.at]) > m4_include([tests/mcast-snooping.at]) > m4_include([tests/packet-type-aware.at]) > m4_include([tests/nsh.at]) > +m4_include([tests/drop-stats.at]) > diff --git a/tests/tunnel-push-pop.at b/tests/tunnel-push-pop.at > index f717243..045b1a7 100644 > --- a/tests/tunnel-push-pop.at > +++ b/tests/tunnel-push-pop.at > @@ -447,6 +447,27 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 7'], > [0], [dnl > port 7: rx pkts=3, bytes=252, drop=?, errs=?, frame=?, over=?, crc=? > ]) > > +AT_CHECK([ovs-appctl netdev-dummy/receive p0 > 'aa55aa550000001b213cab6408004500007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) > + > +ovs-appctl time/warp 5000 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "datapath_drop_tunnel_pop_error" | cut -d':' > -f2|sed 's/ //' > +], [0], [dnl > +1 > +]) > + > +sleep 1 > +AT_CHECK([ovs-appctl netdev-dummy/receive p0 > 'aa55aa550000001b213cab6408004503007079464000402fba600101025c0101025820000800000001c845000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) > + > +ovs-appctl time/warp 5000 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "drop_action_congestion" | cut -d':' -f2|sed > 's/ //' > +], [0], [dnl > +1 > +]) > + > dnl Check GREL3 only accepts non-fragmented packets? > AT_CHECK([ovs-appctl netdev-dummy/receive p0 > 'aa55aa550000001b213cab6408004500007e79464000402fba550101025c0101025820000800000001c8fe71d883724fbeb6f4e1494a080045000054ba200000400184861e0000011e00000200004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) > > @@ -455,7 +476,7 @@ ovs-appctl time/warp 1000 > > AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port [[37]]' | sort], [0], > [dnl > port 3: rx pkts=3, bytes=294, drop=?, errs=?, frame=?, over=?, crc=? > - port 7: rx pkts=4, bytes=350, drop=?, errs=?, frame=?, over=?, crc=? > + port 7: rx pkts=5, bytes=434, drop=?, errs=?, frame=?, over=?, crc=? > ]) > > dnl Check decapsulation of Geneve packet with options > @@ -478,7 +499,7 @@ AT_CHECK([ovs-ofctl dump-ports int-br | grep 'port 5'], > [0], [dnl > port 5: rx pkts=1, bytes=98, drop=?, errs=?, frame=?, over=?, crc=? > ]) > AT_CHECK([ovs-appctl dpif/dump-flows int-br | grep 'in_port(6081)'], [0], > [dnl > -tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), > packets:0, bytes:0, used:never, > actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=3,rule_cookie=0,controller_id=0,max_len=65535)) > +tunnel(tun_id=0x7b,src=1.1.2.92,dst=1.1.2.88,geneve({class=0xffff,type=0x80,len=4,0xa/0xf}{class=0xffff,type=0,len=4}),flags(-df-csum+key)),recirc_id(0),in_port(6081),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), > packets:0, bytes:0, used:never, > actions:userspace(pid=0,controller(reason=1,dont_send=0,continuation=0,recirc_id=2,rule_cookie=0,controller_id=0,max_len=65535)) > ]) > > ovs-appctl time/warp 10000 > @@ -510,7 +531,8 @@ AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl > Listening ports: > ]) > > -OVS_VSWITCHD_STOP > +OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN > capable/d > +/ip packet has invalid checksum/d"]) > AT_CLEANUP > > AT_SETUP([tunnel_push_pop - packet_out]) > diff --git a/tests/tunnel.at b/tests/tunnel.at > index 55fb1d3..7bd5b48 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 > +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,16 @@ AT_CHECK([ovs-appctl ofproto/trace ovs-dummy > 'in_port(2),eth(src=50:54:00:00:00: > AT_CHECK([tail -1 stdout], [0], > [Datapath actions: > set(tunnel(tun_id=0x5,src=2.2.2.2,dst=1.1.1.1,ttl=64,flags(df|key))),set(skb_mark(0x2)),1 > ]) > + > +AT_CHECK([ovs-appctl netdev-dummy/receive p2 > 'aa55aa550001f8bc124434b6080045000054ba20000040018486010103580101037001004227e75400030af3195500000000f265010000000000101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637']) > + > +sleep 2 > + > +AT_CHECK([ > +ovs-appctl coverage/show | grep "datapath_drop_invalid_port" | cut -d':' > -f2|sed 's/ //' > +], [0], [dnl > +1 > +]) > OVS_VSWITCHD_STOP > AT_CLEANUP > > _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev