Subject: Re: [PATCH] Temporary IPv6 address asignment

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

David Miller pisze:
> From: Lukasz Stelmach <[email-masked]>
> Date: Sun, 03 May 2009 23:45:30 +0200
> 
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> Greetings.
>>
>> I discovered recently and fixed some problems with IPv6 temporary
>> address asignment. I have described the problem at
>> http://bugzilla.kernel.org as bugs #13208 and #13221.
>>
>> http://bugzilla.kernel.org/show_bug.cgi?id=13208
>> http://bugzilla.kernel.org/show_bug.cgi?id=13221
>>
>> The patch is available at:
>>
>> http://bugzilla.kernel.org/attachment.cgi?id=21201
> 
> Nobody is going to look at this unless you post the patch
> with description and proper signoffs with [email-masked]
> CC:'d

The description is in the patch, and a sign-off too. But all righ.

- -----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

----------------------------------------------------------------------
Gotowka na koncie. Otworz konto direct i wez podwojny limit. 	 
http://link.interia.pl/f2145