Commit a1664773907a2b69e2a3019598dcbeffa6bc724b

Authored by Alexey Dobriyan
Committed by David S. Miller
1 parent e924960dac

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>

Showing 3 changed files with 88 additions and 62 deletions Side-by-side Diff

... ... @@ -1408,9 +1408,9 @@
1408 1408 xfrm_address_t *saddr, u8 proto);
1409 1409 extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family);
1410 1410 extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family);
1411   -extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr);
1412   -extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr);
1413   -extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr);
  1411 +extern __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr);
  1412 +extern void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr);
  1413 +extern __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr);
1414 1414 extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb);
1415 1415 extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb);
1416 1416 extern int xfrm6_output(struct sk_buff *skb);
... ... @@ -81,7 +81,7 @@
81 81 goto out;
82 82  
83 83 t->id.proto = IPPROTO_IPV6;
84   - t->id.spi = xfrm6_tunnel_alloc_spi((xfrm_address_t *)&x->props.saddr);
  84 + t->id.spi = xfrm6_tunnel_alloc_spi(&init_net, (xfrm_address_t *)&x->props.saddr);
85 85 if (!t->id.spi)
86 86 goto error;
87 87  
... ... @@ -112,7 +112,7 @@
112 112 struct xfrm_state *t = NULL;
113 113 __be32 spi;
114 114  
115   - spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
  115 + spi = xfrm6_tunnel_spi_lookup(&init_net, (xfrm_address_t *)&x->props.saddr);
116 116 if (spi)
117 117 t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr,
118 118 spi, IPPROTO_IPV6, AF_INET6);
net/ipv6/xfrm6_tunnel.c
... ... @@ -30,7 +30,26 @@
30 30 #include <linux/ipv6.h>
31 31 #include <linux/icmpv6.h>
32 32 #include <linux/mutex.h>
  33 +#include <net/netns/generic.h>
33 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 +
  41 +struct 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 +
  47 +static int xfrm6_tunnel_net_id __read_mostly;
  48 +static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net)
  49 +{
  50 + return net_generic(net, xfrm6_tunnel_net_id);
  51 +}
  52 +
34 53 /*
35 54 * xfrm_tunnel_spi things are for allocating unique id ("spi")
36 55 * per xfrm_address_t.
37 56  
... ... @@ -46,19 +65,8 @@
46 65  
47 66 static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock);
48 67  
49   -static u32 xfrm6_tunnel_spi;
50   -
51   -#define XFRM6_TUNNEL_SPI_MIN 1
52   -#define XFRM6_TUNNEL_SPI_MAX 0xffffffff
53   -
54 68 static 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   -
59   -static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
60   -static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
61   -
62 70 static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr)
63 71 {
64 72 unsigned h;
65 73  
66 74  
67 75  
68 76  
69 77  
70 78  
71 79  
... ... @@ -77,49 +85,30 @@
77 85 }
78 86  
79 87  
80   -static int xfrm6_tunnel_spi_init(void)
  88 +static int __init xfrm6_tunnel_spi_init(void)
81 89 {
82   - int i;
83   -
84   - xfrm6_tunnel_spi = 0;
85 90 xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi",
86 91 sizeof(struct xfrm6_tunnel_spi),
87 92 0, SLAB_HWCACHE_ALIGN,
88 93 NULL);
89 94 if (!xfrm6_tunnel_spi_kmem)
90 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 96 return 0;
97 97 }
98 98  
99 99 static 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 101 kmem_cache_destroy(xfrm6_tunnel_spi_kmem);
113   - xfrm6_tunnel_spi_kmem = NULL;
114 102 }
115 103  
116   -static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr)
  104 +static 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 107 struct xfrm6_tunnel_spi *x6spi;
119 108 struct hlist_node *pos;
120 109  
121 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 112 list_byaddr) {
124 113 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0)
125 114 return x6spi;
126 115  
... ... @@ -128,13 +117,13 @@
128 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 122 struct xfrm6_tunnel_spi *x6spi;
134 123 u32 spi;
135 124  
136 125 rcu_read_lock_bh();
137   - x6spi = __xfrm6_tunnel_spi_lookup(saddr);
  126 + x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
138 127 spi = x6spi ? x6spi->spi : 0;
139 128 rcu_read_unlock_bh();
140 129 return htonl(spi);
141 130  
142 131  
... ... @@ -142,14 +131,15 @@
142 131  
143 132 EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
144 133  
145   -static int __xfrm6_tunnel_spi_check(u32 spi)
  134 +static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi)
146 135 {
  136 + struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net);
147 137 struct xfrm6_tunnel_spi *x6spi;
148 138 int index = xfrm6_tunnel_spi_hash_byspi(spi);
149 139 struct hlist_node *pos;
150 140  
151 141 hlist_for_each_entry(x6spi, pos,
152   - &xfrm6_tunnel_spi_byspi[index],
  142 + &xfrm6_tn->spi_byspi[index],
153 143 list_byspi) {
154 144 if (x6spi->spi == spi)
155 145 return -1;
156 146  
157 147  
158 148  
159 149  
160 150  
161 151  
... ... @@ -157,32 +147,33 @@
157 147 return index;
158 148 }
159 149  
160   -static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr)
  150 +static 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 153 u32 spi;
163 154 struct xfrm6_tunnel_spi *x6spi;
164 155 int index;
165 156  
166   - if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN ||
167   - xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX)
168   - xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN;
  157 + if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN ||
  158 + xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX)
  159 + xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN;
169 160 else
170   - xfrm6_tunnel_spi++;
  161 + xfrm6_tn->spi++;
171 162  
172   - for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
173   - index = __xfrm6_tunnel_spi_check(spi);
  163 + for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) {
  164 + index = __xfrm6_tunnel_spi_check(net, spi);
174 165 if (index >= 0)
175 166 goto alloc_spi;
176 167 }
177   - for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) {
178   - index = __xfrm6_tunnel_spi_check(spi);
  168 + for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) {
  169 + index = __xfrm6_tunnel_spi_check(net, spi);
179 170 if (index >= 0)
180 171 goto alloc_spi;
181 172 }
182 173 spi = 0;
183 174 goto out;
184 175 alloc_spi:
185   - xfrm6_tunnel_spi = spi;
  176 + xfrm6_tn->spi = spi;
186 177 x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC);
187 178 if (!x6spi)
188 179 goto out;
189 180  
190 181  
191 182  
192 183  
... ... @@ -192,26 +183,26 @@
192 183 x6spi->spi = spi;
193 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 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]);
199 190 out:
200 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 196 struct xfrm6_tunnel_spi *x6spi;
206 197 u32 spi;
207 198  
208 199 spin_lock_bh(&xfrm6_tunnel_spi_lock);
209   - x6spi = __xfrm6_tunnel_spi_lookup(saddr);
  200 + x6spi = __xfrm6_tunnel_spi_lookup(net, saddr);
210 201 if (x6spi) {
211 202 atomic_inc(&x6spi->refcnt);
212 203 spi = x6spi->spi;
213 204 } else
214   - spi = __xfrm6_tunnel_alloc_spi(saddr);
  205 + spi = __xfrm6_tunnel_alloc_spi(net, saddr);
215 206 spin_unlock_bh(&xfrm6_tunnel_spi_lock);
216 207  
217 208 return htonl(spi);
218 209  
219 210  
... ... @@ -225,15 +216,16 @@
225 216 container_of(head, struct xfrm6_tunnel_spi, rcu_head));
226 217 }
227 218  
228   -void xfrm6_tunnel_free_spi(xfrm_address_t *saddr)
  219 +void 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 222 struct xfrm6_tunnel_spi *x6spi;
231 223 struct hlist_node *pos, *n;
232 224  
233 225 spin_lock_bh(&xfrm6_tunnel_spi_lock);
234 226  
235 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 229 list_byaddr)
238 230 {
239 231 if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) {
240 232  
... ... @@ -263,10 +255,11 @@
263 255  
264 256 static int xfrm6_tunnel_rcv(struct sk_buff *skb)
265 257 {
  258 + struct net *net = dev_net(skb->dev);
266 259 struct ipv6hdr *iph = ipv6_hdr(skb);
267 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 263 return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0;
271 264 }
272 265  
... ... @@ -326,7 +319,9 @@
326 319  
327 320 static 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  
332 327 static const struct xfrm_type xfrm6_tunnel_type = {
... ... @@ -351,6 +346,31 @@
351 346 .priority = 2,
352 347 };
353 348  
  349 +static 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 +
  363 +static void __net_exit xfrm6_tunnel_net_exit(struct net *net)
  364 +{
  365 +}
  366 +
  367 +static 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 +
354 374 static int __init xfrm6_tunnel_init(void)
355 375 {
356 376 int rv;
357 377  
... ... @@ -367,8 +387,13 @@
367 387 rv = xfrm6_tunnel_spi_init();
368 388 if (rv < 0)
369 389 goto dereg46;
  390 + rv = register_pernet_subsys(&xfrm6_tunnel_net_ops);
  391 + if (rv < 0)
  392 + goto deregspi;
370 393 return 0;
371 394  
  395 +deregspi:
  396 + xfrm6_tunnel_spi_fini();
372 397 dereg46:
373 398 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
374 399 dereg6:
... ... @@ -381,6 +406,7 @@
381 406  
382 407 static void __exit xfrm6_tunnel_fini(void)
383 408 {
  409 + unregister_pernet_subsys(&xfrm6_tunnel_net_ops);
384 410 xfrm6_tunnel_spi_fini();
385 411 xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET);
386 412 xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6);