ft_insert(br->ft, f);
queue = true;
}
+ f->need_drop = false;
if (queue) {
struct ofpbuf *fbuf = make_add_flow(flow, pkt->buffer_id,
/* Find the interface and port structure for the received packet. */
in_iface = iface_from_dp_ifidx(br, in_ifidx);
if (!in_iface) {
- struct ft_flow *f;
-
- if (pkt->buf) {
+ /* No interface? Something fishy... */
+ struct ft_flow *f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
+ if (pkt->buf || (f && f->need_drop)) {
+ /* Odd. A few possible reasons here:
+ *
+ * - We deleted an interface but there are still a few packets
+ * queued up from it.
+ *
+ * - Someone externally added an interface (e.g. with "dpctl
+ * addif") that we don't know about.
+ *
+ * - Packet arrived on the local port but the local port is not
+ * one of our bridge ports.
+ */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_WARN_RL(&rl, "bridge %s: received packet on unknown "
"interface %"PRIu16, br->name, in_ifidx);
- }
- queue_tx(br, make_add_flow(flow, pkt->buffer_id,
- br->flow_idle_time, 0));
+ queue_tx(br, make_add_flow(flow, pkt->buffer_id,
+ br->flow_idle_time, 0));
+ if (f) {
+ ftf_set_dsts(f, NULL, 0);
+ f->tags = tags;
+ } else {
+ ft_insert(br->ft, ftf_create(flow, NULL, 0, tags));
+ }
- f = ft_lookup(br->ft, flow, flow_hash(flow, 0));
- if (f) {
- ftf_set_dsts(f, NULL, 0);
- f->tags = tags;
+ /* Mark the flow as being needed to drop packets. (If we don't do
+ * this, then the flow will be deleted as soon as we revalidate
+ * it.) */
+ f->need_drop = true;
} else {
- ft_insert(br->ft, ftf_create(flow, NULL, 0, tags));
+ /* We're revalidating, not receiving a fresh packet. Most likely,
+ * this interface existed and has now been deleted from the
+ * datapath. Drop the flow. */
+ assert(f);
+ queue_tx(br, make_del_flow(flow));
+ ft_remove(br->ft, f);
+ ftf_destroy(f);
+ /* 'flow' pointed to &f->flow, so don't access it anymore. */
}
-
return;
}
in_port = in_iface->port;