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, ...@@ -181,6 +181,7 @@ extern struct neighbour * neigh_create(struct neigh_table *tbl,
extern void neigh_destroy(struct neighbour *neigh); extern void neigh_destroy(struct neighbour *neigh);
extern int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); 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 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_ifdown(struct neigh_table *tbl, struct net_device *dev);
extern int neigh_resolve_output(struct sk_buff *skb); extern int neigh_resolve_output(struct sk_buff *skb);
extern int neigh_connected_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); ...@@ -50,6 +50,7 @@ static void neigh_timer_handler(unsigned long arg);
static void neigh_app_notify(struct neighbour *n); static void neigh_app_notify(struct neighbour *n);
#endif #endif
static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); 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 int neigh_glbl_allocs;
static struct neigh_table *neigh_tables; static struct neigh_table *neigh_tables;
...@@ -168,6 +169,33 @@ static void pneigh_queue_purge(struct sk_buff_head *list) ...@@ -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 neigh_ifdown(struct neigh_table *tbl, struct net_device *dev)
{ {
int i; int i;
......
...@@ -1071,6 +1071,26 @@ int arp_ioctl(unsigned int cmd, void *arg) ...@@ -1071,6 +1071,26 @@ int arp_ioctl(unsigned int cmd, void *arg)
return err; 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. /* Note, that it is not on notifier chain.
It is necessary, that this routine was called after route cache will be It is necessary, that this routine was called after route cache will be
flushed. flushed.
...@@ -1103,6 +1123,7 @@ void __init arp_init(void) ...@@ -1103,6 +1123,7 @@ void __init arp_init(void)
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
NET_IPV4_NEIGH, "ipv4"); NET_IPV4_NEIGH, "ipv4");
#endif #endif
register_netdevice_notifier(&arp_netdev_notifier);
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
......
...@@ -1447,6 +1447,26 @@ int ndisc_rcv(struct sk_buff *skb) ...@@ -1447,6 +1447,26 @@ int ndisc_rcv(struct sk_buff *skb)
return 0; 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) int __init ndisc_init(struct net_proto_family *ops)
{ {
struct ipv6_pinfo *np; struct ipv6_pinfo *np;
...@@ -1480,6 +1500,7 @@ int __init ndisc_init(struct net_proto_family *ops) ...@@ -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"); neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
#endif #endif
register_netdevice_notifier(&ndisc_netdev_notifier);
return 0; 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