diff options
Diffstat (limited to 'net/ipv6/xfrm6_tunnel.c')
-rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 194 |
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 | |||
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 | } | ||
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 | ||
47 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); | 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 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; | 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 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 70 | static 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 | 87 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) | |
80 | static 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 | |||
99 | static 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 | |||
116 | static 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 | ||
143 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); | 115 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); |
144 | 116 | ||
145 | static int __xfrm6_tunnel_spi_check(u32 spi) | 117 | static 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 | ||
160 | static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 133 | static 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; |
184 | alloc_spi: | 158 | alloc_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]); |
199 | out: | 172 | out: |
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 | ||
228 | void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | 201 | void 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 | ||
264 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 238 | static 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 | ||
327 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) | 302 | static 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 | ||
332 | static const struct xfrm_type xfrm6_tunnel_type = { | 309 | static 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 | ||
331 | static 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 | |||
345 | static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | ||
346 | { | ||
347 | } | ||
348 | |||
349 | static 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 | |||
354 | static int __init xfrm6_tunnel_init(void) | 356 | static 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 | ||
366 | dereg46: | 380 | out_xfrm46: |
367 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | ||
368 | dereg6: | ||
369 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 381 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
370 | unreg: | 382 | out_xfrm6: |
371 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 383 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
372 | err: | 384 | out_type: |
373 | return -EAGAIN; | 385 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); |
386 | out_pernet: | ||
387 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
388 | return rv; | ||
374 | } | 389 | } |
375 | 390 | ||
376 | static void __exit xfrm6_tunnel_fini(void) | 391 | static 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 | ||
384 | module_init(xfrm6_tunnel_init); | 400 | module_init(xfrm6_tunnel_init); |