aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netns/ipv6.h1
-rw-r--r--net/ipv6/route.c62
2 files changed, 32 insertions, 31 deletions
diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index 311a942f36e9..53b5a283a4b3 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -41,6 +41,7 @@ struct netns_ipv6 {
41 struct timer_list *ip6_fib_timer; 41 struct timer_list *ip6_fib_timer;
42 struct hlist_head *fib_table_hash; 42 struct hlist_head *fib_table_hash;
43 struct fib6_table *fib6_main_tbl; 43 struct fib6_table *fib6_main_tbl;
44 struct dst_ops *ip6_dst_ops;
44#ifdef CONFIG_IPV6_MULTIPLE_TABLES 45#ifdef CONFIG_IPV6_MULTIPLE_TABLES
45 struct rt6_info *ip6_prohibit_entry; 46 struct rt6_info *ip6_prohibit_entry;
46 struct rt6_info *ip6_blk_hole_entry; 47 struct rt6_info *ip6_blk_hole_entry;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index fa014d701c1a..d88b6ec3c5d1 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -113,8 +113,6 @@ static struct dst_ops ip6_dst_ops_template = {
113 .entries = ATOMIC_INIT(0), 113 .entries = ATOMIC_INIT(0),
114}; 114};
115 115
116static struct dst_ops *ip6_dst_ops;
117
118static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) 116static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu)
119{ 117{
120} 118}
@@ -188,9 +186,9 @@ static struct rt6_info ip6_blk_hole_entry_template = {
188#endif 186#endif
189 187
190/* allocate dst with ip6_dst_ops */ 188/* allocate dst with ip6_dst_ops */
191static __inline__ struct rt6_info *ip6_dst_alloc(void) 189static inline struct rt6_info *ip6_dst_alloc(struct dst_ops *ops)
192{ 190{
193 return (struct rt6_info *)dst_alloc(ip6_dst_ops); 191 return (struct rt6_info *)dst_alloc(ops);
194} 192}
195 193
196static void ip6_dst_destroy(struct dst_entry *dst) 194static void ip6_dst_destroy(struct dst_entry *dst)
@@ -925,7 +923,7 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
925 if (unlikely(idev == NULL)) 923 if (unlikely(idev == NULL))
926 return NULL; 924 return NULL;
927 925
928 rt = ip6_dst_alloc(); 926 rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
929 if (unlikely(rt == NULL)) { 927 if (unlikely(rt == NULL)) {
930 in6_dev_put(idev); 928 in6_dev_put(idev);
931 goto out; 929 goto out;
@@ -999,18 +997,18 @@ static int ip6_dst_gc(struct dst_ops *ops)
999 unsigned long now = jiffies; 997 unsigned long now = jiffies;
1000 998
1001 if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) && 999 if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) &&
1002 atomic_read(&ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) 1000 atomic_read(&init_net.ipv6.ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size)
1003 goto out; 1001 goto out;
1004 1002
1005 expire++; 1003 expire++;
1006 fib6_run_gc(expire, &init_net); 1004 fib6_run_gc(expire, &init_net);
1007 last_gc = now; 1005 last_gc = now;
1008 if (atomic_read(&ip6_dst_ops->entries) < ip6_dst_ops->gc_thresh) 1006 if (atomic_read(&init_net.ipv6.ip6_dst_ops->entries) < init_net.ipv6.ip6_dst_ops->gc_thresh)
1009 expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1; 1007 expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1;
1010 1008
1011out: 1009out:
1012 expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity; 1010 expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity;
1013 return (atomic_read(&ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size); 1011 return (atomic_read(&init_net.ipv6.ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size);
1014} 1012}
1015 1013
1016/* Clean host part of a prefix. Not necessary in radix tree, 1014/* Clean host part of a prefix. Not necessary in radix tree,
@@ -1084,7 +1082,7 @@ int ip6_route_add(struct fib6_config *cfg)
1084 goto out; 1082 goto out;
1085 } 1083 }
1086 1084
1087 rt = ip6_dst_alloc(); 1085 rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
1088 1086
1089 if (rt == NULL) { 1087 if (rt == NULL) {
1090 err = -ENOMEM; 1088 err = -ENOMEM;
@@ -1570,7 +1568,8 @@ out:
1570 1568
1571static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) 1569static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
1572{ 1570{
1573 struct rt6_info *rt = ip6_dst_alloc(); 1571 struct net *net = ort->rt6i_dev->nd_net;
1572 struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
1574 1573
1575 if (rt) { 1574 if (rt) {
1576 rt->u.dst.input = ort->u.dst.input; 1575 rt->u.dst.input = ort->u.dst.input;
@@ -1849,7 +1848,7 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
1849 int anycast) 1848 int anycast)
1850{ 1849{
1851 struct net *net = idev->dev->nd_net; 1850 struct net *net = idev->dev->nd_net;
1852 struct rt6_info *rt = ip6_dst_alloc(); 1851 struct rt6_info *rt = ip6_dst_alloc(net->ipv6.ip6_dst_ops);
1853 1852
1854 if (rt == NULL) 1853 if (rt == NULL)
1855 return ERR_PTR(-ENOMEM); 1854 return ERR_PTR(-ENOMEM);
@@ -2407,7 +2406,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v)
2407 net->ipv6.rt6_stats->fib_rt_alloc, 2406 net->ipv6.rt6_stats->fib_rt_alloc,
2408 net->ipv6.rt6_stats->fib_rt_entries, 2407 net->ipv6.rt6_stats->fib_rt_entries,
2409 net->ipv6.rt6_stats->fib_rt_cache, 2408 net->ipv6.rt6_stats->fib_rt_cache,
2410 atomic_read(&ip6_dst_ops->entries), 2409 atomic_read(&net->ipv6.ip6_dst_ops->entries),
2411 net->ipv6.rt6_stats->fib_discarded_routes); 2410 net->ipv6.rt6_stats->fib_discarded_routes);
2412 2411
2413 return 0; 2412 return 0;
@@ -2552,7 +2551,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net)
2552 2551
2553 if (table) { 2552 if (table) {
2554 table[0].data = &net->ipv6.sysctl.flush_delay; 2553 table[0].data = &net->ipv6.sysctl.flush_delay;
2555 table[1].data = &ip6_dst_ops_template.gc_thresh; 2554 table[1].data = &net->ipv6.ip6_dst_ops->gc_thresh;
2556 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; 2555 table[2].data = &net->ipv6.sysctl.ip6_rt_max_size;
2557 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; 2556 table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval;
2558 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; 2557 table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout;
@@ -2571,14 +2570,21 @@ static int ip6_route_net_init(struct net *net)
2571 int ret = 0; 2570 int ret = 0;
2572 2571
2573 ret = -ENOMEM; 2572 ret = -ENOMEM;
2573 net->ipv6.ip6_dst_ops = kmemdup(&ip6_dst_ops_template,
2574 sizeof(*net->ipv6.ip6_dst_ops),
2575 GFP_KERNEL);
2576 if (!net->ipv6.ip6_dst_ops)
2577 goto out;
2578 net->ipv6.ip6_dst_ops->dst_net = net;
2579
2574 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, 2580 net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template,
2575 sizeof(*net->ipv6.ip6_null_entry), 2581 sizeof(*net->ipv6.ip6_null_entry),
2576 GFP_KERNEL); 2582 GFP_KERNEL);
2577 if (!net->ipv6.ip6_null_entry) 2583 if (!net->ipv6.ip6_null_entry)
2578 goto out; 2584 goto out_ip6_dst_ops;
2579 net->ipv6.ip6_null_entry->u.dst.path = 2585 net->ipv6.ip6_null_entry->u.dst.path =
2580 (struct dst_entry *)net->ipv6.ip6_null_entry; 2586 (struct dst_entry *)net->ipv6.ip6_null_entry;
2581 net->ipv6.ip6_null_entry->u.dst.ops = ip6_dst_ops; 2587 net->ipv6.ip6_null_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
2582 2588
2583#ifdef CONFIG_IPV6_MULTIPLE_TABLES 2589#ifdef CONFIG_IPV6_MULTIPLE_TABLES
2584 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, 2590 net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
@@ -2590,7 +2596,7 @@ static int ip6_route_net_init(struct net *net)
2590 } 2596 }
2591 net->ipv6.ip6_prohibit_entry->u.dst.path = 2597 net->ipv6.ip6_prohibit_entry->u.dst.path =
2592 (struct dst_entry *)net->ipv6.ip6_prohibit_entry; 2598 (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
2593 net->ipv6.ip6_prohibit_entry->u.dst.ops = ip6_dst_ops; 2599 net->ipv6.ip6_prohibit_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
2594 2600
2595 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, 2601 net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
2596 sizeof(*net->ipv6.ip6_blk_hole_entry), 2602 sizeof(*net->ipv6.ip6_blk_hole_entry),
@@ -2602,7 +2608,7 @@ static int ip6_route_net_init(struct net *net)
2602 } 2608 }
2603 net->ipv6.ip6_blk_hole_entry->u.dst.path = 2609 net->ipv6.ip6_blk_hole_entry->u.dst.path =
2604 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; 2610 (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
2605 net->ipv6.ip6_blk_hole_entry->u.dst.ops = ip6_dst_ops; 2611 net->ipv6.ip6_blk_hole_entry->u.dst.ops = net->ipv6.ip6_dst_ops;
2606#endif 2612#endif
2607 2613
2608#ifdef CONFIG_PROC_FS 2614#ifdef CONFIG_PROC_FS
@@ -2612,6 +2618,10 @@ static int ip6_route_net_init(struct net *net)
2612 ret = 0; 2618 ret = 0;
2613out: 2619out:
2614 return ret; 2620 return ret;
2621
2622out_ip6_dst_ops:
2623 kfree(net->ipv6.ip6_dst_ops);
2624 goto out;
2615} 2625}
2616 2626
2617static void ip6_route_net_exit(struct net *net) 2627static void ip6_route_net_exit(struct net *net)
@@ -2625,6 +2635,7 @@ static void ip6_route_net_exit(struct net *net)
2625 kfree(net->ipv6.ip6_prohibit_entry); 2635 kfree(net->ipv6.ip6_prohibit_entry);
2626 kfree(net->ipv6.ip6_blk_hole_entry); 2636 kfree(net->ipv6.ip6_blk_hole_entry);
2627#endif 2637#endif
2638 kfree(net->ipv6.ip6_dst_ops);
2628} 2639}
2629 2640
2630static struct pernet_operations ip6_route_net_ops = { 2641static struct pernet_operations ip6_route_net_ops = {
@@ -2641,20 +2652,12 @@ int __init ip6_route_init(void)
2641{ 2652{
2642 int ret; 2653 int ret;
2643 2654
2644 ip6_dst_ops = kmemdup(&ip6_dst_ops_template,
2645 sizeof(*ip6_dst_ops), GFP_KERNEL);
2646 if (!ip6_dst_ops)
2647 return -ENOMEM;
2648
2649 ret = -ENOMEM; 2655 ret = -ENOMEM;
2650 ip6_dst_ops_template.kmem_cachep = 2656 ip6_dst_ops_template.kmem_cachep =
2651 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, 2657 kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0,
2652 SLAB_HWCACHE_ALIGN, NULL); 2658 SLAB_HWCACHE_ALIGN, NULL);
2653 if (!ip6_dst_ops_template.kmem_cachep) 2659 if (!ip6_dst_ops_template.kmem_cachep)
2654 goto out_ip6_dst_ops; 2660 goto out;;
2655
2656 ip6_dst_ops->kmem_cachep = ip6_dst_ops_template.kmem_cachep;
2657 ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep;
2658 2661
2659 ret = register_pernet_subsys(&ip6_route_net_ops); 2662 ret = register_pernet_subsys(&ip6_route_net_ops);
2660 if (ret) 2663 if (ret)
@@ -2705,9 +2708,7 @@ out_fib6_init:
2705out_register_subsys: 2708out_register_subsys:
2706 unregister_pernet_subsys(&ip6_route_net_ops); 2709 unregister_pernet_subsys(&ip6_route_net_ops);
2707out_kmem_cache: 2710out_kmem_cache:
2708 kmem_cache_destroy(ip6_dst_ops->kmem_cachep); 2711 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
2709out_ip6_dst_ops:
2710 kfree(ip6_dst_ops);
2711 goto out; 2712 goto out;
2712} 2713}
2713 2714
@@ -2718,6 +2719,5 @@ void ip6_route_cleanup(void)
2718 xfrm6_fini(); 2719 xfrm6_fini();
2719 fib6_gc_cleanup(); 2720 fib6_gc_cleanup();
2720 unregister_pernet_subsys(&ip6_route_net_ops); 2721 unregister_pernet_subsys(&ip6_route_net_ops);
2721 kmem_cache_destroy(ip6_dst_ops->kmem_cachep); 2722 kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep);
2722 kfree(ip6_dst_ops);
2723} 2723}