diff mbox

ipv6: address preservation on link down

Message ID 20090108171415.1d282743@extreme
State RFC, archived
Delegated to: David Miller
Headers show

Commit Message

stephen hemminger Jan. 9, 2009, 1:14 a.m. UTC
When an interface goes down, IPV6 deletes all addresses unlike IPV4. This
is a problem since it can break routing protocols and other applications.
It looks like this was done to handle DAD, but is a big stick solution when
other code is possible.

The following patch changes the behaviour to delete link local addresses
but keep all configured addresses and restart DAD when interface comes back up.

See also: https://kerneltrap.org/mailarchive/linux-netdev/2008/3/25/1252064/thread

Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

RĂ©mi Denis-Courmont Jan. 9, 2009, 8:02 a.m. UTC | #1
On Friday 09 January 2009 03:14:15 ext Stephen Hemminger, you wrote:
> When an interface goes down, IPV6 deletes all addresses unlike IPV4. This
> is a problem since it can break routing protocols and other applications.
> It looks like this was done to handle DAD, but is a big stick solution when
> other code is possible.
>
> The following patch changes the behaviour to delete link local addresses
> but keep all configured addresses and restart DAD when interface comes back
> up.

Let alone the backward compatibility problem for a minute. I have two _other_ 
problems with this:

1/ If DAD should fail when the interface is brought back up, wouldn't all the 
EAU-64 autoconfigured address become invalid, rather than just the link-local 
one?

2/ In some case the link-local address is assigned by userland, no different 
from the other ones. At least miredo is behaving this way.
diff mbox

Patch

--- a/net/ipv6/addrconf.c	2009-01-08 16:43:04.921305933 -0800
+++ b/net/ipv6/addrconf.c	2009-01-08 16:47:04.000301344 -0800
@@ -2678,18 +2678,26 @@  static int addrconf_ifdown(struct net_de
 		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);
-
-		__ipv6_ifa_notify(RTM_DELADDR, ifa);
-		atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
-		in6_ifa_put(ifa);
-
-		write_lock_bh(&idev->lock);
+	/* clear regular address list on removal */
+	bifa = &idev->addr_list;
+	while ((ifa = *bifa) != NULL) {
+		if (how || (ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) {
+			*bifa = ifa->if_next;
+			ifa->if_next = NULL;
+			ifa->dead = 1;
+			addrconf_del_timer(ifa);
+			write_unlock_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);
+		} else {
+			/* Force duplicate address detection when link resumes */
+			ifa->flags |= IFA_F_TENTATIVE;
+			bifa = &ifa->if_next;
+		}
 	}
 	write_unlock_bh(&idev->lock);