Skip to content

Commit

Permalink
[NETNS][IPV6] ip6_fib - add net to gc timer parameter
Browse files Browse the repository at this point in the history
The fib tables are now relative to the network namespace. When the
garbage collector timer expires, we must have a network namespace
parameter in order to retrieve the tables. For now this is the
init_net, but we should be able to have a timer per namespace and use
the timer callback parameter to pass the network namespace from the
expired timer.

The timer callback, fib6_run_gc, is actually used to be called
synchronously by some functions and asynchronously when the timer
expires.

When the timer expires, the delay specified for fib6_run_gc parameter
is always zero. So, I changed fib6_run_gc to not be a timer callback
but a function called by the timer callback and I added a timer
callback where its work is just to retrieve from the data arg of the
timer the network namespace and call fib6_run_gc with zero expiring
time and the network namespace parameters. That makes the code cleaner
for the fib6_run_gc callers.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Daniel Lezcano authored and David S. Miller committed Mar 4, 2008
1 parent f3db485 commit 5b7c931
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 14 deletions.
3 changes: 2 additions & 1 deletion include/net/ip6_fib.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ extern int fib6_del(struct rt6_info *rt,
extern void inet6_rt_notify(int event, struct rt6_info *rt,
struct nl_info *info);

extern void fib6_run_gc(unsigned long dummy);
extern void fib6_run_gc(unsigned long expires,
struct net *net);

extern void fib6_gc_cleanup(void);

Expand Down
24 changes: 16 additions & 8 deletions net/ipv6/ip6_fib.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,10 @@ static int fib6_walk_continue(struct fib6_walker_t *w);

static __u32 rt_sernum;

static DEFINE_TIMER(ip6_fib_timer, fib6_run_gc, 0, 0);
static void fib6_gc_timer_cb(unsigned long arg);

static DEFINE_TIMER(ip6_fib_timer, fib6_gc_timer_cb, 0,
(unsigned long)&init_net);

static struct fib6_walker_t fib6_walker_list = {
.prev = &fib6_walker_list,
Expand Down Expand Up @@ -1432,37 +1435,42 @@ static int fib6_age(struct rt6_info *rt, void *arg)

static DEFINE_SPINLOCK(fib6_gc_lock);

void fib6_run_gc(unsigned long dummy)
void fib6_run_gc(unsigned long expires, struct net *net)
{
if (dummy != ~0UL) {
if (expires != ~0UL) {
spin_lock_bh(&fib6_gc_lock);
gc_args.timeout = dummy ? (int)dummy :
init_net.ipv6.sysctl.ip6_rt_gc_interval;
gc_args.timeout = expires ? (int)expires :
net->ipv6.sysctl.ip6_rt_gc_interval;
} else {
local_bh_disable();
if (!spin_trylock(&fib6_gc_lock)) {
mod_timer(&ip6_fib_timer, jiffies + HZ);
local_bh_enable();
return;
}
gc_args.timeout = init_net.ipv6.sysctl.ip6_rt_gc_interval;
gc_args.timeout = net->ipv6.sysctl.ip6_rt_gc_interval;
}
gc_args.more = 0;

icmp6_dst_gc(&gc_args.more);

fib6_clean_all(&init_net, fib6_age, 0, NULL);
fib6_clean_all(net, fib6_age, 0, NULL);

if (gc_args.more)
mod_timer(&ip6_fib_timer, jiffies +
init_net.ipv6.sysctl.ip6_rt_gc_interval);
net->ipv6.sysctl.ip6_rt_gc_interval);
else {
del_timer(&ip6_fib_timer);
ip6_fib_timer.expires = 0;
}
spin_unlock_bh(&fib6_gc_lock);
}

static void fib6_gc_timer_cb(unsigned long arg)
{
fib6_run_gc(0, (struct net *)arg);
}

static int fib6_net_init(struct net *net)
{
int ret;
Expand Down
5 changes: 3 additions & 2 deletions net/ipv6/ndisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1598,18 +1598,19 @@ int ndisc_rcv(struct sk_buff *skb)
static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
struct net_device *dev = ptr;
struct net *net = dev->nd_net;

if (dev->nd_net != &init_net)
return NOTIFY_DONE;

switch (event) {
case NETDEV_CHANGEADDR:
neigh_changeaddr(&nd_tbl, dev);
fib6_run_gc(~0UL);
fib6_run_gc(~0UL, net);
break;
case NETDEV_DOWN:
neigh_ifdown(&nd_tbl, dev);
fib6_run_gc(~0UL);
fib6_run_gc(~0UL, net);
break;
default:
break;
Expand Down
8 changes: 5 additions & 3 deletions net/ipv6/route.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include <linux/if_arp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/nsproxy.h>
#include <net/net_namespace.h>
#include <net/snmp.h>
#include <net/ipv6.h>
Expand Down Expand Up @@ -995,7 +996,7 @@ static int ip6_dst_gc(struct dst_ops *ops)
goto out;

expire++;
fib6_run_gc(expire);
fib6_run_gc(expire, &init_net);
last_gc = now;
if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh)
expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1;
Expand Down Expand Up @@ -2413,10 +2414,11 @@ static
int ipv6_sysctl_rtcache_flush(ctl_table *ctl, int write, struct file * filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int delay = init_net.ipv6.sysctl.flush_delay;
struct net *net = current->nsproxy->net_ns;
int delay = net->ipv6.sysctl.flush_delay;
if (write) {
proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay);
fib6_run_gc(delay <= 0 ? ~0UL : (unsigned long)delay, net);
return 0;
} else
return -EINVAL;
Expand Down

0 comments on commit 5b7c931

Please sign in to comment.