ipv4: Disable route secret interval on zero interval

Let me first state that disabling the route cache hash rebuild
should not be done without extensive analysis on the risk profile
and careful deliberation.

However, there are times when this can be done safely or for
testing.  For example, when you have mechanisms for ensuring
that offending parties do not exist in your network.

This patch lets the user disable the rebuild if the interval is
set to zero.  This also incidentally fixes a divide-by-zero error
with name-spaces.

In addition, this patch makes the effect of an interval change
immediate rather than it taking effect at the next rebuild as
is currently the case.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Herbert Xu 2008-08-15 13:44:31 -07:00 committed by David S. Miller
parent 323c048836
commit c6153b5b77
1 changed files with 70 additions and 6 deletions

View File

@ -2914,6 +2914,68 @@ static int ipv4_sysctl_rtcache_flush_strategy(ctl_table *table,
return 0;
}
static void rt_secret_reschedule(int old)
{
struct net *net;
int new = ip_rt_secret_interval;
int diff = new - old;
if (!diff)
return;
rtnl_lock();
for_each_net(net) {
int deleted = del_timer_sync(&net->ipv4.rt_secret_timer);
if (!new)
continue;
if (deleted) {
long time = net->ipv4.rt_secret_timer.expires - jiffies;
if (time <= 0 || (time += diff) <= 0)
time = 0;
net->ipv4.rt_secret_timer.expires = time;
} else
net->ipv4.rt_secret_timer.expires = new;
net->ipv4.rt_secret_timer.expires += jiffies;
add_timer(&net->ipv4.rt_secret_timer);
}
rtnl_unlock();
}
static int ipv4_sysctl_rt_secret_interval(ctl_table *ctl, int write,
struct file *filp,
void __user *buffer, size_t *lenp,
loff_t *ppos)
{
int old = ip_rt_secret_interval;
int ret = proc_dointvec_jiffies(ctl, write, filp, buffer, lenp, ppos);
rt_secret_reschedule(old);
return ret;
}
static int ipv4_sysctl_rt_secret_interval_strategy(ctl_table *table,
int __user *name,
int nlen,
void __user *oldval,
size_t __user *oldlenp,
void __user *newval,
size_t newlen)
{
int old = ip_rt_secret_interval;
int ret = sysctl_jiffies(table, name, nlen, oldval, oldlenp, newval,
newlen);
rt_secret_reschedule(old);
return ret;
}
static ctl_table ipv4_route_table[] = {
{
.ctl_name = NET_IPV4_ROUTE_GC_THRESH,
@ -3048,8 +3110,8 @@ static ctl_table ipv4_route_table[] = {
.data = &ip_rt_secret_interval,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
.proc_handler = &ipv4_sysctl_rt_secret_interval,
.strategy = &ipv4_sysctl_rt_secret_interval_strategy,
},
{ .ctl_name = 0 }
};
@ -3126,10 +3188,12 @@ static __net_init int rt_secret_timer_init(struct net *net)
net->ipv4.rt_secret_timer.data = (unsigned long)net;
init_timer_deferrable(&net->ipv4.rt_secret_timer);
net->ipv4.rt_secret_timer.expires =
jiffies + net_random() % ip_rt_secret_interval +
ip_rt_secret_interval;
add_timer(&net->ipv4.rt_secret_timer);
if (ip_rt_secret_interval) {
net->ipv4.rt_secret_timer.expires =
jiffies + net_random() % ip_rt_secret_interval +
ip_rt_secret_interval;
add_timer(&net->ipv4.rt_secret_timer);
}
return 0;
}