Commit ae41b279 authored by Tommi Virtanen's avatar Tommi Virtanen Committed by Stephen Hemminger

[NET]: Flush hw header caches on NETDEV_CHANGEADDR events.

parent a0ff86b8
......@@ -181,6 +181,7 @@ extern struct neighbour * neigh_create(struct neigh_table *tbl,
extern void neigh_destroy(struct neighbour *neigh);
extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
extern int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int override, int arp);
extern void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_resolve_output(struct sk_buff *skb);
extern int neigh_connected_output(struct sk_buff *skb);
......
......@@ -50,6 +50,7 @@ static void neigh_timer_handler(unsigned long arg);
static void neigh_app_notify(struct neighbour *n);
#endif
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
static int neigh_glbl_allocs;
static struct neigh_table *neigh_tables;
......@@ -168,6 +169,33 @@ static void pneigh_queue_purge(struct sk_buff_head *list)
}
}
void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev)
{
int i;
write_lock_bh(&tbl->lock);
for (i=0; i <= NEIGH_HASHMASK; i++) {
struct neighbour *n, **np;
np = &tbl->hash_buckets[i];
while ((n = *np) != NULL) {
if (dev && n->dev != dev) {
np = &n->next;
continue;
}
*np = n->next;
write_lock_bh(&n->lock);
n->dead = 1;
neigh_del_timer(n);
write_unlock_bh(&n->lock);
neigh_release(n);
}
}
write_unlock_bh(&tbl->lock);
}
int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
{
int i;
......
......@@ -1071,6 +1071,26 @@ int arp_ioctl(unsigned int cmd, void *arg)
return err;
}
static int arp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
switch (event) {
case NETDEV_CHANGEADDR:
neigh_changeaddr(&arp_tbl, dev);
rt_cache_flush(0);
break;
default:
break;
}
return NOTIFY_DONE;
}
struct notifier_block arp_netdev_notifier = {
.notifier_call = arp_netdev_event,
};
/* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be
flushed.
......@@ -1103,6 +1123,7 @@ void __init arp_init(void)
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4");
#endif
register_netdevice_notifier(&arp_netdev_notifier);
}
#ifdef CONFIG_PROC_FS
......
......@@ -1447,6 +1447,26 @@ int ndisc_rcv(struct sk_buff *skb)
return 0;
}
static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
switch (event) {
case NETDEV_CHANGEADDR:
neigh_changeaddr(&nd_tbl, dev);
fib6_run_gc(0);
break;
default:
break;
}
return NOTIFY_DONE;
}
struct notifier_block ndisc_netdev_notifier = {
.notifier_call = ndisc_netdev_event,
};
int __init ndisc_init(struct net_proto_family *ops)
{
struct ipv6_pinfo *np;
......@@ -1480,6 +1500,7 @@ int __init ndisc_init(struct net_proto_family *ops)
neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
#endif
register_netdevice_notifier(&ndisc_netdev_notifier);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment