diff options
author | Daniel Lezcano <dlezcano@fr.ibm.com> | 2008-03-04 16:48:53 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-04 16:48:53 -0500 |
commit | 9a7ec3a94d8da475fe81810aa55136a81556d445 (patch) | |
tree | 57a241a178d5d60b14a00e1c77a37060fbf8e00a /net | |
parent | 8ed677896752fff056f6cf3d7ce462adc6c464f0 (diff) |
[NETNS][IPV6] route6 - dynamically allocate ip6_dst_ops
ip6_dst_ops is dynamically allocated in init and exit functions. That
provides the ability to do multiple instanciations of this structure.
This will be needed for network namespaces, indeed dst_ops stores data
that are required to be per namespace: entries and gc_thresh.
Signed-off-by: Benjamin Thery <benjamin.thery@bull.net>
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv6/route.c | 47 |
1 files changed, 29 insertions, 18 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7ff66cebe77c..fa014d701c1a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -97,7 +97,7 @@ static struct rt6_info *rt6_get_route_info(struct net *net, | |||
97 | struct in6_addr *gwaddr, int ifindex); | 97 | struct in6_addr *gwaddr, int ifindex); |
98 | #endif | 98 | #endif |
99 | 99 | ||
100 | static struct dst_ops ip6_dst_ops = { | 100 | static struct dst_ops ip6_dst_ops_template = { |
101 | .family = AF_INET6, | 101 | .family = AF_INET6, |
102 | .protocol = __constant_htons(ETH_P_IPV6), | 102 | .protocol = __constant_htons(ETH_P_IPV6), |
103 | .gc = ip6_dst_gc, | 103 | .gc = ip6_dst_gc, |
@@ -113,6 +113,8 @@ static struct dst_ops ip6_dst_ops = { | |||
113 | .entries = ATOMIC_INIT(0), | 113 | .entries = ATOMIC_INIT(0), |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static struct dst_ops *ip6_dst_ops; | ||
117 | |||
116 | static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) | 118 | static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) |
117 | { | 119 | { |
118 | } | 120 | } |
@@ -137,7 +139,6 @@ static struct rt6_info ip6_null_entry_template = { | |||
137 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | 139 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, |
138 | .input = ip6_pkt_discard, | 140 | .input = ip6_pkt_discard, |
139 | .output = ip6_pkt_discard_out, | 141 | .output = ip6_pkt_discard_out, |
140 | .ops = &ip6_dst_ops, | ||
141 | } | 142 | } |
142 | }, | 143 | }, |
143 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 144 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
@@ -160,7 +161,6 @@ struct rt6_info ip6_prohibit_entry_template = { | |||
160 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | 161 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, |
161 | .input = ip6_pkt_prohibit, | 162 | .input = ip6_pkt_prohibit, |
162 | .output = ip6_pkt_prohibit_out, | 163 | .output = ip6_pkt_prohibit_out, |
163 | .ops = &ip6_dst_ops, | ||
164 | } | 164 | } |
165 | }, | 165 | }, |
166 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 166 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
@@ -178,7 +178,6 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
178 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, | 178 | .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, |
179 | .input = dst_discard, | 179 | .input = dst_discard, |
180 | .output = dst_discard, | 180 | .output = dst_discard, |
181 | .ops = &ip6_dst_ops, | ||
182 | } | 181 | } |
183 | }, | 182 | }, |
184 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 183 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
@@ -191,7 +190,7 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
191 | /* allocate dst with ip6_dst_ops */ | 190 | /* allocate dst with ip6_dst_ops */ |
192 | static __inline__ struct rt6_info *ip6_dst_alloc(void) | 191 | static __inline__ struct rt6_info *ip6_dst_alloc(void) |
193 | { | 192 | { |
194 | return (struct rt6_info *)dst_alloc(&ip6_dst_ops); | 193 | return (struct rt6_info *)dst_alloc(ip6_dst_ops); |
195 | } | 194 | } |
196 | 195 | ||
197 | static void ip6_dst_destroy(struct dst_entry *dst) | 196 | static void ip6_dst_destroy(struct dst_entry *dst) |
@@ -1000,18 +999,18 @@ static int ip6_dst_gc(struct dst_ops *ops) | |||
1000 | unsigned long now = jiffies; | 999 | unsigned long now = jiffies; |
1001 | 1000 | ||
1002 | if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) && | 1001 | if (time_after(last_gc + init_net.ipv6.sysctl.ip6_rt_gc_min_interval, now) && |
1003 | atomic_read(&ip6_dst_ops.entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) | 1002 | atomic_read(&ip6_dst_ops->entries) <= init_net.ipv6.sysctl.ip6_rt_max_size) |
1004 | goto out; | 1003 | goto out; |
1005 | 1004 | ||
1006 | expire++; | 1005 | expire++; |
1007 | fib6_run_gc(expire, &init_net); | 1006 | fib6_run_gc(expire, &init_net); |
1008 | last_gc = now; | 1007 | last_gc = now; |
1009 | if (atomic_read(&ip6_dst_ops.entries) < ip6_dst_ops.gc_thresh) | 1008 | if (atomic_read(&ip6_dst_ops->entries) < ip6_dst_ops->gc_thresh) |
1010 | expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1; | 1009 | expire = init_net.ipv6.sysctl.ip6_rt_gc_timeout>>1; |
1011 | 1010 | ||
1012 | out: | 1011 | out: |
1013 | expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity; | 1012 | expire -= expire>>init_net.ipv6.sysctl.ip6_rt_gc_elasticity; |
1014 | return (atomic_read(&ip6_dst_ops.entries) > init_net.ipv6.sysctl.ip6_rt_max_size); | 1013 | return (atomic_read(&ip6_dst_ops->entries) > init_net.ipv6.sysctl.ip6_rt_max_size); |
1015 | } | 1014 | } |
1016 | 1015 | ||
1017 | /* Clean host part of a prefix. Not necessary in radix tree, | 1016 | /* Clean host part of a prefix. Not necessary in radix tree, |
@@ -2408,7 +2407,7 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) | |||
2408 | net->ipv6.rt6_stats->fib_rt_alloc, | 2407 | net->ipv6.rt6_stats->fib_rt_alloc, |
2409 | net->ipv6.rt6_stats->fib_rt_entries, | 2408 | net->ipv6.rt6_stats->fib_rt_entries, |
2410 | net->ipv6.rt6_stats->fib_rt_cache, | 2409 | net->ipv6.rt6_stats->fib_rt_cache, |
2411 | atomic_read(&ip6_dst_ops.entries), | 2410 | atomic_read(&ip6_dst_ops->entries), |
2412 | net->ipv6.rt6_stats->fib_discarded_routes); | 2411 | net->ipv6.rt6_stats->fib_discarded_routes); |
2413 | 2412 | ||
2414 | return 0; | 2413 | return 0; |
@@ -2464,7 +2463,7 @@ ctl_table ipv6_route_table_template[] = { | |||
2464 | { | 2463 | { |
2465 | .ctl_name = NET_IPV6_ROUTE_GC_THRESH, | 2464 | .ctl_name = NET_IPV6_ROUTE_GC_THRESH, |
2466 | .procname = "gc_thresh", | 2465 | .procname = "gc_thresh", |
2467 | .data = &ip6_dst_ops.gc_thresh, | 2466 | .data = &ip6_dst_ops_template.gc_thresh, |
2468 | .maxlen = sizeof(int), | 2467 | .maxlen = sizeof(int), |
2469 | .mode = 0644, | 2468 | .mode = 0644, |
2470 | .proc_handler = &proc_dointvec, | 2469 | .proc_handler = &proc_dointvec, |
@@ -2553,8 +2552,7 @@ struct ctl_table *ipv6_route_sysctl_init(struct net *net) | |||
2553 | 2552 | ||
2554 | if (table) { | 2553 | if (table) { |
2555 | table[0].data = &net->ipv6.sysctl.flush_delay; | 2554 | table[0].data = &net->ipv6.sysctl.flush_delay; |
2556 | /* table[1].data will be handled when we have | 2555 | table[1].data = &ip6_dst_ops_template.gc_thresh; |
2557 | routes per namespace */ | ||
2558 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; | 2556 | table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; |
2559 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; | 2557 | table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; |
2560 | table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; | 2558 | table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; |
@@ -2580,6 +2578,7 @@ static int ip6_route_net_init(struct net *net) | |||
2580 | goto out; | 2578 | goto out; |
2581 | net->ipv6.ip6_null_entry->u.dst.path = | 2579 | net->ipv6.ip6_null_entry->u.dst.path = |
2582 | (struct dst_entry *)net->ipv6.ip6_null_entry; | 2580 | (struct dst_entry *)net->ipv6.ip6_null_entry; |
2581 | net->ipv6.ip6_null_entry->u.dst.ops = ip6_dst_ops; | ||
2583 | 2582 | ||
2584 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES | 2583 | #ifdef CONFIG_IPV6_MULTIPLE_TABLES |
2585 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, | 2584 | net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, |
@@ -2591,6 +2590,7 @@ static int ip6_route_net_init(struct net *net) | |||
2591 | } | 2590 | } |
2592 | net->ipv6.ip6_prohibit_entry->u.dst.path = | 2591 | net->ipv6.ip6_prohibit_entry->u.dst.path = |
2593 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; | 2592 | (struct dst_entry *)net->ipv6.ip6_prohibit_entry; |
2593 | net->ipv6.ip6_prohibit_entry->u.dst.ops = ip6_dst_ops; | ||
2594 | 2594 | ||
2595 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, | 2595 | net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, |
2596 | sizeof(*net->ipv6.ip6_blk_hole_entry), | 2596 | sizeof(*net->ipv6.ip6_blk_hole_entry), |
@@ -2602,6 +2602,7 @@ static int ip6_route_net_init(struct net *net) | |||
2602 | } | 2602 | } |
2603 | net->ipv6.ip6_blk_hole_entry->u.dst.path = | 2603 | net->ipv6.ip6_blk_hole_entry->u.dst.path = |
2604 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; | 2604 | (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; |
2605 | net->ipv6.ip6_blk_hole_entry->u.dst.ops = ip6_dst_ops; | ||
2605 | #endif | 2606 | #endif |
2606 | 2607 | ||
2607 | #ifdef CONFIG_PROC_FS | 2608 | #ifdef CONFIG_PROC_FS |
@@ -2640,13 +2641,20 @@ int __init ip6_route_init(void) | |||
2640 | { | 2641 | { |
2641 | int ret; | 2642 | int ret; |
2642 | 2643 | ||
2643 | ip6_dst_ops.kmem_cachep = | 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; | ||
2650 | ip6_dst_ops_template.kmem_cachep = | ||
2644 | kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, | 2651 | kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, |
2645 | SLAB_HWCACHE_ALIGN, NULL); | 2652 | SLAB_HWCACHE_ALIGN, NULL); |
2646 | if (!ip6_dst_ops.kmem_cachep) | 2653 | if (!ip6_dst_ops_template.kmem_cachep) |
2647 | return -ENOMEM; | 2654 | goto out_ip6_dst_ops; |
2648 | 2655 | ||
2649 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; | 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; | ||
2650 | 2658 | ||
2651 | ret = register_pernet_subsys(&ip6_route_net_ops); | 2659 | ret = register_pernet_subsys(&ip6_route_net_ops); |
2652 | if (ret) | 2660 | if (ret) |
@@ -2697,7 +2705,9 @@ out_fib6_init: | |||
2697 | out_register_subsys: | 2705 | out_register_subsys: |
2698 | unregister_pernet_subsys(&ip6_route_net_ops); | 2706 | unregister_pernet_subsys(&ip6_route_net_ops); |
2699 | out_kmem_cache: | 2707 | out_kmem_cache: |
2700 | kmem_cache_destroy(ip6_dst_ops.kmem_cachep); | 2708 | kmem_cache_destroy(ip6_dst_ops->kmem_cachep); |
2709 | out_ip6_dst_ops: | ||
2710 | kfree(ip6_dst_ops); | ||
2701 | goto out; | 2711 | goto out; |
2702 | } | 2712 | } |
2703 | 2713 | ||
@@ -2708,5 +2718,6 @@ void ip6_route_cleanup(void) | |||
2708 | xfrm6_fini(); | 2718 | xfrm6_fini(); |
2709 | fib6_gc_cleanup(); | 2719 | fib6_gc_cleanup(); |
2710 | unregister_pernet_subsys(&ip6_route_net_ops); | 2720 | unregister_pernet_subsys(&ip6_route_net_ops); |
2711 | kmem_cache_destroy(ip6_dst_ops.kmem_cachep); | 2721 | kmem_cache_destroy(ip6_dst_ops->kmem_cachep); |
2722 | kfree(ip6_dst_ops); | ||
2712 | } | 2723 | } |