}
}
+static bool
+is_bcast_arp_reply(const flow_t *flow, const struct ofpbuf *packet)
+{
+ struct arp_eth_header *arp = (struct arp_eth_header *) packet->data;
+ return (flow->dl_type == htons(ETH_TYPE_ARP)
+ && eth_addr_is_broadcast(flow->dl_dst)
+ && packet->size >= sizeof(struct arp_eth_header)
+ && arp->ar_op == ARP_OP_REQUEST);
+}
+
/* If the composed actions may be applied to any packet in the given 'flow',
* returns true. Otherwise, the actions should only be applied to 'packet', or
* not at all, if 'packet' was NULL. */
/* If the packet arrived on a bonded port, don't learn from it
* unless we haven't learned any port at all for that address
* (because we probably sent the packet on one bonded interface and
- * got it back on the other). */
- /* XXX invalidation? */
+ * got it back on the other). Broadcast ARP replies are an
+ * exception to this rule: the host has moved to another switch. */
int src_idx = mac_learning_lookup(br->ml, flow->dl_src, vlan);
- may_learn = src_idx < 0 || src_idx == in_port->port_idx;
-
- /* XXX Need to make an exception for broadcast ARP replies here:
- * the host has moved to another switch. */
+ may_learn = (src_idx < 0
+ || src_idx == in_port->port_idx
+ || is_bcast_arp_reply(flow, packet));
} else {
may_learn = true;
}