logo       

[PATCH] IPv6: Refine IPv6 Address Validation Timer: msg#00277

Subject: [PATCH] IPv6: Refine IPv6 Address Validation Timer
Hello!

Current IPv6 address validation timer is rough and
timing of address validation is not precise.
This patch refines timing of address validation timer.

Following patch is against linux-2.4.19.

Thank you in advance.

-------------------------------------------------------------------
Patch-Name: Refine IPv6 Address Validation Timer
Patch-Id: FIX_2_4_19_ADDRCONF_TIMER-20020905
Patch-Author: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@xxxxxxxxxxxxxx>
Credit: YOSHIFUJI Hideaki / USAGI Project <yoshfuji@xxxxxxxxxxxxxx>
Reference: RFC2462
-------------------------------------------------------------------
Index: net/ipv6/addrconf.c
===================================================================
RCS file: /cvsroot/usagi/usagi-backport/linux24/net/ipv6/addrconf.c,v
retrieving revision 1.1.1.1
retrieving revision 1.1.1.1.4.3
diff -u -r1.1.1.1 -r1.1.1.1.4.3
--- net/ipv6/addrconf.c 2002/08/20 09:47:02     1.1.1.1
+++ net/ipv6/addrconf.c 2002/09/26 06:58:20     1.1.1.1.4.3
@@ -26,6 +26,8 @@
  *                                             packets.
  *     yoshfuji@USAGI                  :       Fixed interval between DAD
  *                                             packets.
+ *     YOSHIFUJI Hideaki @USAGI        :       improved accuracy of
+ *                                             address validation timer.
  */
 
 #include <linux/config.h>
@@ -93,6 +95,7 @@
 void addrconf_verify(unsigned long);
 
 static struct timer_list addr_chk_timer = { function: addrconf_verify };
+static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED;
 
 static int addrconf_ifdown(struct net_device *dev, int how);
 
@@ -1616,9 +1619,15 @@
 void addrconf_verify(unsigned long foo)
 {
        struct inet6_ifaddr *ifp;
-       unsigned long now = jiffies;
+       unsigned long now, next;
        int i;
 
+       spin_lock_bh(&addrconf_verify_lock);
+       now = jiffies;
+       next = now + ADDR_CHECK_FREQUENCY;
+
+       del_timer(&addr_chk_timer);
+
        for (i=0; i < IN6_ADDR_HSIZE; i++) {
 
 restart:
@@ -1626,24 +1635,32 @@
                for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
                        unsigned long age;
 
-                       if (ifp->flags & IFA_F_PERMANENT)
+                       spin_lock(&ifp->lock);
+                       if (ifp->flags & IFA_F_PERMANENT) {
+                               spin_unlock(&ifp->lock);
                                continue;
+                       }
 
                        age = (now - ifp->tstamp) / HZ;
 
-                       if (age > ifp->valid_lft) {
+                       if (age >= ifp->valid_lft) {
+                               spin_unlock(&ifp->lock);
                                in6_ifa_hold(ifp);
                                write_unlock(&addrconf_hash_lock);
                                ipv6_del_addr(ifp);
                                goto restart;
-                       } else if (age > ifp->prefered_lft) {
+                       } else if (age >= ifp->prefered_lft) {
+                               /* jiffies - ifp->tsamp > age >= 
ifp->prefered_lft */
                                int deprecate = 0;
 
-                               spin_lock(&ifp->lock);
                                if (!(ifp->flags&IFA_F_DEPRECATED)) {
                                        deprecate = 1;
                                        ifp->flags |= IFA_F_DEPRECATED;
                                }
+
+                               if (time_before(ifp->tstamp + ifp->valid_lft * 
HZ, next))
+                                       next = ifp->tstamp + ifp->valid_lft * 
HZ;
+
                                spin_unlock(&ifp->lock);
 
                                if (deprecate) {
@@ -1654,12 +1671,24 @@
                                        in6_ifa_put(ifp);
                                        goto restart;
                                }
+                       } else {
+                               /* ifp->prefered_lft <= ifp->valid_lft */
+                               if (time_before(ifp->tstamp + ifp->prefered_lft 
* HZ, next))
+                                       next = ifp->tstamp + ifp->prefered_lft 
* HZ;
+                               spin_unlock(&ifp->lock);
                        }
                }
                write_unlock(&addrconf_hash_lock);
        }
 
-       mod_timer(&addr_chk_timer, jiffies + ADDR_CHECK_FREQUENCY);
+       if (time_before(now + HZ/2, jiffies)) {
+               ADBG((KERN_WARNING 
+                     "addrconf_verify(): too slow; jiffies - now = %ld\n",
+                     (long)jiffies - (long)now));
+       }
+       addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ 
: next;
+       add_timer(&addr_chk_timer);
+       spin_unlock_bh(&addrconf_verify_lock);
 }
 
 static int
@@ -2033,8 +2062,7 @@
        proc_net_create("if_inet6", 0, iface_proc_info);
 #endif
        
-       addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY;
-       add_timer(&addr_chk_timer);
+       addrconf_verify(0);
        rtnetlink_links[PF_INET6] = inet6_rtnetlink_table;
 #ifdef CONFIG_SYSCTL
        addrconf_sysctl.sysctl_header =





<Prev in Thread] Current Thread [Next in Thread>