diff options
-rw-r--r-- | include/net/inetpeer.h | 9 | ||||
-rw-r--r-- | net/ipv4/inetpeer.c | 64 | ||||
-rw-r--r-- | net/ipv4/route.c | 25 | ||||
-rw-r--r-- | net/ipv6/route.c | 34 |
4 files changed, 83 insertions, 49 deletions
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 20e67db69ac9..5a96c8edc526 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h | |||
@@ -65,6 +65,14 @@ struct inet_peer { | |||
65 | atomic_t refcnt; | 65 | atomic_t refcnt; |
66 | }; | 66 | }; |
67 | 67 | ||
68 | struct inet_peer_base { | ||
69 | struct inet_peer __rcu *root; | ||
70 | seqlock_t lock; | ||
71 | int total; | ||
72 | }; | ||
73 | |||
74 | extern void inet_peer_base_init(struct inet_peer_base *); | ||
75 | |||
68 | void inet_initpeers(void) __init; | 76 | void inet_initpeers(void) __init; |
69 | 77 | ||
70 | #define INETPEER_METRICS_NEW (~(u32) 0) | 78 | #define INETPEER_METRICS_NEW (~(u32) 0) |
@@ -105,6 +113,7 @@ static inline struct inet_peer *inet_getpeer_v6(struct net *net, | |||
105 | extern void inet_putpeer(struct inet_peer *p); | 113 | extern void inet_putpeer(struct inet_peer *p); |
106 | extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); | 114 | extern bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); |
107 | 115 | ||
116 | extern void __inetpeer_invalidate_tree(struct inet_peer_base *); | ||
108 | extern void inetpeer_invalidate_tree(struct net *net, int family); | 117 | extern void inetpeer_invalidate_tree(struct net *net, int family); |
109 | 118 | ||
110 | /* | 119 | /* |
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 1c8527349c86..d0d72f89b279 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c | |||
@@ -82,11 +82,13 @@ static const struct inet_peer peer_fake_node = { | |||
82 | .avl_height = 0 | 82 | .avl_height = 0 |
83 | }; | 83 | }; |
84 | 84 | ||
85 | struct inet_peer_base { | 85 | void inet_peer_base_init(struct inet_peer_base *bp) |
86 | struct inet_peer __rcu *root; | 86 | { |
87 | seqlock_t lock; | 87 | bp->root = peer_avl_empty_rcu; |
88 | int total; | 88 | seqlock_init(&bp->lock); |
89 | }; | 89 | bp->total = 0; |
90 | } | ||
91 | EXPORT_SYMBOL_GPL(inet_peer_base_init); | ||
90 | 92 | ||
91 | #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ | 93 | #define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ |
92 | 94 | ||
@@ -141,46 +143,6 @@ static void inetpeer_gc_worker(struct work_struct *work) | |||
141 | schedule_delayed_work(&gc_work, gc_delay); | 143 | schedule_delayed_work(&gc_work, gc_delay); |
142 | } | 144 | } |
143 | 145 | ||
144 | static int __net_init inetpeer_net_init(struct net *net) | ||
145 | { | ||
146 | net->ipv4.peers = kzalloc(sizeof(struct inet_peer_base), | ||
147 | GFP_KERNEL); | ||
148 | if (net->ipv4.peers == NULL) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | net->ipv4.peers->root = peer_avl_empty_rcu; | ||
152 | seqlock_init(&net->ipv4.peers->lock); | ||
153 | |||
154 | net->ipv6.peers = kzalloc(sizeof(struct inet_peer_base), | ||
155 | GFP_KERNEL); | ||
156 | if (net->ipv6.peers == NULL) | ||
157 | goto out_ipv6; | ||
158 | |||
159 | net->ipv6.peers->root = peer_avl_empty_rcu; | ||
160 | seqlock_init(&net->ipv6.peers->lock); | ||
161 | |||
162 | return 0; | ||
163 | out_ipv6: | ||
164 | kfree(net->ipv4.peers); | ||
165 | return -ENOMEM; | ||
166 | } | ||
167 | |||
168 | static void __net_exit inetpeer_net_exit(struct net *net) | ||
169 | { | ||
170 | inetpeer_invalidate_tree(net, AF_INET); | ||
171 | kfree(net->ipv4.peers); | ||
172 | net->ipv4.peers = NULL; | ||
173 | |||
174 | inetpeer_invalidate_tree(net, AF_INET6); | ||
175 | kfree(net->ipv6.peers); | ||
176 | net->ipv6.peers = NULL; | ||
177 | } | ||
178 | |||
179 | static struct pernet_operations inetpeer_ops = { | ||
180 | .init = inetpeer_net_init, | ||
181 | .exit = inetpeer_net_exit, | ||
182 | }; | ||
183 | |||
184 | /* Called from ip_output.c:ip_init */ | 146 | /* Called from ip_output.c:ip_init */ |
185 | void __init inet_initpeers(void) | 147 | void __init inet_initpeers(void) |
186 | { | 148 | { |
@@ -205,7 +167,6 @@ void __init inet_initpeers(void) | |||
205 | NULL); | 167 | NULL); |
206 | 168 | ||
207 | INIT_DELAYED_WORK_DEFERRABLE(&gc_work, inetpeer_gc_worker); | 169 | INIT_DELAYED_WORK_DEFERRABLE(&gc_work, inetpeer_gc_worker); |
208 | register_pernet_subsys(&inetpeer_ops); | ||
209 | } | 170 | } |
210 | 171 | ||
211 | static int addr_compare(const struct inetpeer_addr *a, | 172 | static int addr_compare(const struct inetpeer_addr *a, |
@@ -603,10 +564,9 @@ static void inetpeer_inval_rcu(struct rcu_head *head) | |||
603 | schedule_delayed_work(&gc_work, gc_delay); | 564 | schedule_delayed_work(&gc_work, gc_delay); |
604 | } | 565 | } |
605 | 566 | ||
606 | void inetpeer_invalidate_tree(struct net *net, int family) | 567 | void __inetpeer_invalidate_tree(struct inet_peer_base *base) |
607 | { | 568 | { |
608 | struct inet_peer *old, *new, *prev; | 569 | struct inet_peer *old, *new, *prev; |
609 | struct inet_peer_base *base = family_to_base(net, family); | ||
610 | 570 | ||
611 | write_seqlock_bh(&base->lock); | 571 | write_seqlock_bh(&base->lock); |
612 | 572 | ||
@@ -625,4 +585,12 @@ void inetpeer_invalidate_tree(struct net *net, int family) | |||
625 | out: | 585 | out: |
626 | write_sequnlock_bh(&base->lock); | 586 | write_sequnlock_bh(&base->lock); |
627 | } | 587 | } |
588 | EXPORT_SYMBOL(__inetpeer_invalidate_tree); | ||
589 | |||
590 | void inetpeer_invalidate_tree(struct net *net, int family) | ||
591 | { | ||
592 | struct inet_peer_base *base = family_to_base(net, family); | ||
593 | |||
594 | __inetpeer_invalidate_tree(base); | ||
595 | } | ||
628 | EXPORT_SYMBOL(inetpeer_invalidate_tree); | 596 | EXPORT_SYMBOL(inetpeer_invalidate_tree); |
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 7a4d724765e6..4cd35c3904d4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -3385,6 +3385,30 @@ static __net_initdata struct pernet_operations rt_genid_ops = { | |||
3385 | .init = rt_genid_init, | 3385 | .init = rt_genid_init, |
3386 | }; | 3386 | }; |
3387 | 3387 | ||
3388 | static int __net_init ipv4_inetpeer_init(struct net *net) | ||
3389 | { | ||
3390 | struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL); | ||
3391 | |||
3392 | if (!bp) | ||
3393 | return -ENOMEM; | ||
3394 | inet_peer_base_init(bp); | ||
3395 | net->ipv4.peers = bp; | ||
3396 | return 0; | ||
3397 | } | ||
3398 | |||
3399 | static void __net_exit ipv4_inetpeer_exit(struct net *net) | ||
3400 | { | ||
3401 | struct inet_peer_base *bp = net->ipv4.peers; | ||
3402 | |||
3403 | net->ipv4.peers = NULL; | ||
3404 | __inetpeer_invalidate_tree(bp); | ||
3405 | kfree(bp); | ||
3406 | } | ||
3407 | |||
3408 | static __net_initdata struct pernet_operations ipv4_inetpeer_ops = { | ||
3409 | .init = ipv4_inetpeer_init, | ||
3410 | .exit = ipv4_inetpeer_exit, | ||
3411 | }; | ||
3388 | 3412 | ||
3389 | #ifdef CONFIG_IP_ROUTE_CLASSID | 3413 | #ifdef CONFIG_IP_ROUTE_CLASSID |
3390 | struct ip_rt_acct __percpu *ip_rt_acct __read_mostly; | 3414 | struct ip_rt_acct __percpu *ip_rt_acct __read_mostly; |
@@ -3465,6 +3489,7 @@ int __init ip_rt_init(void) | |||
3465 | register_pernet_subsys(&sysctl_route_ops); | 3489 | register_pernet_subsys(&sysctl_route_ops); |
3466 | #endif | 3490 | #endif |
3467 | register_pernet_subsys(&rt_genid_ops); | 3491 | register_pernet_subsys(&rt_genid_ops); |
3492 | register_pernet_subsys(&ipv4_inetpeer_ops); | ||
3468 | return rc; | 3493 | return rc; |
3469 | } | 3494 | } |
3470 | 3495 | ||
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8a986be4aeda..3e1e4e0da096 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -2996,6 +2996,31 @@ static struct pernet_operations ip6_route_net_ops = { | |||
2996 | .exit = ip6_route_net_exit, | 2996 | .exit = ip6_route_net_exit, |
2997 | }; | 2997 | }; |
2998 | 2998 | ||
2999 | static int __net_init ipv6_inetpeer_init(struct net *net) | ||
3000 | { | ||
3001 | struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL); | ||
3002 | |||
3003 | if (!bp) | ||
3004 | return -ENOMEM; | ||
3005 | inet_peer_base_init(bp); | ||
3006 | net->ipv6.peers = bp; | ||
3007 | return 0; | ||
3008 | } | ||
3009 | |||
3010 | static void __net_exit ipv6_inetpeer_exit(struct net *net) | ||
3011 | { | ||
3012 | struct inet_peer_base *bp = net->ipv6.peers; | ||
3013 | |||
3014 | net->ipv6.peers = NULL; | ||
3015 | __inetpeer_invalidate_tree(bp); | ||
3016 | kfree(bp); | ||
3017 | } | ||
3018 | |||
3019 | static __net_initdata struct pernet_operations ipv6_inetpeer_ops = { | ||
3020 | .init = ipv6_inetpeer_init, | ||
3021 | .exit = ipv6_inetpeer_exit, | ||
3022 | }; | ||
3023 | |||
2999 | static struct notifier_block ip6_route_dev_notifier = { | 3024 | static struct notifier_block ip6_route_dev_notifier = { |
3000 | .notifier_call = ip6_route_dev_notify, | 3025 | .notifier_call = ip6_route_dev_notify, |
3001 | .priority = 0, | 3026 | .priority = 0, |
@@ -3020,6 +3045,10 @@ int __init ip6_route_init(void) | |||
3020 | if (ret) | 3045 | if (ret) |
3021 | goto out_dst_entries; | 3046 | goto out_dst_entries; |
3022 | 3047 | ||
3048 | ret = register_pernet_subsys(&ipv6_inetpeer_ops); | ||
3049 | if (ret) | ||
3050 | goto out_register_subsys; | ||
3051 | |||
3023 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; | 3052 | ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; |
3024 | 3053 | ||
3025 | /* Registering of the loopback is done before this portion of code, | 3054 | /* Registering of the loopback is done before this portion of code, |
@@ -3035,7 +3064,7 @@ int __init ip6_route_init(void) | |||
3035 | #endif | 3064 | #endif |
3036 | ret = fib6_init(); | 3065 | ret = fib6_init(); |
3037 | if (ret) | 3066 | if (ret) |
3038 | goto out_register_subsys; | 3067 | goto out_register_inetpeer; |
3039 | 3068 | ||
3040 | ret = xfrm6_init(); | 3069 | ret = xfrm6_init(); |
3041 | if (ret) | 3070 | if (ret) |
@@ -3064,6 +3093,8 @@ xfrm6_init: | |||
3064 | xfrm6_fini(); | 3093 | xfrm6_fini(); |
3065 | out_fib6_init: | 3094 | out_fib6_init: |
3066 | fib6_gc_cleanup(); | 3095 | fib6_gc_cleanup(); |
3096 | out_register_inetpeer: | ||
3097 | unregister_pernet_subsys(&ipv6_inetpeer_ops); | ||
3067 | out_register_subsys: | 3098 | out_register_subsys: |
3068 | unregister_pernet_subsys(&ip6_route_net_ops); | 3099 | unregister_pernet_subsys(&ip6_route_net_ops); |
3069 | out_dst_entries: | 3100 | out_dst_entries: |
@@ -3079,6 +3110,7 @@ void ip6_route_cleanup(void) | |||
3079 | fib6_rules_cleanup(); | 3110 | fib6_rules_cleanup(); |
3080 | xfrm6_fini(); | 3111 | xfrm6_fini(); |
3081 | fib6_gc_cleanup(); | 3112 | fib6_gc_cleanup(); |
3113 | unregister_pernet_subsys(&ipv6_inetpeer_ops); | ||
3082 | unregister_pernet_subsys(&ip6_route_net_ops); | 3114 | unregister_pernet_subsys(&ip6_route_net_ops); |
3083 | dst_entries_destroy(&ip6_dst_blackhole_ops); | 3115 | dst_entries_destroy(&ip6_dst_blackhole_ops); |
3084 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); | 3116 | kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); |