Skip to content

Commit

Permalink
IPv6: keep permanent addresses on admin down
Browse files Browse the repository at this point in the history
Permanent IPV6 addresses should not be removed when the link is
set to admin down, only when device is removed.

When link is lost permanent addresses should be marked as tentative
so that when link comes back they are subject to duplicate address
detection (if DAD was enabled for that address).

Other routing systems keep manually configured IPv6 addresses
when link is set down.

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
stephen hemminger authored and David S. Miller committed Feb 12, 2010
1 parent c0ad984 commit dc2b99f
Showing 1 changed file with 24 additions and 11 deletions.
35 changes: 24 additions & 11 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2646,7 +2646,8 @@ static int addrconf_ifdown(struct net_device *dev, int how)

write_lock_bh(&addrconf_hash_lock);
while ((ifa = *bifa) != NULL) {
if (ifa->idev == idev) {
if (ifa->idev == idev &&
(how || !(ifa->flags&IFA_F_PERMANENT))) {
*bifa = ifa->lst_next;
ifa->lst_next = NULL;
addrconf_del_timer(ifa);
Expand Down Expand Up @@ -2686,18 +2687,30 @@ static int addrconf_ifdown(struct net_device *dev, int how)
write_lock_bh(&idev->lock);
}
#endif
while ((ifa = idev->addr_list) != NULL) {
idev->addr_list = ifa->if_next;
ifa->if_next = NULL;
ifa->dead = 1;
addrconf_del_timer(ifa);
write_unlock_bh(&idev->lock);
bifa = &idev->addr_list;
while ((ifa = *bifa) != NULL) {
if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) {
/* Retain permanent address on admin down */
bifa = &ifa->if_next;

/* Restart DAD if needed when link comes back up */
if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
idev->cnf.accept_dad <= 0 ||
(ifa->flags & IFA_F_NODAD)))
ifa->flags |= IFA_F_TENTATIVE;
} else {
*bifa = ifa->if_next;
ifa->if_next = NULL;

__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
in6_ifa_put(ifa);
ifa->dead = 1;
write_unlock_bh(&idev->lock);

write_lock_bh(&idev->lock);
__ipv6_ifa_notify(RTM_DELADDR, ifa);
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
in6_ifa_put(ifa);

write_lock_bh(&idev->lock);
}
}
write_unlock_bh(&idev->lock);

Expand Down

0 comments on commit dc2b99f

Please sign in to comment.