[PATCH Precise SRU] UBUNTU: SAUCE: net/ipv6: don't take interface down when enabling/disabling use_tempaddr

Tim Gardner tim.gardner at canonical.com
Fri Jun 20 13:32:27 UTC 2014


From: Malcolm Scott <debianpkg at malc.org.uk>

BugLink: http://bugs.launchpad.net/bugs/994931

Altering use_tempaddr drops all IPv6 addresses.

Signed-off-by: Malcolm Scott <debianpkg at malc.org.uk>
Signed-off-by: Tim Gardner <tim.gardner at canonical.com>
---
 net/ipv6/addrconf.c | 57 ++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 43 insertions(+), 14 deletions(-)

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 246a170..6e576c6 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -125,7 +125,8 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
 #ifdef CONFIG_IPV6_PRIVACY
 static int __ipv6_regen_rndid(struct inet6_dev *idev);
 static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
-static void ipv6_regen_rndid(unsigned long data);
+static void ipv6_regen_rndid(struct inet6_dev *idev);
+static void ipv6_regen_rndid_tick(unsigned long data);
 #endif
 
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
@@ -409,7 +410,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 
 #ifdef CONFIG_IPV6_PRIVACY
 	INIT_LIST_HEAD(&ndev->tempaddr_list);
-	setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);
+	setup_timer(&ndev->regen_timer, ipv6_regen_rndid_tick, (unsigned long)ndev);
 	if ((dev->flags&IFF_LOOPBACK) ||
 	    dev->type == ARPHRD_TUNNEL ||
 	    dev->type == ARPHRD_TUNNEL6 ||
@@ -417,8 +418,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
 	    dev->type == ARPHRD_NONE) {
 		ndev->cnf.use_tempaddr = -1;
 	} else {
-		in6_dev_hold(ndev);
-		ipv6_regen_rndid((unsigned long) ndev);
+		rcu_read_lock_bh();
+		ipv6_regen_rndid(ndev);
+		rcu_read_unlock_bh();
 	}
 #endif
 
@@ -1649,12 +1651,21 @@ regen:
 	return 0;
 }
 
-static void ipv6_regen_rndid(unsigned long data)
+static void ipv6_regen_rndid_tick(unsigned long data)
 {
 	struct inet6_dev *idev = (struct inet6_dev *) data;
-	unsigned long expires;
 
 	rcu_read_lock_bh();
+	ipv6_regen_rndid(idev);
+	rcu_read_unlock_bh();
+	in6_dev_put(idev);
+}
+
+/* called with rcu_read_lock_bh() */
+static void ipv6_regen_rndid(struct inet6_dev *idev)
+{
+	unsigned long expires;
+
 	write_lock_bh(&idev->lock);
 
 	if (idev->dead)
@@ -1679,8 +1690,6 @@ static void ipv6_regen_rndid(unsigned long data)
 
 out:
 	write_unlock_bh(&idev->lock);
-	rcu_read_unlock_bh();
-	in6_dev_put(idev);
 }
 
 static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) {
@@ -4390,12 +4399,32 @@ static void dev_tempaddr_change(struct inet6_dev *idev)
 	if (!idev || !idev->dev)
 		return;
 
-	if (!idev->cnf.disable_ipv6) {
-		/* If ipv6 is enabled, try to bring down and back up the
-		 * interface to get new temporary addresses created
-		 */
-		addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
-		addrconf_notify(NULL, NETDEV_UP, idev->dev);
+	/* Add/remove temporary addresses if necessary */
+	if (!idev->cnf.disable_ipv6 && idev->cnf.autoconf) {
+		if (idev->cnf.use_tempaddr > 0) {
+			struct inet6_ifaddr *ifp, *ifn;
+
+			/*
+			 * Create a temporary address for every non-temporary,
+			 * non-permanent (i.e. autoconfigured) address
+			 */
+
+			ipv6_regen_rndid(idev);
+
+			list_for_each_entry_safe(ifp, ifn, &idev->addr_list, if_list) {
+				if (!(ifp->flags & (IFA_F_TEMPORARY | IFA_F_PERMANENT))) {
+					ipv6_create_tempaddr(ifp, NULL);
+				}
+			}
+		} else {
+			struct inet6_ifaddr *ifa;
+
+			while (!list_empty(&idev->tempaddr_list)) {
+				ifa = list_first_entry(&idev->tempaddr_list,
+						       struct inet6_ifaddr, tmp_list);
+				ipv6_del_addr(ifa);
+			}
+		}
 	}
 }
 
-- 
2.0.0





More information about the kernel-team mailing list