Hello, This is a resend of the patch according to Yoshifuji comment. I will send a patch for IPv6 later.
We know that changes in MAC addresses are not frequent but we are working on a special, highly advanced networking Linux based project in our LABs, where we do change MAC addresses of an interface quite frequently. (We do not go totally wild; the MAC addresses we are changing into are from a set of given MAC addresses). Normally, when we change a MAC address of some interface, the relevant neighbours in the LAN which have entries with the previous MAC address are not sent any update notification; instead, it is there regular timers mechanisms which update the MAC address to the new one in their ARP tables. I had written a small patch to neigh_changeaddr() in net/ipv4/arp.c against the 2.6 git net tree, which sends a gratuitous ARP to update the list of all the involved neighbours with the change of MAC address. The patch is for arp_netdev_event() only. This patch was tested and it does work in my LAB; if such a patch is not needed, I wonder why ? It seems to me that it could not cause any troubles. BTW, I had noticed that in irlan driver, there is such a mechanism of sending a gratuitous ARP to update all the neighbours when a MAC address is changed. Signed-off-by: David Shwartz <[EMAIL PROTECTED]>
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 08174a2..7b1162b 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1185,6 +1185,8 @@ out: static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { + struct in_device *in_dev; + struct in_ifaddr *ifa; struct net_device *dev = ptr; if (dev->nd_net != &init_net) @@ -1194,6 +1196,22 @@ static int arp_netdev_event(struct notifier_block *this, unsigned long event, vo case NETDEV_CHANGEADDR: neigh_changeaddr(&arp_tbl, dev); rt_cache_flush(0); + + /* Send gratuitous ARP to the neighbours to update their arp tables */ + + rcu_read_lock(); + in_dev = __in_dev_get_rcu(dev); + if (in_dev == NULL) + goto out; + for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) + arp_send(ARPOP_REQUEST, ETH_P_ARP, + ifa->ifa_address, + dev, + ifa->ifa_address, + NULL, dev->dev_addr, NULL); +out: + rcu_read_unlock(); + break; default: break;