Subject: Re: [PATCH] Temporary IPv6 address asignment

From: Lukasz Stelmach <[email-masked]>
Date: Mon, 04 May 2009 00:45:05 +0200

David Miller pisze:
> Please fix this up and make a fresh submission of your patch to
> [email-masked]

-----CUT HERE-----
A fixed mechanism to create and recreate temporary addresses,
even for very short preferred lifetimes.

A new RFC-compliant DESYNC_FACTOR implemented as a sysctl
variable desync_factor which is assigned a random value
each time max_desync_factor is written to.  Each interface
has its own desync_factor and max_desync_factor. Writes to
default/max_desync_factor influence only default values. Writes
to all/max_desync_factor influence "all" and default values but
not values of running interfaces.

The patch fixes issues described in bugs #13208 and #13221 at
http://bugzilla.kernel.org.

Signed-off-by: Łukasz Stelmach <[email-masked]>

diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 476d946..fa45ad2 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -146,6 +146,7 @@ struct ipv6_devconf {
 	__s32		temp_prefered_lft;
 	__s32		regen_max_retry;
 	__s32		max_desync_factor;
+	__s32		desync_factor;
 #endif
 	__s32		max_addresses;
 	__s32		accept_ra_defrtr;
@@ -188,6 +189,7 @@ enum {
 	DEVCONF_TEMP_PREFERED_LFT,
 	DEVCONF_REGEN_MAX_RETRY,
 	DEVCONF_MAX_DESYNC_FACTOR,
+	DEVCONF_DESYNC_FACTOR,
 	DEVCONF_MAX_ADDRESSES,
 	DEVCONF_FORCE_MLD_VERSION,
 	DEVCONF_ACCEPT_RA_DEFRTR,
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index e76d3b2..951ba2c 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -570,15 +570,16 @@ enum {
 	NET_IPV6_TEMP_PREFERED_LFT=13,
 	NET_IPV6_REGEN_MAX_RETRY=14,
 	NET_IPV6_MAX_DESYNC_FACTOR=15,
-	NET_IPV6_MAX_ADDRESSES=16,
-	NET_IPV6_FORCE_MLD_VERSION=17,
-	NET_IPV6_ACCEPT_RA_DEFRTR=18,
-	NET_IPV6_ACCEPT_RA_PINFO=19,
-	NET_IPV6_ACCEPT_RA_RTR_PREF=20,
-	NET_IPV6_RTR_PROBE_INTERVAL=21,
-	NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22,
-	NET_IPV6_PROXY_NDP=23,
-	NET_IPV6_ACCEPT_SOURCE_ROUTE=25,
+	NET_IPV6_DESYNC_FACTOR=16,
+	NET_IPV6_MAX_ADDRESSES=17,
+	NET_IPV6_FORCE_MLD_VERSION=18,
+	NET_IPV6_ACCEPT_RA_DEFRTR=19,
+	NET_IPV6_ACCEPT_RA_PINFO=20,
+	NET_IPV6_ACCEPT_RA_RTR_PREF=21,
+	NET_IPV6_RTR_PROBE_INTERVAL=22,
+	NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=23,
+	NET_IPV6_PROXY_NDP=24,
+	NET_IPV6_ACCEPT_SOURCE_ROUTE=26,
 	__NET_IPV6_MAX
 };

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a8218bc..1b746ee 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -116,8 +116,6 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
 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 int desync_factor = MAX_DESYNC_FACTOR * HZ;
 #endif

 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
@@ -172,6 +170,7 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
 	.temp_prefered_lft	= TEMP_PREFERRED_LIFETIME,
 	.regen_max_retry	= REGEN_MAX_RETRY,
 	.max_desync_factor	= MAX_DESYNC_FACTOR,
+	.desync_factor		= MAX_DESYNC_FACTOR / 2,
 #endif
 	.max_addresses		= IPV6_MAX_ADDRESSES,
 	.accept_ra_defrtr	= 1,
@@ -206,6 +205,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 	.temp_prefered_lft	= TEMP_PREFERRED_LIFETIME,
 	.regen_max_retry	= REGEN_MAX_RETRY,
 	.max_desync_factor	= MAX_DESYNC_FACTOR,
+	.desync_factor		= MAX_DESYNC_FACTOR / 2,
 #endif
 	.max_addresses		= IPV6_MAX_ADDRESSES,
 	.accept_ra_defrtr	= 1,
@@ -831,11 +831,13 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
 }

 #ifdef CONFIG_IPV6_PRIVACY
-static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift)
+static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp,
+				struct inet6_ifaddr *ift,
+				unsigned long now)
 {
 	struct inet6_dev *idev = ifp->idev;
 	struct in6_addr addr, *tmpaddr;
-	unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_cstamp, tmp_tstamp;
+	unsigned long tmp_prefered_lft, tmp_valid_lft;
 	unsigned long regen_advance;
 	int tmp_plen;
 	int ret = 0;
@@ -890,11 +892,9 @@ retry:
 			      idev->cnf.temp_valid_lft);
 	tmp_prefered_lft = min_t(__u32,
 				 ifp->prefered_lft,
-				 idev->cnf.temp_prefered_lft - desync_factor / HZ);
+				 idev->cnf.temp_prefered_lft - idev->cnf.desync_factor);
 	tmp_plen = ifp->prefix_len;
 	max_addresses = idev->cnf.max_addresses;
-	tmp_cstamp = ifp->cstamp;
-	tmp_tstamp = ifp->tstamp;
 	spin_unlock_bh(&ifp->lock);

 	regen_advance = idev->cnf.regen_max_retry *
@@ -938,8 +938,7 @@ retry:
 	ift->ifpub = ifp;
 	ift->valid_lft = tmp_valid_lft;
 	ift->prefered_lft = tmp_prefered_lft;
-	ift->cstamp = tmp_cstamp;
-	ift->tstamp = tmp_tstamp;
+	ift->cstamp = ift->tstamp = now;
 	spin_unlock_bh(&ift->lock);

 	addrconf_dad_start(ift, 0);
@@ -1388,7 +1387,7 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
 		if (ifpub) {
 			in6_ifa_hold(ifpub);
 			spin_unlock_bh(&ifp->lock);
-			ipv6_create_tempaddr(ifpub, ifp);
+			ipv6_create_tempaddr(ifpub, ifp, jiffies);
 			in6_ifa_put(ifpub);
 		} else {
 			spin_unlock_bh(&ifp->lock);
@@ -1624,7 +1623,8 @@ static void ipv6_regen_rndid(unsigned long data)

 	expires = jiffies +
 		idev->cnf.temp_prefered_lft * HZ -
-		idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time - desync_factor;
+		idev->cnf.regen_max_retry * idev->cnf.dad_transmits * idev->nd_parms->retrans_time -
+		idev->cnf.desync_factor * HZ;
 	if (time_before(expires, jiffies)) {
 		printk(KERN_WARNING
 			"ipv6_regen_rndid(): too short regeneration interval; timer disabled for %s.\n",
@@ -1971,7 +1971,7 @@ ok:
 				 * also create a new temporary address.
 				 */
 				read_unlock_bh(&in6_dev->lock);
-				ipv6_create_tempaddr(ifp, NULL);
+				ipv6_create_tempaddr(ifp, NULL, jiffies);
 			} else {
 				read_unlock_bh(&in6_dev->lock);
 			}
@@ -2809,6 +2809,11 @@ static void addrconf_dad_timer(unsigned long data)
 		read_unlock_bh(&idev->lock);

 		addrconf_dad_completed(ifp);
+		/*
+		 * Required to expire properly temporary addresses
+		 * with preferred lifetimes < ADDR_CHECK_FREQUENCY
+		 */
+		addrconf_verify(0);

 		goto out;
 	}
@@ -3121,7 +3126,7 @@ restart:
 						spin_lock(&ifpub->lock);
 						ifpub->regen_count = 0;
 						spin_unlock(&ifpub->lock);
-						ipv6_create_tempaddr(ifpub, ifp);
+						ipv6_create_tempaddr(ifpub, ifp, now);
 						in6_ifa_put(ifpub);
 						in6_ifa_put(ifp);
 						goto restart;
@@ -3638,6 +3643,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
 	array[DEVCONF_TEMP_PREFERED_LFT] = cnf->temp_prefered_lft;
 	array[DEVCONF_REGEN_MAX_RETRY] = cnf->regen_max_retry;
 	array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor;
+	array[DEVCONF_DESYNC_FACTOR] = cnf->desync_factor;
 #endif
 	array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses;
 	array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr;
@@ -3935,6 +3941,43 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
 }

 #ifdef CONFIG_SYSCTL
+#ifdef CONFIG_IPV6_PRIVACY
+static int addrconf_sysctl_desync(ctl_table *ctl, int write,
+				 struct file *filp, void __user *buffer,
+				 size_t *lenp, loff_t *ppos)
+{
+	int ret;
+
+	ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
+
+	if (write) {
+		__s32 df;
+		int *valp = ctl->data;
+		struct ipv6_devconf *all, *dflt;
+		struct inet6_dev *idev = ctl->extra1;
+		struct net *net = ctl->extra2;
+		all = net->ipv6.devconf_all;
+		dflt = net->ipv6.devconf_dflt;
+
+		get_random_bytes(&df, sizeof(df));
+		/* The global abs() casts to int. */;
+		df = ((df) < 0 ? -(df) : df) % (*valp)
+
+		/* XXX How about some locking? */
+		if(idev)
+			idev->cnf.desync_factor = df;
+		else if (valp == &dflt->max_desync_factor)
+			dflt->desync_factor = df;
+		else if (valp == &all->max_desync_factor) {
+			all->desync_factor = df;
+			dflt->max_desync_factor = all->max_desync_factor;
+			dflt->desync_factor = df;
+		}
+
+	}
+	return ret;
+}
+#endif

 static
 int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
@@ -4124,6 +4167,14 @@ static struct addrconf_sysctl_table
 			.data		=	&ipv6_devconf.max_desync_factor,
 			.maxlen		=	sizeof(int),
 			.mode		=	0644,
+			.proc_handler	=	addrconf_sysctl_desync,
+		},
+		{
+			.ctl_name	=	NET_IPV6_DESYNC_FACTOR,
+			.procname	=	"desync_factor",
+			.data		=	&ipv6_devconf.desync_factor,
+			.maxlen		=	sizeof(int),
+			.mode		=	0444,
 			.proc_handler	=	proc_dointvec,
 		},
 #endif
@@ -4449,6 +4500,11 @@ int __init addrconf_init(void)
 	rtnl_unlock();
 	if (err)
 		goto errlo;
+#ifdef CONFIG_IPV6_PRIVACY
+	get_random_bytes(&ipv6_devconf.desync_factor, sizeof(ipv6_devconf.desync_factor));
+	ipv6_devconf.desync_factor = abs(ipv6_devconf.desync_factor) % ipv6_devconf.max_desync_factor;
+	ipv6_devconf_dflt.desync_factor = ipv6_devconf.desync_factor;
+#endif

 	register_netdevice_notifier(&ipv6_dev_notf);

-----CUT HERE-----

-- 
Było mi bardzo miło.               Czwarta pospolita klęska, [...]
>Łukasz<                 Już nie katolicka lecz złodziejska.  (c)PP

----------------------------------------------------------------------
Dzwonki na komork�!
Sprawdz >> http://link.interia.pl/f2152