diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h index a158abe7193..79dce496f4d 100644 --- a/include/net/ip6_route.h +++ b/include/net/ip6_route.h @@ -78,7 +78,7 @@ extern struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct in6_addr *addr); extern int icmp6_dst_gc(int *more); -extern void fib6_force_start_gc(void); +extern void fib6_force_start_gc(struct net *net); extern struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, const struct in6_addr *addr, diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index b0653261c5a..5279cd6a00b 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -36,6 +36,7 @@ struct netns_ipv6 { struct xt_table *ip6table_mangle; struct xt_table *ip6table_raw; #endif + struct timer_list *ip6_fib_timer; struct hlist_head *fib_table_hash; struct fib6_table *fib6_main_tbl; #ifdef CONFIG_IPV6_MULTIPLE_TABLES diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 77ad1002c90..4aa67988f51 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -95,8 +95,6 @@ static __u32 rt_sernum; static void fib6_gc_timer_cb(unsigned long arg); -static struct timer_list *ip6_fib_timer; - static struct fib6_walker_t fib6_walker_list = { .prev = &fib6_walker_list, .next = &fib6_walker_list, @@ -663,19 +661,19 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, return 0; } -static __inline__ void fib6_start_gc(struct rt6_info *rt) +static __inline__ void fib6_start_gc(struct net *net, struct rt6_info *rt) { - if (ip6_fib_timer->expires == 0 && + if (net->ipv6.ip6_fib_timer->expires == 0 && (rt->rt6i_flags & (RTF_EXPIRES|RTF_CACHE))) - mod_timer(ip6_fib_timer, jiffies + - init_net.ipv6.sysctl.ip6_rt_gc_interval); + mod_timer(net->ipv6.ip6_fib_timer, jiffies + + net->ipv6.sysctl.ip6_rt_gc_interval); } -void fib6_force_start_gc(void) +void fib6_force_start_gc(struct net *net) { - if (ip6_fib_timer->expires == 0) - mod_timer(ip6_fib_timer, jiffies + - init_net.ipv6.sysctl.ip6_rt_gc_interval); + if (net->ipv6.ip6_fib_timer->expires == 0) + mod_timer(net->ipv6.ip6_fib_timer, jiffies + + net->ipv6.sysctl.ip6_rt_gc_interval); } /* @@ -762,7 +760,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nl_info *info) err = fib6_add_rt2node(fn, rt, info); if (err == 0) { - fib6_start_gc(rt); + fib6_start_gc(info->nl_net, rt); if (!(rt->rt6i_flags&RTF_CACHE)) fib6_prune_clones(pn, rt); } @@ -1443,7 +1441,7 @@ void fib6_run_gc(unsigned long expires, struct net *net) } else { local_bh_disable(); if (!spin_trylock(&fib6_gc_lock)) { - mod_timer(ip6_fib_timer, jiffies + HZ); + mod_timer(net->ipv6.ip6_fib_timer, jiffies + HZ); local_bh_enable(); return; } @@ -1456,11 +1454,11 @@ void fib6_run_gc(unsigned long expires, struct net *net) fib6_clean_all(net, fib6_age, 0, NULL); if (gc_args.more) - mod_timer(ip6_fib_timer, jiffies + + mod_timer(net->ipv6.ip6_fib_timer, jiffies + net->ipv6.sysctl.ip6_rt_gc_interval); else { - del_timer(ip6_fib_timer); - ip6_fib_timer->expires = 0; + del_timer(net->ipv6.ip6_fib_timer); + net->ipv6.ip6_fib_timer->expires = 0; } spin_unlock_bh(&fib6_gc_lock); } @@ -1473,13 +1471,21 @@ static void fib6_gc_timer_cb(unsigned long arg) static int fib6_net_init(struct net *net) { int ret; + struct timer_list *timer; ret = -ENOMEM; + timer = kzalloc(sizeof(*timer), GFP_KERNEL); + if (!timer) + goto out; + + setup_timer(timer, fib6_gc_timer_cb, (unsigned long)net); + net->ipv6.ip6_fib_timer = timer; + net->ipv6.fib_table_hash = kzalloc(sizeof(*net->ipv6.fib_table_hash)*FIB_TABLE_HASHSZ, GFP_KERNEL); if (!net->ipv6.fib_table_hash) - goto out; + goto out_timer; net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl), GFP_KERNEL); @@ -1513,11 +1519,15 @@ out_fib6_main_tbl: #endif out_fib_table_hash: kfree(net->ipv6.fib_table_hash); +out_timer: + kfree(timer); goto out; } static void fib6_net_exit(struct net *net) { + del_timer(net->ipv6.ip6_fib_timer); + kfree(net->ipv6.ip6_fib_timer); #ifdef CONFIG_IPV6_MULTIPLE_TABLES kfree(net->ipv6.fib6_local_tbl); #endif @@ -1533,6 +1543,7 @@ static struct pernet_operations fib6_net_ops = { int __init fib6_init(void) { int ret = -ENOMEM; + fib6_node_kmem = kmem_cache_create("fib6_nodes", sizeof(struct fib6_node), 0, SLAB_HWCACHE_ALIGN, @@ -1540,16 +1551,9 @@ int __init fib6_init(void) if (!fib6_node_kmem) goto out; - ret = -ENOMEM; - ip6_fib_timer = kzalloc(sizeof(*ip6_fib_timer), GFP_KERNEL); - if (!ip6_fib_timer) - goto out_kmem_cache_create; - - setup_timer(ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)&init_net); - ret = register_pernet_subsys(&fib6_net_ops); if (ret) - goto out_timer; + goto out_kmem_cache_create; ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib); if (ret) @@ -1559,8 +1563,6 @@ out: out_unregister_subsys: unregister_pernet_subsys(&fib6_net_ops); -out_timer: - kfree(ip6_fib_timer); out_kmem_cache_create: kmem_cache_destroy(fib6_node_kmem); goto out; @@ -1568,8 +1570,6 @@ out_kmem_cache_create: void fib6_gc_cleanup(void) { - del_timer(ip6_fib_timer); - kfree(ip6_fib_timer); unregister_pernet_subsys(&fib6_net_ops); kmem_cache_destroy(fib6_node_kmem); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index fd44721abeb..b13eb011127 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -952,7 +952,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev, icmp6_dst_gc_list = &rt->u.dst; spin_unlock_bh(&icmp6_dst_lock); - fib6_force_start_gc(); + fib6_force_start_gc(dev->nd_net); out: return &rt->u.dst; @@ -1230,6 +1230,9 @@ install_route: rt->u.dst.dev = dev; rt->rt6i_idev = idev; rt->rt6i_table = table; + + cfg->fc_nlinfo.nl_net = dev->nd_net; + return __ip6_ins_rt(rt, &cfg->fc_nlinfo); out: