aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2010-03-20 19:11:12 -0400
committerDavid S. Miller <davem@davemloft.net>2010-03-20 19:11:12 -0400
commitb2db756449f63f98049587f7ede4a8e85e0c79b1 (patch)
tree0d9087ccfcc3e7faa1e00fbf340f21d204f3ea15 /net
parent88949cf484bfc399e1d662b5dda6892aaca21aae (diff)
ipv6: Reduce timer events for addrconf_verify().
This patch reduces timer events while keeping accuracy by rounding our timer and/or batching several address validations in addrconf_verify(). addrconf_verify() is called at earliest timeout among interface addresses' timeouts, but at maximum ADDR_CHECK_FREQUENCY (120 secs). In most cases, all of timeouts of interface addresses are long enough (e.g. several hours or days vs 2 minutes), this timer is usually called every ADDR_CHECK_FREQUENCY, and it is okay to be lazy. (Note this timer could be eliminated if all code paths which modifies variables related to timeouts call us manually, but it is another story.) However, in other least but important cases, we try keeping accuracy. When the real interface address timeout is coming, and the timeout is just before the rounded timeout, we accept some error. When a timeout has been reached, we also try batching other several events in very near future. Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 36ebb4ad8a0a..7d7d4b17c0f0 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -99,6 +99,10 @@
99#define INFINITY_LIFE_TIME 0xFFFFFFFF 99#define INFINITY_LIFE_TIME 0xFFFFFFFF
100#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) 100#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))
101 101
102#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1)
103#define ADDRCONF_TIMER_FUZZ (HZ / 4)
104#define ADDRCONF_TIMER_FUZZ_MAX (HZ)
105
102#ifdef CONFIG_SYSCTL 106#ifdef CONFIG_SYSCTL
103static void addrconf_sysctl_register(struct inet6_dev *idev); 107static void addrconf_sysctl_register(struct inet6_dev *idev);
104static void addrconf_sysctl_unregister(struct inet6_dev *idev); 108static void addrconf_sysctl_unregister(struct inet6_dev *idev);
@@ -3107,15 +3111,15 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)
3107 3111
3108static void addrconf_verify(unsigned long foo) 3112static void addrconf_verify(unsigned long foo)
3109{ 3113{
3114 unsigned long now, next, next_sec, next_sched;
3110 struct inet6_ifaddr *ifp; 3115 struct inet6_ifaddr *ifp;
3111 struct hlist_node *node; 3116 struct hlist_node *node;
3112 unsigned long now, next;
3113 int i; 3117 int i;
3114 3118
3115 rcu_read_lock_bh(); 3119 rcu_read_lock_bh();
3116 spin_lock(&addrconf_verify_lock); 3120 spin_lock(&addrconf_verify_lock);
3117 now = jiffies; 3121 now = jiffies;
3118 next = now + ADDR_CHECK_FREQUENCY; 3122 next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);
3119 3123
3120 del_timer(&addr_chk_timer); 3124 del_timer(&addr_chk_timer);
3121 3125
@@ -3129,7 +3133,8 @@ restart:
3129 continue; 3133 continue;
3130 3134
3131 spin_lock(&ifp->lock); 3135 spin_lock(&ifp->lock);
3132 age = (now - ifp->tstamp) / HZ; 3136 /* We try to batch several events at once. */
3137 age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;
3133 3138
3134 if (ifp->valid_lft != INFINITY_LIFE_TIME && 3139 if (ifp->valid_lft != INFINITY_LIFE_TIME &&
3135 age >= ifp->valid_lft) { 3140 age >= ifp->valid_lft) {
@@ -3199,7 +3204,21 @@ restart:
3199 } 3204 }
3200 } 3205 }
3201 3206
3202 addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next; 3207 next_sec = round_jiffies_up(next);
3208 next_sched = next;
3209
3210 /* If rounded timeout is accurate enough, accept it. */
3211 if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
3212 next_sched = next_sec;
3213
3214 /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
3215 if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
3216 next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;
3217
3218 ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
3219 now, next, next_sec, next_sched));
3220
3221 addr_chk_timer.expires = next_sched;
3203 add_timer(&addr_chk_timer); 3222 add_timer(&addr_chk_timer);
3204 spin_unlock(&addrconf_verify_lock); 3223 spin_unlock(&addrconf_verify_lock);
3205 rcu_read_unlock_bh(); 3224 rcu_read_unlock_bh();