Skip to content

Commit

Permalink
ipv6: Reduce timer events for addrconf_verify().
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
yoshfuji authored and davem330 committed Mar 20, 2010
1 parent 88949cf commit b2db756
Showing 1 changed file with 23 additions and 4 deletions.
27 changes: 23 additions & 4 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@
#define INFINITY_LIFE_TIME 0xFFFFFFFF
#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b)))

#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ/50 : 1)
#define ADDRCONF_TIMER_FUZZ (HZ / 4)
#define ADDRCONF_TIMER_FUZZ_MAX (HZ)

#ifdef CONFIG_SYSCTL
static void addrconf_sysctl_register(struct inet6_dev *idev);
static void addrconf_sysctl_unregister(struct inet6_dev *idev);
Expand Down Expand Up @@ -3107,15 +3111,15 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)

static void addrconf_verify(unsigned long foo)
{
unsigned long now, next, next_sec, next_sched;
struct inet6_ifaddr *ifp;
struct hlist_node *node;
unsigned long now, next;
int i;

rcu_read_lock_bh();
spin_lock(&addrconf_verify_lock);
now = jiffies;
next = now + ADDR_CHECK_FREQUENCY;
next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);

del_timer(&addr_chk_timer);

Expand All @@ -3129,7 +3133,8 @@ static void addrconf_verify(unsigned long foo)
continue;

spin_lock(&ifp->lock);
age = (now - ifp->tstamp) / HZ;
/* We try to batch several events at once. */
age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;

if (ifp->valid_lft != INFINITY_LIFE_TIME &&
age >= ifp->valid_lft) {
Expand Down Expand Up @@ -3199,7 +3204,21 @@ static void addrconf_verify(unsigned long foo)
}
}

addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next;
next_sec = round_jiffies_up(next);
next_sched = next;

/* If rounded timeout is accurate enough, accept it. */
if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ))
next_sched = next_sec;

/* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */
if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;

ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
now, next, next_sec, next_sched));

addr_chk_timer.expires = next_sched;
add_timer(&addr_chk_timer);
spin_unlock(&addrconf_verify_lock);
rcu_read_unlock_bh();
Expand Down

0 comments on commit b2db756

Please sign in to comment.