aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/xfrm6_tunnel.c
diff options
context:
space:
mode:
authorAlexey Dobriyan <adobriyan@gmail.com>2010-01-25 05:37:54 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-28 09:31:05 -0500
commita1664773907a2b69e2a3019598dcbeffa6bc724b (patch)
tree77070892675e29de901587a4f55bbc620b20e211 /net/ipv6/xfrm6_tunnel.c
parente924960dacdf85d118a98c7262edf2f99c3015cf (diff)
netns xfrm: xfrm6_tunnel in netns
I'm not sure about rcu stuff near kmem cache destruction: * checks for non-empty hashes look bogus, they're done _before_ rcu_berrier() * unregistering netns ops is done before kmem_cache destoy (as it should), and unregistering involves rcu barriers by itself So it looks nothing should be done. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/xfrm6_tunnel.c')
-rw-r--r--net/ipv6/xfrm6_tunnel.c140
1 files changed, 83 insertions, 57 deletions
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 23fb1002124c..d6f9aeec69f7 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -30,6 +30,25 @@
30#include <linux/ipv6.h> 30#include <linux/ipv6.h>
31#include <linux/icmpv6.h> 31#include <linux/icmpv6.h>
32#include <linux/mutex.h> 32#include <linux/mutex.h>
33#include <net/netns/generic.h>
34
35#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
36#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
37
38#define XFRM6_TUNNEL_SPI_MIN 1
39#define XFRM6_TUNNEL_SPI_MAX 0xffffffff
40
41struct xfrm6_tunnel_net {
42 struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
43 struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
44 u32 spi;
45};
46
47static int xfrm6_tunnel_net_id __read_mostly;
48static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net)
49{
50 return net_generic(net, xfrm6_tunnel_net_id);
51}
33 52
34/* 53/*
35 * xfrm_tunnel_spi things are for allocating unique id ("spi") 54 * xfrm_tunnel_spi things are for allocating unique id ("spi")
@@ -46,19 +65,8 @@ struct xfrm6_tunnel_spi {
46 65
47static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); 66static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock);
48 67
49static u32 xfrm6_tunnel_spi;
50
51#define XFRM6_TUNNEL_SPI_MIN 1
52#define XFRM6_TUNNEL_SPI_MAX 0xffffffff
53
54static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; 68static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly;
55 69
56#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256
57#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256
58
59static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
60static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
61
62static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) 70static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr)
63{ 71{
64 unsigned h; 72 unsigned h;
@@ -77,49 +85,30 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi)
77} 85}
78 86
79 87
80static int xfrm6_tunnel_spi_init(void) 88static int __init xfrm6_tunnel_spi_init(void)
81{ 89{
82 int i;
83
84 xfrm6_tunnel_spi = 0;
85 xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", 90 xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
86 sizeof(struct xfrm6_tunnel_spi), 91 sizeof(struct xfrm6_tunnel_spi),
87 0, SLAB_HWCACHE_ALIGN, 92 0, SLAB_HWCACHE_ALIGN,
88 NULL); 93 NULL);
89 if (!xfrm6_tunnel_spi_kmem) 94 if (!xfrm6_tunnel_spi_kmem)
90 return -ENOMEM; 95 return -ENOMEM;
91
92 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
93 INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]);
94 for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
95 INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]);
96 return 0; 96 return 0;
97} 97}
98 98
99static void xfrm6_tunnel_spi_fini(void) 99static void xfrm6_tunnel_spi_fini(void)
100{ 100{
101 int i;
102
103 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) {
104 if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i]))
105 return;
106 }
107 for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) {
108 if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i]))
109 return;
110 }
111 rcu_barrier();
112 kmem_cache_destroy(xfrm6_tunnel_spi_kmem); 101 kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
113 xfrm6_tunnel_spi_kmem = NULL;
114} 102}
115 103
116static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) 104static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
117{ 105{
106 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
118 struct xfrm6_tunnel_spi *x6spi; 107 struct xfrm6_tunnel_spi *x6spi;
119 struct hlist_node *pos; 108 struct hlist_node *pos;
120 109
121 hlist_for_each_entry_rcu(x6spi, pos, 110 hlist_for_each_entry_rcu(x6spi, pos,
122 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], 111 &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
123 list_byaddr) { 112 list_byaddr) {
124 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) 113 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0)
125 return x6spi; 114 return x6spi;
@@ -128,13 +117,13 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
128 return NULL; 117 return NULL;
129} 118}
130 119
131__be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) 120__be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
132{ 121{
133 struct xfrm6_tunnel_spi *x6spi; 122 struct xfrm6_tunnel_spi *x6spi;
134 u32 spi; 123 u32 spi;
135 124
136 rcu_read_lock_bh(); 125 rcu_read_lock_bh();
137 x6spi = __xfrm6_tunnel_spi_lookup(saddr); 126 x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
138 spi = x6spi ? x6spi->spi : 0; 127 spi = x6spi ? x6spi->spi : 0;
139 rcu_read_unlock_bh(); 128 rcu_read_unlock_bh();
140 return htonl(spi); 129 return htonl(spi);
@@ -142,14 +131,15 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
142 131
143EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); 132EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
144 133
145static int __xfrm6_tunnel_spi_check(u32 spi) 134static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi)
146{ 135{
136 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
147 struct xfrm6_tunnel_spi *x6spi; 137 struct xfrm6_tunnel_spi *x6spi;
148 int index = xfrm6_tunnel_spi_hash_byspi(spi); 138 int index = xfrm6_tunnel_spi_hash_byspi(spi);
149 struct hlist_node *pos; 139 struct hlist_node *pos;
150 140
151 hlist_for_each_entry(x6spi, pos, 141 hlist_for_each_entry(x6spi, pos,
152 &xfrm6_tunnel_spi_byspi[index], 142 &xfrm6_tn->spi_byspi[index],
153 list_byspi) { 143 list_byspi) {
154 if (x6spi->spi == spi) 144 if (x6spi->spi == spi)
155 return -1; 145 return -1;
@@ -157,32 +147,33 @@ static int __xfrm6_tunnel_spi_check(u32 spi)
157 return index; 147 return index;
158} 148}
159 149
160static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) 150static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
161{ 151{
152 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
162 u32 spi; 153 u32 spi;
163 struct xfrm6_tunnel_spi *x6spi; 154 struct xfrm6_tunnel_spi *x6spi;
164 int index; 155 int index;
165 156
166 if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || 157 if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN ||
167 xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) 158 xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX)
168 xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; 159 xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN;
169 else 160 else
170 xfrm6_tunnel_spi++; 161 xfrm6_tn->spi++;
171 162
172 for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { 163 for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
173 index = __xfrm6_tunnel_spi_check(spi); 164 index = __xfrm6_tunnel_spi_check(net, spi);
174 if (index >= 0) 165 if (index >= 0)
175 goto alloc_spi; 166 goto alloc_spi;
176 } 167 }
177 for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { 168 for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) {
178 index = __xfrm6_tunnel_spi_check(spi); 169 index = __xfrm6_tunnel_spi_check(net, spi);
179 if (index >= 0) 170 if (index >= 0)
180 goto alloc_spi; 171 goto alloc_spi;
181 } 172 }
182 spi = 0; 173 spi = 0;
183 goto out; 174 goto out;
184alloc_spi: 175alloc_spi:
185 xfrm6_tunnel_spi = spi; 176 xfrm6_tn->spi = spi;
186 x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); 177 x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC);
187 if (!x6spi) 178 if (!x6spi)
188 goto out; 179 goto out;
@@ -192,26 +183,26 @@ alloc_spi:
192 x6spi->spi = spi; 183 x6spi->spi = spi;
193 atomic_set(&x6spi->refcnt, 1); 184 atomic_set(&x6spi->refcnt, 1);
194 185
195 hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); 186 hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]);
196 187
197 index = xfrm6_tunnel_spi_hash_byaddr(saddr); 188 index = xfrm6_tunnel_spi_hash_byaddr(saddr);
198 hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); 189 hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]);
199out: 190out:
200 return spi; 191 return spi;
201} 192}
202 193
203__be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) 194__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
204{ 195{
205 struct xfrm6_tunnel_spi *x6spi; 196 struct xfrm6_tunnel_spi *x6spi;
206 u32 spi; 197 u32 spi;
207 198
208 spin_lock_bh(&xfrm6_tunnel_spi_lock); 199 spin_lock_bh(&xfrm6_tunnel_spi_lock);
209 x6spi = __xfrm6_tunnel_spi_lookup(saddr); 200 x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
210 if (x6spi) { 201 if (x6spi) {
211 atomic_inc(&x6spi->refcnt); 202 atomic_inc(&x6spi->refcnt);
212 spi = x6spi->spi; 203 spi = x6spi->spi;
213 } else 204 } else
214 spi = __xfrm6_tunnel_alloc_spi(saddr); 205 spi = __xfrm6_tunnel_alloc_spi(net, saddr);
215 spin_unlock_bh(&xfrm6_tunnel_spi_lock); 206 spin_unlock_bh(&xfrm6_tunnel_spi_lock);
216 207
217 return htonl(spi); 208 return htonl(spi);
@@ -225,15 +216,16 @@ static void x6spi_destroy_rcu(struct rcu_head *head)
225 container_of(head, struct xfrm6_tunnel_spi, rcu_head)); 216 container_of(head, struct xfrm6_tunnel_spi, rcu_head));
226} 217}
227 218
228void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) 219void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr)
229{ 220{
221 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
230 struct xfrm6_tunnel_spi *x6spi; 222 struct xfrm6_tunnel_spi *x6spi;
231 struct hlist_node *pos, *n; 223 struct hlist_node *pos, *n;
232 224
233 spin_lock_bh(&xfrm6_tunnel_spi_lock); 225 spin_lock_bh(&xfrm6_tunnel_spi_lock);
234 226
235 hlist_for_each_entry_safe(x6spi, pos, n, 227 hlist_for_each_entry_safe(x6spi, pos, n,
236 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], 228 &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
237 list_byaddr) 229 list_byaddr)
238 { 230 {
239 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { 231 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
@@ -263,10 +255,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
263 255
264static int xfrm6_tunnel_rcv(struct sk_buff *skb) 256static int xfrm6_tunnel_rcv(struct sk_buff *skb)
265{ 257{
258 struct net *net = dev_net(skb->dev);
266 struct ipv6hdr *iph = ipv6_hdr(skb); 259 struct ipv6hdr *iph = ipv6_hdr(skb);
267 __be32 spi; 260 __be32 spi;
268 261
269 spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); 262 spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr);
270 return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; 263 return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
271} 264}
272 265
@@ -326,7 +319,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x)
326 319
327static void xfrm6_tunnel_destroy(struct xfrm_state *x) 320static void xfrm6_tunnel_destroy(struct xfrm_state *x)
328{ 321{
329 xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); 322 struct net *net = xs_net(x);
323
324 xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr);
330} 325}
331 326
332static const struct xfrm_type xfrm6_tunnel_type = { 327static const struct xfrm_type xfrm6_tunnel_type = {
@@ -351,6 +346,31 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = {
351 .priority = 2, 346 .priority = 2,
352}; 347};
353 348
349static int __net_init xfrm6_tunnel_net_init(struct net *net)
350{
351 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
352 unsigned int i;
353
354 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
355 INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]);
356 for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
357 INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]);
358 xfrm6_tn->spi = 0;
359
360 return 0;
361}
362
363static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
364{
365}
366
367static struct pernet_operations xfrm6_tunnel_net_ops = {
368 .init = xfrm6_tunnel_net_init,
369 .exit = xfrm6_tunnel_net_exit,
370 .id = &xfrm6_tunnel_net_id,
371 .size = sizeof(struct xfrm6_tunnel_net),
372};
373
354static int __init xfrm6_tunnel_init(void) 374static int __init xfrm6_tunnel_init(void)
355{ 375{
356 int rv; 376 int rv;
@@ -367,8 +387,13 @@ static int __init xfrm6_tunnel_init(void)
367 rv = xfrm6_tunnel_spi_init(); 387 rv = xfrm6_tunnel_spi_init();
368 if (rv < 0) 388 if (rv < 0)
369 goto dereg46; 389 goto dereg46;
390 rv = register_pernet_subsys(&xfrm6_tunnel_net_ops);
391 if (rv < 0)
392 goto deregspi;
370 return 0; 393 return 0;
371 394
395deregspi:
396 xfrm6_tunnel_spi_fini();
372dereg46: 397dereg46:
373 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); 398 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
374dereg6: 399dereg6:
@@ -381,6 +406,7 @@ err:
381 406
382static void __exit xfrm6_tunnel_fini(void) 407static void __exit xfrm6_tunnel_fini(void)
383{ 408{
409 unregister_pernet_subsys(&xfrm6_tunnel_net_ops);
384 xfrm6_tunnel_spi_fini(); 410 xfrm6_tunnel_spi_fini();
385 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); 411 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
386 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); 412 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);