@@ -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*/
@@ -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
@@ -33,6 +33,7 @@
#include "timeval.h"
#include "unixctl.h"
#include "util.h"
+#include "dpif.h"
#ifdef __cplusplus
extern "C" {
@@ -91,6 +92,28 @@ struct pmd_counters {
uint64_t zero[PMD_N_STATS]; /* Value at last _clear(). */
};
+/* Drop statistics maintained at per PMD level.*/
+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];
+};
+
+/* Clear Drop statistics reference value maintained at per PMD level.*/
+struct pmd_drop_zero_stats {
+ 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 tx_drops[DPIF_TX_MAX_DROP];
+};
+
+struct pmd_drop_counters {
+ struct pmd_drop_stats n; /* Value since _init(). */
+ struct pmd_drop_zero_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 +183,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 +302,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 +429,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
@@ -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,
@@ -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 */
@@ -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.
*
@@ -538,6 +538,38 @@ dpif_get_dp_stats(const struct dpif *dpif, struct dpif_dp_stats *stats)
return error;
}
+/* Retrieves drop statistics for 'dpif' into 'drop_stats'. Returns 0
+ * if successful, otherwise a positive errno value. */
+int
+dpif_get_dp_drop_stats(const struct dpif *dpif,
+ struct dpif_dp_drop_stats *drop_stats)
+{
+ int error = 0;
+ if (dpif->dpif_class->get_drop_stats) {
+ error = dpif->dpif_class->get_drop_stats(dpif, drop_stats);
+ if (error) {
+ memset(drop_stats, 0, sizeof *drop_stats);
+ }
+ log_operation(dpif, "get_drop_stats", error);
+ } else {
+ log_operation(dpif, "get_drop_stats not supported", error);
+ }
+ return error;
+}
+
+/* Clears drop statistics in 'dpif' into 'drop_stats'. */
+int
+dpif_clear_dp_drop_stats(const struct dpif *dpif)
+{
+ int error = 0;
+ if (dpif->dpif_class->clear_drop_stats) {
+ error = dpif->dpif_class->clear_drop_stats(dpif);
+ } else {
+ log_operation(dpif, "clear_drop_stats not supported", error);
+ }
+ return error;
+}
+
const char *
dpif_port_open_type(const char *datapath_type, const char *port_type)
{
@@ -1280,6 +1312,7 @@ dpif_execute_helper_cb(void *aux_, struct dp_packet_batch *packets_,
case OVS_ACTION_ATTR_PUSH_NSH:
case OVS_ACTION_ATTR_POP_NSH:
case OVS_ACTION_ATTR_CT_CLEAR:
+ case OVS_ACTION_ATTR_DROP:
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
OVS_NOT_REACHED();
@@ -1302,7 +1335,7 @@ dpif_execute_with_help(struct dpif *dpif, struct dpif_execute *execute)
dp_packet_batch_init_packet(&pb, execute->packet);
odp_execute_actions(&aux, &pb, false, execute->actions,
- execute->actions_len, dpif_execute_helper_cb);
+ execute->actions_len, dpif_execute_helper_cb, NULL);
return aux.error;
}
@@ -1875,6 +1908,12 @@ dpif_supports_tnl_push_pop(const struct dpif *dpif)
return dpif_is_netdev(dpif);
}
+bool
+dpif_supports_explicit_drop_action(const struct dpif *dpif)
+{
+ return dpif_is_netdev(dpif);
+}
+
/* Meters */
void
dpif_meter_get_features(const struct dpif *dpif,
@@ -1972,3 +2011,153 @@ dpif_meter_del(struct dpif *dpif, ofproto_meter_id meter_id,
}
return error;
}
+
+static void
+dpif_show_drop_stats(struct ds *reply,
+ struct dpif_dp_drop_stats *drop_stats)
+{
+ uint64_t rx_drops,tx_drops,dp_drops,drop_action_drops;
+ int i;
+
+ rx_drops = 0;
+ tx_drops = 0;
+ dp_drops = 0;
+ drop_action_drops = 0;
+ for (i = 0; i < DPIF_RX_MAX_DROP; i++) {
+ rx_drops += drop_stats->rx_drops[i];
+ }
+ for (i = 0; i < OVS_DROP_REASON_MAX; i++) {
+ drop_action_drops += drop_stats->drop_action_drops[i];
+ }
+ for (i = 0; i < DPIF_DP_MAX_DROP; i++) {
+ dp_drops += drop_stats->dp_drops[i];
+ }
+ for (i = 0; i < DPIF_TX_MAX_DROP; i++) {
+ tx_drops += drop_stats->tx_drops[i];
+ }
+ dp_drops += drop_action_drops;
+ rx_drops += drop_stats->iface_rx_drops;
+ tx_drops += drop_stats->iface_tx_drops;
+
+ ds_put_format(reply, "%-28s: %-12"PRIu64"\n", "rx-drops", rx_drops);
+ ds_put_format(reply, "%-28s: %-12"PRIu64"\n",
+ "dataplane-processing-drops", dp_drops);
+ ds_put_format(reply, " %-23s: %-12"PRIu64"\n", "drop action",
+ drop_action_drops);
+ ds_put_format(reply, " %-23s: %-12"PRIu64"\n", "upcall drops",
+ drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP] +
+ drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+ ds_put_format(reply, " %-23s: %-12"PRIu64"\n", "dp error drops",
+ dp_drops -
+ drop_action_drops -
+ drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP] -
+ drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+ ds_put_format(reply, "%-28s: %-12"PRIu64"\n", "tx-drops",
+ tx_drops);
+}
+
+static void
+dpif_show_drop_stats_detail(struct ds *reply,
+ struct dpif_dp_drop_stats *drop_stats)
+{
+ uint32_t idx = 0;
+ ds_put_format(reply, "rx-drops: \n");
+ ds_put_format(reply, "%-7s %-38s %-12s\n", "[IDX]", "Drop Reason",
+ "Packets");
+ ds_put_format(reply, "------- ------------------------------------- "
+ "------------\n");
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "interface & policer", drop_stats->iface_rx_drops);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "parsing error/invalid packet",
+ drop_stats->rx_drops[DPIF_RX_INVALID_PACKET_DROP]);
+ ds_put_format(reply, "dataplane-processing-drops: \n");
+ ds_put_format(reply, "\"drop\" action:\n");
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "pipeline drop",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_OF_PIPELINE]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "bridge not found",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_BRIDGE_NOT_FOUND]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "recursion too deep",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_RECURSION_TOO_DEEP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "too many resubmits",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_TOO_MANY_RESUBMITS]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "stack too deep",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_STACK_TOO_DEEP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "no recirculation context",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "recirculation conflict",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_RECIRCULATION_CONFLICT]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "too many mpls labels",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_TOO_MANY_MPLS_LABELS]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "invalid tunnel metadata",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_INVALID_TUNNEL_METADATA]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "unsupported packet type",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "ecn mismatch at tunnel decapsulation",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_CONGESTION]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "forwarding disabled (stp/rstp)",
+ drop_stats->drop_action_drops[OVS_DROP_REASON_FORWARDING_DISABLED]);
+ ds_put_format(reply, "upcall drops:\n");
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "upcall lock contention drop",
+ drop_stats->dp_drops[DPIF_DP_UPCALL_LOCK_ERROR_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "upcall error drops",
+ drop_stats->dp_drops[DPIF_DP_UPCALL_ERROR_DROP]);
+ ds_put_format(reply, "dp error drops:\n");
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "tunnel pop action errors",
+ drop_stats->dp_drops[DPIF_DP_TUNNEL_POP_ERROR_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "tunnel push action errors",
+ drop_stats->dp_drops[DPIF_DP_TUNNEL_PUSH_ERROR_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "nsh decap errors",
+ drop_stats->dp_drops[DPIF_DP_NSH_DECAP_ERROR_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "recirculation errors",
+ drop_stats->dp_drops[DPIF_DP_RECIRC_ERROR_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "sampling error",
+ drop_stats->dp_drops[DPIF_DP_SAMPLE_ERROR_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "meter drop",
+ drop_stats->dp_drops[DPIF_DP_METER_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "user space action error",
+ drop_stats->dp_drops[DPIF_DP_USER_SPACE_ACTION_ERROR_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++, "invalid port",
+ drop_stats->dp_drops[DPIF_DP_INVALID_PORT_DROP]);
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "invalid tunnel port",
+ drop_stats->dp_drops[DPIF_DP_INVALID_TNL_PORT_DROP]);
+ ds_put_format(reply, "tx-drops: \n");
+ ds_put_format(reply, "%-7d %-38s %-12"PRIu64"\n", idx++,
+ "interface & policer", drop_stats->iface_tx_drops);
+}
+
+int
+dpif_show_drop_stats_support(struct dpif *dpif, bool detail, struct ds *reply)
+{
+ struct dpif_dp_drop_stats drop_stats;
+ int error = 0;
+ error = dpif_get_dp_drop_stats(dpif, &drop_stats);
+ if (error) {
+ return error;
+ }
+ if (detail) {
+ dpif_show_drop_stats_detail(reply, &drop_stats);
+ } else {
+ dpif_show_drop_stats(reply, &drop_stats);
+ }
+ return 0;
+}
@@ -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;
@@ -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;
}
@@ -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:
@@ -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
@@ -124,6 +124,7 @@ odp_action_len(uint16_t type)
case OVS_ACTION_ATTR_CLONE: return ATTR_LEN_VARIABLE;
case OVS_ACTION_ATTR_PUSH_NSH: return ATTR_LEN_VARIABLE;
case OVS_ACTION_ATTR_POP_NSH: return 0;
+ case OVS_ACTION_ATTR_DROP: return sizeof(struct ovs_action_drop);
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
@@ -338,6 +339,49 @@ format_nsh_key_mask(struct ds *ds, const struct ovs_key_nsh *key,
}
}
+static const char *
+dropreason_str(enum ovs_drop_reason reason)
+{
+ switch (reason) {
+ case OVS_DROP_REASON_OF_PIPELINE:
+ return "pipeline-drop";
+ case OVS_DROP_REASON_BRIDGE_NOT_FOUND:
+ return "bridge not found";
+ case OVS_DROP_REASON_RECURSION_TOO_DEEP:
+ return "recursion too deep";
+ case OVS_DROP_REASON_TOO_MANY_RESUBMITS:
+ return "too many resubmits";
+ case OVS_DROP_REASON_STACK_TOO_DEEP:
+ return "stack too deep";
+ case OVS_DROP_REASON_NO_RECIRCULATION_CONTEXT:
+ return "no recirculation context";
+ case OVS_DROP_REASON_RECIRCULATION_CONFLICT:
+ return "recirculation conflict";
+ case OVS_DROP_REASON_TOO_MANY_MPLS_LABELS:
+ return "too many mpls labels";
+ case OVS_DROP_REASON_INVALID_TUNNEL_METADATA:
+ return "invalid tunnel metadata";
+ case OVS_DROP_REASON_UNSUPPORTED_PACKET_TYPE:
+ return "unsupported packet type";
+ case OVS_DROP_REASON_CONGESTION:
+ return "ecn mismatch at tunnel decapsulation";
+ case OVS_DROP_REASON_FORWARDING_DISABLED:
+ return "forwarding disabled (stp/rstp)";
+ case OVS_DROP_REASON_MAX:
+ default:
+ return "unknown reason";
+ }
+ return "unknown reason";
+}
+
+static void
+format_odp_drop_action(struct ds *ds,
+ const struct ovs_action_drop *drop_action)
+{
+ ds_put_format(ds, "drop:%s",
+ dropreason_str(drop_action->drop_reason));
+}
+
static void
format_odp_push_nsh_action(struct ds *ds,
const struct nsh_hdr *nsh_hdr)
@@ -1174,6 +1218,9 @@ format_odp_action(struct ds *ds, const struct nlattr *a,
case OVS_ACTION_ATTR_POP_NSH:
ds_put_cstr(ds, "pop_nsh()");
break;
+ case OVS_ACTION_ATTR_DROP:
+ format_odp_drop_action(ds, nl_attr_get(a));
+ break;
case OVS_ACTION_ATTR_UNSPEC:
case __OVS_ACTION_ATTR_MAX:
default:
@@ -2412,8 +2459,13 @@ odp_actions_from_string(const char *s, const struct simap *port_names,
struct ofpbuf *actions)
{
size_t old_size;
+ struct ovs_action_drop drop_action;
- if (!strcasecmp(s, "drop")) {
+ if ((!strcasecmp(s, "drop") ||
+ !strcasecmp(s, "drop:pipeline-drop"))) {
+ drop_action.drop_reason = OVS_DROP_REASON_OF_PIPELINE;
+ nl_msg_put_unspec(actions, OVS_ACTION_ATTR_DROP,
+ &drop_action, sizeof drop_action);
return 0;
}
@@ -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;
@@ -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;
@@ -32,3 +32,62 @@ underlying datapath implementation (e.g., kernel datapath module).
This command is primarily useful for debugging Open vSwitch. As
discussed in \fBdpif/dump\-flows\fR, these entries are
not OpenFlow flow entries.
+.IP "\fBdpif/show\-drop\-stats\fR [\fB\--detail\fR]"
+Prints the dataplane drops for Open vSwitch datapath.
+With [\fB\--detail\fR], it shows the detailed classified drop.
+
+This command is primarily useful for debugging dataplane drops.
+It helps in indentifying the reason of packet drop.
+.IP
+[currently supported for netdev datapath only]
+
+ Sample output:
+ $ovs-appctl dpif/show-drop-stats
+ netdev:
+ rx-drops : 0
+ dataplane-processing-drops : 59
+ drop action : 59
+ upcall drops : 0
+ dp error drops : 0
+ tx-drops : 0
+ $ovs-appctl dpif/show-drop-stats --detail
+ netdev:
+ rx-drops:
+ [IDX] Drop Reason Packets
+ ------- ------------------------------------- ------------
+ 0 interface & policer 0
+ 1 parsing error/invalid packet 0
+ dataplane-processing-drops:
+ "drop" action:
+ 2 pipeline drop 0
+ 3 bridge not found 0
+ 4 recursion too deep 68
+ 5 too many resubmits 0
+ 6 stack too deep 0
+ 7 no recirculation context 0
+ 8 recirculation conflict 0
+ 9 too many mpls labels 0
+ 10 invalid tunnel metadata 0
+ 11 unsupported packet type 0
+ 12 ecn mismatch at tunnel decapsulation 0
+ 13 forwarding disabled (stp/rstp) 0
+ upcall drops:
+ 14 upcall lock contention drop 0
+ 15 upcall error drops 0
+ dp error drops:
+ 16 tunnel pop action errors 0
+ 17 tunnel push action errors 0
+ 18 nsh decap errors 0
+ 19 recirculation errors 0
+ 20 sampling error 0
+ 21 meter drop 0
+ 22 user space action error 0
+ 23 invalid port 0
+ 24 invalid tunnel port 0
+ tx-drops:
+ 25 interface & policer 0
+
+.IP "\fBdpif/clear\-drop\-stats\fR"
+Clears the drop stats displayed in dpif/show-drop-stats command.
+.IP
+[currently supported for netdev datapath only]
@@ -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;
}
@@ -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;
}
@@ -216,12 +216,16 @@ enum xlate_error {
XLATE_TOO_MANY_MPLS_LABELS,
XLATE_INVALID_TUNNEL_METADATA,
XLATE_UNSUPPORTED_PACKET_TYPE,
+ XLATE_CONGESTION_DROP,
+ XLATE_FORWARDING_DISABLED,
};
const char *xlate_strerror(enum xlate_error error);
enum xlate_error xlate_actions(struct xlate_in *, struct xlate_out *);
+enum ovs_drop_reason xlate_error_to_drop_reason(enum xlate_error error);
+
void xlate_in_init(struct xlate_in *, struct ofproto_dpif *, ovs_version_t,
const struct flow *, ofp_port_t in_port, struct rule_dpif *,
uint16_t tcp_flags, const struct dp_packet *packet,
@@ -828,6 +828,12 @@ ovs_native_tunneling_is_on(struct ofproto_dpif *ofproto)
&& atomic_count_get(&ofproto->backer->tnl_count);
}
+bool
+ovs_explicit_drop_action_supported(struct ofproto_dpif *ofproto)
+{
+ return ofproto->backer->rt_support.explicit_drop_action;
+}
+
/* Tests whether 'backer''s datapath supports recirculation. Only newer
* datapaths support OVS_KEY_ATTR_RECIRC_ID in keys. We need to disable some
* features on older datapaths that don't support this feature.
@@ -1398,6 +1404,8 @@ check_support(struct dpif_backer *backer)
backer->rt_support.ct_eventmask = check_ct_eventmask(backer);
backer->rt_support.ct_clear = check_ct_clear(backer);
backer->rt_support.max_hash_alg = check_max_dp_hash_alg(backer);
+ backer->rt_support.explicit_drop_action =
+ dpif_supports_explicit_drop_action(backer->dpif);
/* Flow fields. */
backer->rt_support.odp.ct_state = check_ct_state(backer);
@@ -5788,6 +5796,83 @@ ofproto_unixctl_dpif_set_dp_features(struct unixctl_conn *conn,
}
static void
+ofproto_unixctl_dpif_show_drop_stats(struct unixctl_conn *conn,
+ int argc OVS_UNUSED, const char *argv[],
+ void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ int error = 0;
+ int i;
+ const struct shash_node **backers;
+ struct dpif_backer *backer;
+ bool detail = false;
+
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "--detail")) {
+ detail = true;
+ }
+ }
+
+ ds_init(&ds);
+ backers = shash_sort(&all_dpif_backers);
+ for (i = 0; i < shash_count(&all_dpif_backers); i++) {
+ backer = (struct dpif_backer *)backers[i]->data;
+ if (dpif_supports_explicit_drop_action(backer->dpif)) {
+ ds_put_format(&ds, "%s:\n", backer->type);
+ error = dpif_show_drop_stats_support(backer->dpif,
+ detail, &ds);
+ if (error) {
+ break;
+ }
+ }
+ }
+ if (error) {
+ ds_clear(&ds);
+ ds_put_format(&ds, "dpif/show-drop-stats failed");
+ unixctl_command_reply_error(conn, ds_cstr(&ds));
+ } else {
+ unixctl_command_reply(conn, ds_cstr(&ds));
+ }
+ free(backers);
+ ds_destroy(&ds);
+}
+
+
+static void
+ofproto_unixctl_dpif_clear_drop_stats(struct unixctl_conn *conn,
+ int argc OVS_UNUSED,
+ const char *argv[] OVS_UNUSED,
+ void *aux OVS_UNUSED)
+{
+ struct ds ds = DS_EMPTY_INITIALIZER;
+ int error = 0;
+ int i;
+ const struct shash_node **backers;
+ struct dpif_backer *backer;
+
+ ds_init(&ds);
+ backers = shash_sort(&all_dpif_backers);
+ for (i = 0; i < shash_count(&all_dpif_backers) ; i++) {
+ backer = (struct dpif_backer *)backers[i]->data;
+ if (dpif_supports_explicit_drop_action(backer->dpif)) {
+ error = dpif_clear_dp_drop_stats(backer->dpif);
+ if (error) {
+ break;
+ }
+ }
+ }
+ if (error) {
+ ds_clear(&ds);
+ ds_put_format(&ds, "dpif/clear-drop-stats failed");
+ unixctl_command_reply_error(conn, ds_cstr(&ds));
+ } else {
+ unixctl_command_reply(conn, ds_cstr(&ds));
+ }
+ free(backers);
+ ds_destroy(&ds);
+}
+
+static void
ofproto_unixctl_init(void)
{
static bool registered;
@@ -5819,6 +5904,10 @@ ofproto_unixctl_init(void)
ofproto_unixctl_dpif_dump_flows, NULL);
unixctl_command_register("dpif/set-dp-features", "bridge", 1, 3 ,
ofproto_unixctl_dpif_set_dp_features, NULL);
+ unixctl_command_register("dpif/show-drop-stats", "[--detail]", 0, 1,
+ ofproto_unixctl_dpif_show_drop_stats, NULL);
+ unixctl_command_register("dpif/clear-drop-stats", "", 0, 0,
+ ofproto_unixctl_dpif_clear_drop_stats, NULL);
}
static odp_port_t
@@ -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 */
@@ -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 \
@@ -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])
@@ -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],
@@ -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
new file mode 100644
@@ -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
@@ -713,7 +713,7 @@ AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 'group_id=1234,type=ff,bucket=wa
AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=write_actions(group:1234)'])
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,dl_type=0x0800,nw_src=192.168.0.1,nw_dst=192.168.0.2,nw_proto=1,nw_tos=0,nw_ttl=128,icmp_type=8,icmp_code=0'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: drop
+ [Datapath actions: drop:pipeline-drop
])
OVS_VSWITCHD_STOP
AT_CLEANUP
@@ -3524,51 +3524,51 @@ dnl Each of these specifies an in_port by number, a VLAN VID (or "none"),
dnl a VLAN PCP (used if the VID isn't "none") and the expected set of datapath
dnl actions.
for tuple in \
- "100 none 0 drop" \
- "100 0 0 drop" \
- "100 0 1 drop" \
+ "100 none 0 drop:pipeline-drop" \
+ "100 0 0 drop:pipeline-drop" \
+ "100 0 1 drop:pipeline-drop" \
"100 10 0 1,5,6,7,8,pop_vlan,2,9" \
"100 10 1 1,5,6,7,8,pop_vlan,2,9" \
"100 11 0 5,7" \
"100 11 1 5,7" \
"100 12 0 1,5,6,pop_vlan,3,4,7,8,11,12" \
"100 12 1 1,5,6,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
- "1 none 0 drop" \
- "1 0 0 drop" \
- "1 0 1 drop" \
+ "1 none 0 drop:pipeline-drop" \
+ "1 0 0 drop:pipeline-drop" \
+ "1 0 1 drop:pipeline-drop" \
"1 10 0 5,6,7,8,100,pop_vlan,2,9" \
"1 10 1 5,6,7,8,100,pop_vlan,2,9" \
- "1 11 0 drop" \
- "1 11 1 drop" \
+ "1 11 0 drop:pipeline-drop" \
+ "1 11 1 drop:pipeline-drop" \
"1 12 0 5,6,100,pop_vlan,3,4,7,8,11,12" \
"1 12 1 5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
"2 none 0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
"2 0 0 pop_vlan,9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
"2 0 1 pop_vlan,9,push_vlan(vid=10,pcp=1),1,5,6,7,8,100" \
- "2 10 0 drop" \
- "2 10 1 drop" \
- "2 11 0 drop" \
- "2 11 1 drop" \
- "2 12 0 drop" \
- "2 12 1 drop" \
+ "2 10 0 drop:pipeline-drop" \
+ "2 10 1 drop:pipeline-drop" \
+ "2 11 0 drop:pipeline-drop" \
+ "2 11 1 drop:pipeline-drop" \
+ "2 12 0 drop:pipeline-drop" \
+ "2 12 1 drop:pipeline-drop" \
"3 none 0 4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
"3 0 0 pop_vlan,4,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
"3 0 1 8,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
- "3 10 0 drop" \
- "3 10 1 drop" \
- "3 11 0 drop" \
- "3 11 1 drop" \
- "3 12 0 drop" \
- "3 12 1 drop" \
+ "3 10 0 drop:pipeline-drop" \
+ "3 10 1 drop:pipeline-drop" \
+ "3 11 0 drop:pipeline-drop" \
+ "3 11 1 drop:pipeline-drop" \
+ "3 12 0 drop:pipeline-drop" \
+ "3 12 1 drop:pipeline-drop" \
"4 none 0 3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
"4 0 0 pop_vlan,3,7,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
"4 0 1 3,8,12,pop_vlan,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
- "4 10 0 drop" \
- "4 10 1 drop" \
- "4 11 0 drop" \
- "4 11 1 drop" \
- "4 12 0 drop" \
- "4 12 1 drop" \
+ "4 10 0 drop:pipeline-drop" \
+ "4 10 1 drop:pipeline-drop" \
+ "4 11 0 drop:pipeline-drop" \
+ "4 11 1 drop:pipeline-drop" \
+ "4 12 0 drop:pipeline-drop" \
+ "4 12 1 drop:pipeline-drop" \
"5 none 0 2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \
"5 0 0 pop_vlan,2,9,push_vlan(vid=10,pcp=0),1,6,7,8,100" \
"5 0 1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,6,7,8,100" \
@@ -3583,8 +3583,8 @@ for tuple in \
"6 0 1 pop_vlan,2,9,push_vlan(vid=10,pcp=1),1,5,7,8,100" \
"6 10 0 1,5,7,8,100,pop_vlan,2,9" \
"6 10 1 1,5,7,8,100,pop_vlan,2,9" \
- "6 11 0 drop" \
- "6 11 1 drop" \
+ "6 11 0 drop:pipeline-drop" \
+ "6 11 1 drop:pipeline-drop" \
"6 12 0 1,5,100,pop_vlan,3,4,7,8,11,12" \
"6 12 1 1,5,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,8,12" \
"7 none 0 3,4,8,11,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
@@ -3601,16 +3601,16 @@ for tuple in \
"8 0 1 3,12,pop_vlan,4,7,11,push_vlan(vid=12,pcp=1),1,5,6,100" \
"8 10 0 1,5,6,7,100,pop_vlan,2,9" \
"8 10 1 1,5,6,7,100,pop_vlan,2,9" \
- "8 11 0 drop" \
- "8 11 1 drop" \
+ "8 11 0 drop:pipeline-drop" \
+ "8 11 1 drop:pipeline-drop" \
"8 12 0 1,5,6,100,pop_vlan,3,4,7,11,12" \
"8 12 1 1,5,6,100,pop_vlan,4,7,11,push_vlan(vid=0,pcp=1),3,12" \
"9 none 0 2,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
"9 10 0 10,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
"9 11 0 push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
- "10 none 0 drop" \
- "10 0 0 drop" \
- "10 11 0 drop" \
+ "10 none 0 drop:pipeline-drop" \
+ "10 0 0 drop:pipeline-drop" \
+ "10 11 0 drop:pipeline-drop" \
"10 12 0 9,push_vlan(vid=10,pcp=0),1,5,6,7,8,100" \
"11 10 0 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100" \
"11 10 1 7,8,12,push_vlan(vid=12,pcp=0),1,5,6,100"
@@ -4350,11 +4350,11 @@ no_flow="$base_flow,frag=no),tcp(src=12345,dst=80)"
first_flow="$base_flow,frag=first),tcp(src=12345,dst=80)"
later_flow="$base_flow,frag=later)"
- # mode no first later
+ # mode no first later
for tuple in \
- 'normal 1 5 6' \
- 'drop 1 drop drop' \
- 'nx-match 1 2 6'
+ 'normal 1 5 6' \
+ 'drop 1 drop:pipeline-drop drop:pipeline-drop' \
+ 'nx-match 1 2 6'
do
set $tuple
mode=$1
@@ -4432,8 +4432,8 @@ done
AT_CHECK([ovs-appctl dpctl/dump-flows], [0], [dnl
flow-dump from non-dpdk interfaces:
recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=6,frag=no),tcp(dst=80), packets:0, bytes:0, used:never, actions:set(tcp(dst=81)),1
-recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never, actions:drop
-recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=first), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+recirc_id(0),in_port(90),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=later), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
])
mode=nx-match
@@ -5711,7 +5711,7 @@ bridge("br0")
Final flow: <cleared>
Megaflow: <cleared>
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
])
dnl Now, try again without megaflows:
@@ -5732,7 +5732,7 @@ bridge("br0")
Final flow: <cleared>
Megaflow: <cleared>
-Datapath actions: drop
+Datapath actions: drop:pipeline-drop
])
OVS_VSWITCHD_STOP
@@ -7026,7 +7026,7 @@ for i in `seq 1 3`; do
done
AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
flow-dump from non-dpdk interfaces:
-packets:2, bytes:68, used:0.001s, actions:drop
+packets:2, bytes:68, used:0.001s, actions:drop:pipeline-drop
])
OVS_VSWITCHD_STOP(["/sending to collector failed/d"])
@@ -7118,7 +7118,7 @@ for i in `seq 1 3`; do
done
AT_CHECK([ovs-appctl dpctl/dump-flows | sed 's/.*\(packets:\)/\1/' | sed 's/used:[[0-9]].[[0-9]]*s/used:0.001s/'], [0], [dnl
flow-dump from non-dpdk interfaces:
-packets:2, bytes:68, used:0.001s, actions:drop
+packets:2, bytes:68, used:0.001s, actions:drop:pipeline-drop
])
OVS_VSWITCHD_STOP(["/sending to collector failed/d
@@ -7792,21 +7792,21 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
AT_CHECK([ovs-appctl netdev-dummy/receive p3 'in_port(3),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0)'])
ovs-appctl revalidator/wait
AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
-recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
])
AT_CHECK([ovs-appctl dpif/dump-flows br1 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
])
AT_CHECK([ovs-appctl dpif/dump-flows -m br0 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:05/00:00:00:00:00:00,dst=50:54:00:00:00:07/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.1/0.0.0.0,dst=192.168.0.2/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p2),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:07/00:00:00:00:00:00,dst=50:54:00:00:00:05/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=192.168.0.2/0.0.0.0,dst=192.168.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=0/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
])
AT_CHECK([ovs-appctl dpif/dump-flows -m br1 | strip_ufid | strip_used | sort], [0], [dnl
-skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop
+skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(p3),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x0800),ipv4(src=10.0.0.2/0.0.0.0,dst=10.0.0.1/0.0.0.0,proto=1/0,tos=0/0,ttl=64/0,frag=no),icmp(type=8/0,code=0/0), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
])
OVS_VSWITCHD_STOP
@@ -7829,7 +7829,7 @@ m4_define([OFPROTO_DPIF_GET_FLOW],
UFID=`sed -n 's/\(ufid:[[-0-9a-fA-F]]*\).*/\1/p' stdout`
AT_CHECK([ovs-appctl dpctl/get-flow $UFID], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:0, bytes:0, used:never, actions:drop:pipeline-drop
])
OVS_VSWITCHD_STOP
@@ -8577,11 +8577,11 @@ table=0 in_port=1,ip,nw_dst=10.0.0.3 actions=drop
sleep 1
AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:2
-skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop
+skb_priority(0),skb_mark(0),ct_state(-new-est-rel-rpl-inv-trk-snat-dnat),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), actions:drop:pipeline-drop
])
AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_dump | grep 'packets:3'], [0], [dnl
skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.0.0.2,dst=10.0.0.1,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:2
-skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:drop
+skb_priority(0),skb_mark(0),ct_state(0/0xff),ct_zone(0),ct_mark(0),ct_label(0),recirc_id(0),dp_hash(0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:0b,dst=50:54:00:00:00:0c),eth_type(0x0800),ipv4(src=10.0.0.4,dst=10.0.0.3,proto=1,tos=0,ttl=64,frag=no),icmp(type=8,code=0), packets:3, bytes:318, used:0.0s, actions:drop:pipeline-drop
])
OVS_VSWITCHD_STOP
AT_CLEANUP])
@@ -9312,7 +9312,7 @@ for i in 1 2 3; do
done
AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:5, bytes:70, used:0.0s, actions:drop:pipeline-drop
])
# Add a flow that matches the non-presence of a vlan tag, and check
@@ -9341,16 +9341,16 @@ done
AT_CHECK([ovs-appctl dpif/dump-flows br0 | strip_ufid | strip_used | sort], [0], [dnl
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), packets:8, bytes:112, used:0.0s, actions:100
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), packets:2, bytes:36, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), packets:2, bytes:36, used:0.0s, actions:drop:pipeline-drop
])
# Check that the new flow matches the CFI bit, while both vid and pcp
# are wildcarded.
AT_CHECK([grep '\(modify\)\|\(flow_add\)' ovs-vswitchd.log | strip_ufid ], [0], [dnl
dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x1234), actions:100
-dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234)
+dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:drop:pipeline-drop
dpif|DBG|dummy@ovs-dummy: put[[modify]] skb_priority(0/0),skb_mark(0/0),ct_state(0/0),ct_zone(0/0),ct_mark(0/0),ct_label(0/0),recirc_id(0),dp_hash(0/0),in_port(1),packet_type(ns=0,id=0),eth(src=50:54:00:00:00:09/00:00:00:00:00:00,dst=50:54:00:00:00:0a/00:00:00:00:00:00),eth_type(0x1234), actions:100
-dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop
+dpif_netdev|DBG|flow_add: recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x8100),vlan(vid=99,pcp=7/0x0),encap(eth_type(0x1234)), actions:drop:pipeline-drop
])
OVS_VSWITCHD_STOP
AT_CLEANUP
@@ -9675,7 +9675,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p2 'in_port(2),eth(src=50:54:00:00:00:
AT_CHECK([cat ovs-vswitchd.log | strip_ufid | filter_flow_install], [0], [dnl
-ct_state(+new-est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:drop
+ct_state(+new-est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), actions:drop:pipeline-drop
ct_state(-new+est+trk),recirc_id(0x1),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:1
recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct(commit),2
recirc_id(0),in_port(2),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=no), actions:ct,recirc(0x1)
@@ -10362,7 +10362,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt])
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=2,udp'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
- [Datapath actions: drop
+ [Datapath actions: drop:pipeline-drop
])
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,udp'], [0], [stdout])
@@ -10454,7 +10454,7 @@ AT_CHECK([ovs-appctl netdev-dummy/receive p1 'recirc_id(0),in_port(1),eth_type(0
ovs-appctl time/warp 5000
AT_CHECK([strip_ufid < ovs-vswitchd.log | filter_flow_install | strip_used], [0], [dnl
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(proto=17,frag=later), actions:drop:pipeline-drop
])
dnl Change the flow table. This will trigger revalidation of all the flows.
@@ -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
@@ -505,7 +505,7 @@ AT_CHECK([
ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
recirc_id(0),in_port(n3),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(dst=192.168.10.20,tos=0/0x3,frag=no), packets:1, bytes:98, used:0.0s, actions:pop_eth,clone(tnl_push(tnl_port(gre_sys),header(size=38,type=3,eth(dst=aa:55:00:00:00:02,src=aa:55:00:00:00:03,dl_type=0x0800),ipv4(src=30.0.0.3,dst=30.0.0.2,proto=47,tos=0,ttl=64,frag=0x4000),gre((flags=0x0,proto=0x800))),out_port(br-p3)),set(ipv4(src=20.0.0.3,dst=20.0.0.2)),tnl_pop(gre_sys))
-tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop
+tunnel(src=20.0.0.3,dst=20.0.0.2,flags(-df-csum)),recirc_id(0),in_port(gre_sys),packet_type(ns=1,id=0x800),ipv4(dst=192.168.10.20,frag=no), packets:1, bytes:84, used:0.0s, actions:drop:pipeline-drop
])
OVS_VSWITCHD_STOP(["/The Open vSwitch kernel module is probably not loaded/d"])
@@ -565,7 +565,13 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:unsupported packet type
+])
+
+AT_CHECK([
+ ovs-appctl dpif/show-drop-stats --detail | grep "unsupported packet type" | tr -s " " | sed 's/[ \t]*$//'
+], [0], [dnl
+11 unsupported packet type 2
])
# Encap(ethernet) on Ethernet frame -> should be droped
@@ -587,7 +593,7 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:pipeline-drop
])
# Encap(ethernet) on VLAN tagged Ethernet frame -> should be droped
@@ -609,7 +615,7 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:unsupported packet type
])
OVS_VSWITCHD_STOP
@@ -770,7 +776,7 @@ ovs-appctl time/warp 1000
AT_CHECK([
ovs-appctl dpctl/dump-flows --names dummy@ovs-dummy | strip_used | grep -v ipv6 | sort
], [0], [flow-dump from non-dpdk interfaces:
-recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop
+recirc_id(0),in_port(n0),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no), packets:1, bytes:98, used:0.0s, actions:drop:pipeline-drop
])
AT_CHECK([
@@ -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])
@@ -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])
@@ -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