aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vswitchd/bridge.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 8314c539..61813bb4 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -2269,12 +2269,17 @@ update_learning_table(struct bridge *br, const flow_t *flow, int vlan,
}
}
+/* A VM broadcasts a gratuitous ARP to indicate that it has resumed after
+ * migration. Older Citrix-patched Linux DomU used gratuitous ARP replies to
+ * indicate this; newer upstream kernels use gratuitous ARP requests. */
static bool
-is_bcast_arp_reply(const flow_t *flow)
+is_gratuitous_arp(const flow_t *flow)
{
return (flow->dl_type == htons(ETH_TYPE_ARP)
- && flow->nw_proto == ARP_OP_REPLY
- && eth_addr_is_broadcast(flow->dl_dst));
+ && eth_addr_is_broadcast(flow->dl_dst)
+ && (flow->nw_proto == ARP_OP_REPLY
+ || (flow->nw_proto == ARP_OP_REQUEST
+ && flow->nw_src == flow->nw_dst)));
}
/* Determines whether packets in 'flow' within 'br' should be forwarded or
@@ -2366,11 +2371,11 @@ is_admissible(struct bridge *br, const flow_t *flow, bool have_packet,
/* Drop all packets for which we have learned a different input
* port, because we probably sent the packet on one slave and got
- * it back on the other. Broadcast ARP replies are an exception
+ * it back on the other. Gratuitous ARP packets are an exception
* to this rule: the host has moved to another switch. */
src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan);
if (src_idx != -1 && src_idx != in_port->port_idx &&
- !is_bcast_arp_reply(flow)) {
+ !is_gratuitous_arp(flow)) {
return false;
}
}