Skip to content

Commit 84e8b80

Browse files
stephen hemmingerdavem330
authored andcommitted
IPv6: addrconf notify when address is unavailable
My recent change in net-next to retain permanent addresses caused regression. Device refcount would not go to zero when device was unregistered because left over anycast reference would hold ipv6 dev reference which would hold device references... The correct procedure is to call notify chain when address is no longer available for use. When interface comes back DAD timer will notify back that address is available. Also, link local addresses should be purged when interface is brought down. The address might be changed. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 5b2a195 commit 84e8b80

File tree

1 file changed

+29
-17
lines changed

1 file changed

+29
-17
lines changed

net/ipv6/addrconf.c

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,11 +2649,11 @@ static int addrconf_ifdown(struct net_device *dev, int how)
26492649
write_lock_bh(&addrconf_hash_lock);
26502650
while ((ifa = *bifa) != NULL) {
26512651
if (ifa->idev == idev &&
2652-
(how || !(ifa->flags&IFA_F_PERMANENT))) {
2652+
(how || !(ifa->flags&IFA_F_PERMANENT) ||
2653+
ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
26532654
*bifa = ifa->lst_next;
26542655
ifa->lst_next = NULL;
2655-
addrconf_del_timer(ifa);
2656-
in6_ifa_put(ifa);
2656+
__in6_ifa_put(ifa);
26572657
continue;
26582658
}
26592659
bifa = &ifa->lst_next;
@@ -2691,28 +2691,40 @@ static int addrconf_ifdown(struct net_device *dev, int how)
26912691
#endif
26922692
bifa = &idev->addr_list;
26932693
while ((ifa = *bifa) != NULL) {
2694-
if (how == 0 && (ifa->flags&IFA_F_PERMANENT)) {
2695-
/* Retain permanent address on admin down */
2694+
addrconf_del_timer(ifa);
2695+
2696+
/* If just doing link down, and address is permanent
2697+
and not link-local, then retain it. */
2698+
if (how == 0 &&
2699+
(ifa->flags&IFA_F_PERMANENT) &&
2700+
!(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
26962701
bifa = &ifa->if_next;
26972702

2698-
/* Restart DAD if needed when link comes back up */
2699-
if ( !((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2700-
idev->cnf.accept_dad <= 0 ||
2701-
(ifa->flags & IFA_F_NODAD)))
2702-
ifa->flags |= IFA_F_TENTATIVE;
2703+
/* If not doing DAD on this address, just keep it. */
2704+
if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) ||
2705+
idev->cnf.accept_dad <= 0 ||
2706+
(ifa->flags & IFA_F_NODAD))
2707+
continue;
2708+
2709+
/* If it was tentative already, no need to notify */
2710+
if (ifa->flags & IFA_F_TENTATIVE)
2711+
continue;
2712+
2713+
/* Flag it for later restoration when link comes up */
2714+
ifa->flags |= IFA_F_TENTATIVE;
2715+
in6_ifa_hold(ifa);
27032716
} else {
27042717
*bifa = ifa->if_next;
27052718
ifa->if_next = NULL;
2706-
27072719
ifa->dead = 1;
2708-
write_unlock_bh(&idev->lock);
2720+
}
2721+
write_unlock_bh(&idev->lock);
27092722

2710-
__ipv6_ifa_notify(RTM_DELADDR, ifa);
2711-
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2712-
in6_ifa_put(ifa);
2723+
__ipv6_ifa_notify(RTM_DELADDR, ifa);
2724+
atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
2725+
in6_ifa_put(ifa);
27132726

2714-
write_lock_bh(&idev->lock);
2715-
}
2727+
write_lock_bh(&idev->lock);
27162728
}
27172729
write_unlock_bh(&idev->lock);
27182730

0 commit comments

Comments
 (0)