aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/xfrm6_tunnel.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/xfrm6_tunnel.c')
-rw-r--r--net/ipv6/xfrm6_tunnel.c194
1 files changed, 105 insertions, 89 deletions
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 438831d33593..fa85a7d22dc4 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;
@@ -76,50 +84,14 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi)
76 return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; 84 return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE;
77} 85}
78 86
79 87static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
80static int xfrm6_tunnel_spi_init(void)
81{
82 int i;
83
84 xfrm6_tunnel_spi = 0;
85 xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
86 sizeof(struct xfrm6_tunnel_spi),
87 0, SLAB_HWCACHE_ALIGN,
88 NULL);
89 if (!xfrm6_tunnel_spi_kmem)
90 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;
97}
98
99static void xfrm6_tunnel_spi_fini(void)
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);
113 xfrm6_tunnel_spi_kmem = NULL;
114}
115
116static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
117{ 88{
89 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
118 struct xfrm6_tunnel_spi *x6spi; 90 struct xfrm6_tunnel_spi *x6spi;
119 struct hlist_node *pos; 91 struct hlist_node *pos;
120 92
121 hlist_for_each_entry_rcu(x6spi, pos, 93 hlist_for_each_entry_rcu(x6spi, pos,
122 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], 94 &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
123 list_byaddr) { 95 list_byaddr) {
124 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) 96 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0)
125 return x6spi; 97 return x6spi;
@@ -128,13 +100,13 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
128 return NULL; 100 return NULL;
129} 101}
130 102
131__be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) 103__be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr)
132{ 104{
133 struct xfrm6_tunnel_spi *x6spi; 105 struct xfrm6_tunnel_spi *x6spi;
134 u32 spi; 106 u32 spi;
135 107
136 rcu_read_lock_bh(); 108 rcu_read_lock_bh();
137 x6spi = __xfrm6_tunnel_spi_lookup(saddr); 109 x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
138 spi = x6spi ? x6spi->spi : 0; 110 spi = x6spi ? x6spi->spi : 0;
139 rcu_read_unlock_bh(); 111 rcu_read_unlock_bh();
140 return htonl(spi); 112 return htonl(spi);
@@ -142,14 +114,15 @@ __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
142 114
143EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); 115EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
144 116
145static int __xfrm6_tunnel_spi_check(u32 spi) 117static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi)
146{ 118{
119 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
147 struct xfrm6_tunnel_spi *x6spi; 120 struct xfrm6_tunnel_spi *x6spi;
148 int index = xfrm6_tunnel_spi_hash_byspi(spi); 121 int index = xfrm6_tunnel_spi_hash_byspi(spi);
149 struct hlist_node *pos; 122 struct hlist_node *pos;
150 123
151 hlist_for_each_entry(x6spi, pos, 124 hlist_for_each_entry(x6spi, pos,
152 &xfrm6_tunnel_spi_byspi[index], 125 &xfrm6_tn->spi_byspi[index],
153 list_byspi) { 126 list_byspi) {
154 if (x6spi->spi == spi) 127 if (x6spi->spi == spi)
155 return -1; 128 return -1;
@@ -157,61 +130,61 @@ static int __xfrm6_tunnel_spi_check(u32 spi)
157 return index; 130 return index;
158} 131}
159 132
160static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) 133static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
161{ 134{
135 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
162 u32 spi; 136 u32 spi;
163 struct xfrm6_tunnel_spi *x6spi; 137 struct xfrm6_tunnel_spi *x6spi;
164 int index; 138 int index;
165 139
166 if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || 140 if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN ||
167 xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) 141 xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX)
168 xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; 142 xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN;
169 else 143 else
170 xfrm6_tunnel_spi++; 144 xfrm6_tn->spi++;
171 145
172 for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { 146 for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
173 index = __xfrm6_tunnel_spi_check(spi); 147 index = __xfrm6_tunnel_spi_check(net, spi);
174 if (index >= 0) 148 if (index >= 0)
175 goto alloc_spi; 149 goto alloc_spi;
176 } 150 }
177 for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { 151 for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) {
178 index = __xfrm6_tunnel_spi_check(spi); 152 index = __xfrm6_tunnel_spi_check(net, spi);
179 if (index >= 0) 153 if (index >= 0)
180 goto alloc_spi; 154 goto alloc_spi;
181 } 155 }
182 spi = 0; 156 spi = 0;
183 goto out; 157 goto out;
184alloc_spi: 158alloc_spi:
185 xfrm6_tunnel_spi = spi; 159 xfrm6_tn->spi = spi;
186 x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); 160 x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC);
187 if (!x6spi) 161 if (!x6spi)
188 goto out; 162 goto out;
189 163
190 INIT_RCU_HEAD(&x6spi->rcu_head);
191 memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); 164 memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr));
192 x6spi->spi = spi; 165 x6spi->spi = spi;
193 atomic_set(&x6spi->refcnt, 1); 166 atomic_set(&x6spi->refcnt, 1);
194 167
195 hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); 168 hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]);
196 169
197 index = xfrm6_tunnel_spi_hash_byaddr(saddr); 170 index = xfrm6_tunnel_spi_hash_byaddr(saddr);
198 hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); 171 hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]);
199out: 172out:
200 return spi; 173 return spi;
201} 174}
202 175
203__be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) 176__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr)
204{ 177{
205 struct xfrm6_tunnel_spi *x6spi; 178 struct xfrm6_tunnel_spi *x6spi;
206 u32 spi; 179 u32 spi;
207 180
208 spin_lock_bh(&xfrm6_tunnel_spi_lock); 181 spin_lock_bh(&xfrm6_tunnel_spi_lock);
209 x6spi = __xfrm6_tunnel_spi_lookup(saddr); 182 x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
210 if (x6spi) { 183 if (x6spi) {
211 atomic_inc(&x6spi->refcnt); 184 atomic_inc(&x6spi->refcnt);
212 spi = x6spi->spi; 185 spi = x6spi->spi;
213 } else 186 } else
214 spi = __xfrm6_tunnel_alloc_spi(saddr); 187 spi = __xfrm6_tunnel_alloc_spi(net, saddr);
215 spin_unlock_bh(&xfrm6_tunnel_spi_lock); 188 spin_unlock_bh(&xfrm6_tunnel_spi_lock);
216 189
217 return htonl(spi); 190 return htonl(spi);
@@ -225,15 +198,16 @@ static void x6spi_destroy_rcu(struct rcu_head *head)
225 container_of(head, struct xfrm6_tunnel_spi, rcu_head)); 198 container_of(head, struct xfrm6_tunnel_spi, rcu_head));
226} 199}
227 200
228void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) 201void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr)
229{ 202{
203 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
230 struct xfrm6_tunnel_spi *x6spi; 204 struct xfrm6_tunnel_spi *x6spi;
231 struct hlist_node *pos, *n; 205 struct hlist_node *pos, *n;
232 206
233 spin_lock_bh(&xfrm6_tunnel_spi_lock); 207 spin_lock_bh(&xfrm6_tunnel_spi_lock);
234 208
235 hlist_for_each_entry_safe(x6spi, pos, n, 209 hlist_for_each_entry_safe(x6spi, pos, n,
236 &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], 210 &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)],
237 list_byaddr) 211 list_byaddr)
238 { 212 {
239 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { 213 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
@@ -263,10 +237,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
263 237
264static int xfrm6_tunnel_rcv(struct sk_buff *skb) 238static int xfrm6_tunnel_rcv(struct sk_buff *skb)
265{ 239{
240 struct net *net = dev_net(skb->dev);
266 struct ipv6hdr *iph = ipv6_hdr(skb); 241 struct ipv6hdr *iph = ipv6_hdr(skb);
267 __be32 spi; 242 __be32 spi;
268 243
269 spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); 244 spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr);
270 return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; 245 return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
271} 246}
272 247
@@ -326,7 +301,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x)
326 301
327static void xfrm6_tunnel_destroy(struct xfrm_state *x) 302static void xfrm6_tunnel_destroy(struct xfrm_state *x)
328{ 303{
329 xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); 304 struct net *net = xs_net(x);
305
306 xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr);
330} 307}
331 308
332static const struct xfrm_type xfrm6_tunnel_type = { 309static const struct xfrm_type xfrm6_tunnel_type = {
@@ -351,34 +328,73 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = {
351 .priority = 2, 328 .priority = 2,
352}; 329};
353 330
331static int __net_init xfrm6_tunnel_net_init(struct net *net)
332{
333 struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
334 unsigned int i;
335
336 for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++)
337 INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]);
338 for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++)
339 INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]);
340 xfrm6_tn->spi = 0;
341
342 return 0;
343}
344
345static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
346{
347}
348
349static struct pernet_operations xfrm6_tunnel_net_ops = {
350 .init = xfrm6_tunnel_net_init,
351 .exit = xfrm6_tunnel_net_exit,
352 .id = &xfrm6_tunnel_net_id,
353 .size = sizeof(struct xfrm6_tunnel_net),
354};
355
354static int __init xfrm6_tunnel_init(void) 356static int __init xfrm6_tunnel_init(void)
355{ 357{
356 if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) 358 int rv;
357 goto err; 359
358 if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) 360 xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
359 goto unreg; 361 sizeof(struct xfrm6_tunnel_spi),
360 if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) 362 0, SLAB_HWCACHE_ALIGN,
361 goto dereg6; 363 NULL);
362 if (xfrm6_tunnel_spi_init() < 0) 364 if (!xfrm6_tunnel_spi_kmem)
363 goto dereg46; 365 return -ENOMEM;
366 rv = register_pernet_subsys(&xfrm6_tunnel_net_ops);
367 if (rv < 0)
368 goto out_pernet;
369 rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6);
370 if (rv < 0)
371 goto out_type;
372 rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6);
373 if (rv < 0)
374 goto out_xfrm6;
375 rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET);
376 if (rv < 0)
377 goto out_xfrm46;
364 return 0; 378 return 0;
365 379
366dereg46: 380out_xfrm46:
367 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
368dereg6:
369 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); 381 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
370unreg: 382out_xfrm6:
371 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); 383 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
372err: 384out_type:
373 return -EAGAIN; 385 unregister_pernet_subsys(&xfrm6_tunnel_net_ops);
386out_pernet:
387 kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
388 return rv;
374} 389}
375 390
376static void __exit xfrm6_tunnel_fini(void) 391static void __exit xfrm6_tunnel_fini(void)
377{ 392{
378 xfrm6_tunnel_spi_fini();
379 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); 393 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
380 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); 394 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);
381 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); 395 xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6);
396 unregister_pernet_subsys(&xfrm6_tunnel_net_ops);
397 kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
382} 398}
383 399
384module_init(xfrm6_tunnel_init); 400module_init(xfrm6_tunnel_init);