diff options
Diffstat (limited to 'net/ipv6/xfrm6_tunnel.c')
-rw-r--r-- | net/ipv6/xfrm6_tunnel.c | 234 |
1 files changed, 130 insertions, 104 deletions
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index 81a95c00e503..2ce3a8278f26 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c | |||
@@ -23,41 +23,51 @@ | |||
23 | */ | 23 | */ |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/xfrm.h> | 25 | #include <linux/xfrm.h> |
26 | #include <linux/list.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/rculist.h> | ||
27 | #include <net/ip.h> | 28 | #include <net/ip.h> |
28 | #include <net/xfrm.h> | 29 | #include <net/xfrm.h> |
29 | #include <net/ipv6.h> | 30 | #include <net/ipv6.h> |
30 | #include <linux/ipv6.h> | 31 | #include <linux/ipv6.h> |
31 | #include <linux/icmpv6.h> | 32 | #include <linux/icmpv6.h> |
32 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | #include <net/netns/generic.h> | ||
35 | |||
36 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
37 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
38 | |||
39 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
40 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
41 | |||
42 | struct xfrm6_tunnel_net { | ||
43 | struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
44 | struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
45 | u32 spi; | ||
46 | }; | ||
47 | |||
48 | static int xfrm6_tunnel_net_id __read_mostly; | ||
49 | static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net) | ||
50 | { | ||
51 | return net_generic(net, xfrm6_tunnel_net_id); | ||
52 | } | ||
33 | 53 | ||
34 | /* | 54 | /* |
35 | * xfrm_tunnel_spi things are for allocating unique id ("spi") | 55 | * xfrm_tunnel_spi things are for allocating unique id ("spi") |
36 | * per xfrm_address_t. | 56 | * per xfrm_address_t. |
37 | */ | 57 | */ |
38 | struct xfrm6_tunnel_spi { | 58 | struct xfrm6_tunnel_spi { |
39 | struct hlist_node list_byaddr; | 59 | struct hlist_node list_byaddr; |
40 | struct hlist_node list_byspi; | 60 | struct hlist_node list_byspi; |
41 | xfrm_address_t addr; | 61 | xfrm_address_t addr; |
42 | u32 spi; | 62 | u32 spi; |
43 | atomic_t refcnt; | 63 | atomic_t refcnt; |
64 | struct rcu_head rcu_head; | ||
44 | }; | 65 | }; |
45 | 66 | ||
46 | static DEFINE_RWLOCK(xfrm6_tunnel_spi_lock); | 67 | static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); |
47 | |||
48 | static u32 xfrm6_tunnel_spi; | ||
49 | |||
50 | #define XFRM6_TUNNEL_SPI_MIN 1 | ||
51 | #define XFRM6_TUNNEL_SPI_MAX 0xffffffff | ||
52 | 68 | ||
53 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; | 69 | static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly; |
54 | 70 | ||
55 | #define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256 | ||
56 | #define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256 | ||
57 | |||
58 | static struct hlist_head xfrm6_tunnel_spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE]; | ||
59 | static struct hlist_head xfrm6_tunnel_spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE]; | ||
60 | |||
61 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) | 71 | static inline unsigned xfrm6_tunnel_spi_hash_byaddr(xfrm_address_t *addr) |
62 | { | 72 | { |
63 | unsigned h; | 73 | unsigned h; |
@@ -75,49 +85,14 @@ static inline unsigned xfrm6_tunnel_spi_hash_byspi(u32 spi) | |||
75 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; | 85 | return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; |
76 | } | 86 | } |
77 | 87 | ||
78 | 88 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) | |
79 | static int xfrm6_tunnel_spi_init(void) | ||
80 | { | ||
81 | int i; | ||
82 | |||
83 | xfrm6_tunnel_spi = 0; | ||
84 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", | ||
85 | sizeof(struct xfrm6_tunnel_spi), | ||
86 | 0, SLAB_HWCACHE_ALIGN, | ||
87 | NULL); | ||
88 | if (!xfrm6_tunnel_spi_kmem) | ||
89 | return -ENOMEM; | ||
90 | |||
91 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
92 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byaddr[i]); | ||
93 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
94 | INIT_HLIST_HEAD(&xfrm6_tunnel_spi_byspi[i]); | ||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static void xfrm6_tunnel_spi_fini(void) | ||
99 | { | ||
100 | int i; | ||
101 | |||
102 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) { | ||
103 | if (!hlist_empty(&xfrm6_tunnel_spi_byaddr[i])) | ||
104 | return; | ||
105 | } | ||
106 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) { | ||
107 | if (!hlist_empty(&xfrm6_tunnel_spi_byspi[i])) | ||
108 | return; | ||
109 | } | ||
110 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
111 | xfrm6_tunnel_spi_kmem = NULL; | ||
112 | } | ||
113 | |||
114 | static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | ||
115 | { | 89 | { |
90 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
116 | struct xfrm6_tunnel_spi *x6spi; | 91 | struct xfrm6_tunnel_spi *x6spi; |
117 | struct hlist_node *pos; | 92 | struct hlist_node *pos; |
118 | 93 | ||
119 | hlist_for_each_entry(x6spi, pos, | 94 | hlist_for_each_entry_rcu(x6spi, pos, |
120 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 95 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
121 | list_byaddr) { | 96 | list_byaddr) { |
122 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) | 97 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) |
123 | return x6spi; | 98 | return x6spi; |
@@ -126,28 +101,29 @@ static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | |||
126 | return NULL; | 101 | return NULL; |
127 | } | 102 | } |
128 | 103 | ||
129 | __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr) | 104 | __be32 xfrm6_tunnel_spi_lookup(struct net *net, xfrm_address_t *saddr) |
130 | { | 105 | { |
131 | struct xfrm6_tunnel_spi *x6spi; | 106 | struct xfrm6_tunnel_spi *x6spi; |
132 | u32 spi; | 107 | u32 spi; |
133 | 108 | ||
134 | read_lock_bh(&xfrm6_tunnel_spi_lock); | 109 | rcu_read_lock_bh(); |
135 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 110 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
136 | spi = x6spi ? x6spi->spi : 0; | 111 | spi = x6spi ? x6spi->spi : 0; |
137 | read_unlock_bh(&xfrm6_tunnel_spi_lock); | 112 | rcu_read_unlock_bh(); |
138 | return htonl(spi); | 113 | return htonl(spi); |
139 | } | 114 | } |
140 | 115 | ||
141 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); | 116 | EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup); |
142 | 117 | ||
143 | static int __xfrm6_tunnel_spi_check(u32 spi) | 118 | static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) |
144 | { | 119 | { |
120 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
145 | struct xfrm6_tunnel_spi *x6spi; | 121 | struct xfrm6_tunnel_spi *x6spi; |
146 | int index = xfrm6_tunnel_spi_hash_byspi(spi); | 122 | int index = xfrm6_tunnel_spi_hash_byspi(spi); |
147 | struct hlist_node *pos; | 123 | struct hlist_node *pos; |
148 | 124 | ||
149 | hlist_for_each_entry(x6spi, pos, | 125 | hlist_for_each_entry(x6spi, pos, |
150 | &xfrm6_tunnel_spi_byspi[index], | 126 | &xfrm6_tn->spi_byspi[index], |
151 | list_byspi) { | 127 | list_byspi) { |
152 | if (x6spi->spi == spi) | 128 | if (x6spi->spi == spi) |
153 | return -1; | 129 | return -1; |
@@ -155,32 +131,33 @@ static int __xfrm6_tunnel_spi_check(u32 spi) | |||
155 | return index; | 131 | return index; |
156 | } | 132 | } |
157 | 133 | ||
158 | static u32 __xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 134 | static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
159 | { | 135 | { |
136 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
160 | u32 spi; | 137 | u32 spi; |
161 | struct xfrm6_tunnel_spi *x6spi; | 138 | struct xfrm6_tunnel_spi *x6spi; |
162 | int index; | 139 | int index; |
163 | 140 | ||
164 | if (xfrm6_tunnel_spi < XFRM6_TUNNEL_SPI_MIN || | 141 | if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN || |
165 | xfrm6_tunnel_spi >= XFRM6_TUNNEL_SPI_MAX) | 142 | xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX) |
166 | xfrm6_tunnel_spi = XFRM6_TUNNEL_SPI_MIN; | 143 | xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN; |
167 | else | 144 | else |
168 | xfrm6_tunnel_spi++; | 145 | xfrm6_tn->spi++; |
169 | 146 | ||
170 | for (spi = xfrm6_tunnel_spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { | 147 | for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { |
171 | index = __xfrm6_tunnel_spi_check(spi); | 148 | index = __xfrm6_tunnel_spi_check(net, spi); |
172 | if (index >= 0) | 149 | if (index >= 0) |
173 | goto alloc_spi; | 150 | goto alloc_spi; |
174 | } | 151 | } |
175 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tunnel_spi; spi++) { | 152 | for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) { |
176 | index = __xfrm6_tunnel_spi_check(spi); | 153 | index = __xfrm6_tunnel_spi_check(net, spi); |
177 | if (index >= 0) | 154 | if (index >= 0) |
178 | goto alloc_spi; | 155 | goto alloc_spi; |
179 | } | 156 | } |
180 | spi = 0; | 157 | spi = 0; |
181 | goto out; | 158 | goto out; |
182 | alloc_spi: | 159 | alloc_spi: |
183 | xfrm6_tunnel_spi = spi; | 160 | xfrm6_tn->spi = spi; |
184 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); | 161 | x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); |
185 | if (!x6spi) | 162 | if (!x6spi) |
186 | goto out; | 163 | goto out; |
@@ -189,54 +166,61 @@ alloc_spi: | |||
189 | x6spi->spi = spi; | 166 | x6spi->spi = spi; |
190 | atomic_set(&x6spi->refcnt, 1); | 167 | atomic_set(&x6spi->refcnt, 1); |
191 | 168 | ||
192 | hlist_add_head(&x6spi->list_byspi, &xfrm6_tunnel_spi_byspi[index]); | 169 | hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]); |
193 | 170 | ||
194 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); | 171 | index = xfrm6_tunnel_spi_hash_byaddr(saddr); |
195 | hlist_add_head(&x6spi->list_byaddr, &xfrm6_tunnel_spi_byaddr[index]); | 172 | hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]); |
196 | out: | 173 | out: |
197 | return spi; | 174 | return spi; |
198 | } | 175 | } |
199 | 176 | ||
200 | __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr) | 177 | __be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) |
201 | { | 178 | { |
202 | struct xfrm6_tunnel_spi *x6spi; | 179 | struct xfrm6_tunnel_spi *x6spi; |
203 | u32 spi; | 180 | u32 spi; |
204 | 181 | ||
205 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 182 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
206 | x6spi = __xfrm6_tunnel_spi_lookup(saddr); | 183 | x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); |
207 | if (x6spi) { | 184 | if (x6spi) { |
208 | atomic_inc(&x6spi->refcnt); | 185 | atomic_inc(&x6spi->refcnt); |
209 | spi = x6spi->spi; | 186 | spi = x6spi->spi; |
210 | } else | 187 | } else |
211 | spi = __xfrm6_tunnel_alloc_spi(saddr); | 188 | spi = __xfrm6_tunnel_alloc_spi(net, saddr); |
212 | write_unlock_bh(&xfrm6_tunnel_spi_lock); | 189 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
213 | 190 | ||
214 | return htonl(spi); | 191 | return htonl(spi); |
215 | } | 192 | } |
216 | 193 | ||
217 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); | 194 | EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi); |
218 | 195 | ||
219 | void xfrm6_tunnel_free_spi(xfrm_address_t *saddr) | 196 | static void x6spi_destroy_rcu(struct rcu_head *head) |
197 | { | ||
198 | kmem_cache_free(xfrm6_tunnel_spi_kmem, | ||
199 | container_of(head, struct xfrm6_tunnel_spi, rcu_head)); | ||
200 | } | ||
201 | |||
202 | void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) | ||
220 | { | 203 | { |
204 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
221 | struct xfrm6_tunnel_spi *x6spi; | 205 | struct xfrm6_tunnel_spi *x6spi; |
222 | struct hlist_node *pos, *n; | 206 | struct hlist_node *pos, *n; |
223 | 207 | ||
224 | write_lock_bh(&xfrm6_tunnel_spi_lock); | 208 | spin_lock_bh(&xfrm6_tunnel_spi_lock); |
225 | 209 | ||
226 | hlist_for_each_entry_safe(x6spi, pos, n, | 210 | hlist_for_each_entry_safe(x6spi, pos, n, |
227 | &xfrm6_tunnel_spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], | 211 | &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], |
228 | list_byaddr) | 212 | list_byaddr) |
229 | { | 213 | { |
230 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { | 214 | if (memcmp(&x6spi->addr, saddr, sizeof(x6spi->addr)) == 0) { |
231 | if (atomic_dec_and_test(&x6spi->refcnt)) { | 215 | if (atomic_dec_and_test(&x6spi->refcnt)) { |
232 | hlist_del(&x6spi->list_byaddr); | 216 | hlist_del_rcu(&x6spi->list_byaddr); |
233 | hlist_del(&x6spi->list_byspi); | 217 | hlist_del_rcu(&x6spi->list_byspi); |
234 | kmem_cache_free(xfrm6_tunnel_spi_kmem, x6spi); | 218 | call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu); |
235 | break; | 219 | break; |
236 | } | 220 | } |
237 | } | 221 | } |
238 | } | 222 | } |
239 | write_unlock_bh(&xfrm6_tunnel_spi_lock); | 223 | spin_unlock_bh(&xfrm6_tunnel_spi_lock); |
240 | } | 224 | } |
241 | 225 | ||
242 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); | 226 | EXPORT_SYMBOL(xfrm6_tunnel_free_spi); |
@@ -254,10 +238,11 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
254 | 238 | ||
255 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) | 239 | static int xfrm6_tunnel_rcv(struct sk_buff *skb) |
256 | { | 240 | { |
241 | struct net *net = dev_net(skb->dev); | ||
257 | struct ipv6hdr *iph = ipv6_hdr(skb); | 242 | struct ipv6hdr *iph = ipv6_hdr(skb); |
258 | __be32 spi; | 243 | __be32 spi; |
259 | 244 | ||
260 | spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr); | 245 | spi = xfrm6_tunnel_spi_lookup(net, (xfrm_address_t *)&iph->saddr); |
261 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; | 246 | return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi) > 0 ? : 0; |
262 | } | 247 | } |
263 | 248 | ||
@@ -317,7 +302,9 @@ static int xfrm6_tunnel_init_state(struct xfrm_state *x) | |||
317 | 302 | ||
318 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) | 303 | static void xfrm6_tunnel_destroy(struct xfrm_state *x) |
319 | { | 304 | { |
320 | xfrm6_tunnel_free_spi((xfrm_address_t *)&x->props.saddr); | 305 | struct net *net = xs_net(x); |
306 | |||
307 | xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr); | ||
321 | } | 308 | } |
322 | 309 | ||
323 | static const struct xfrm_type xfrm6_tunnel_type = { | 310 | static const struct xfrm_type xfrm6_tunnel_type = { |
@@ -342,34 +329,73 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { | |||
342 | .priority = 2, | 329 | .priority = 2, |
343 | }; | 330 | }; |
344 | 331 | ||
332 | static int __net_init xfrm6_tunnel_net_init(struct net *net) | ||
333 | { | ||
334 | struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); | ||
335 | unsigned int i; | ||
336 | |||
337 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) | ||
338 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]); | ||
339 | for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) | ||
340 | INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]); | ||
341 | xfrm6_tn->spi = 0; | ||
342 | |||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | static void __net_exit xfrm6_tunnel_net_exit(struct net *net) | ||
347 | { | ||
348 | } | ||
349 | |||
350 | static struct pernet_operations xfrm6_tunnel_net_ops = { | ||
351 | .init = xfrm6_tunnel_net_init, | ||
352 | .exit = xfrm6_tunnel_net_exit, | ||
353 | .id = &xfrm6_tunnel_net_id, | ||
354 | .size = sizeof(struct xfrm6_tunnel_net), | ||
355 | }; | ||
356 | |||
345 | static int __init xfrm6_tunnel_init(void) | 357 | static int __init xfrm6_tunnel_init(void) |
346 | { | 358 | { |
347 | if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) | 359 | int rv; |
348 | goto err; | 360 | |
349 | if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) | 361 | xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", |
350 | goto unreg; | 362 | sizeof(struct xfrm6_tunnel_spi), |
351 | if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) | 363 | 0, SLAB_HWCACHE_ALIGN, |
352 | goto dereg6; | 364 | NULL); |
353 | if (xfrm6_tunnel_spi_init() < 0) | 365 | if (!xfrm6_tunnel_spi_kmem) |
354 | goto dereg46; | 366 | return -ENOMEM; |
367 | rv = register_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
368 | if (rv < 0) | ||
369 | goto out_pernet; | ||
370 | rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6); | ||
371 | if (rv < 0) | ||
372 | goto out_type; | ||
373 | rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6); | ||
374 | if (rv < 0) | ||
375 | goto out_xfrm6; | ||
376 | rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET); | ||
377 | if (rv < 0) | ||
378 | goto out_xfrm46; | ||
355 | return 0; | 379 | return 0; |
356 | 380 | ||
357 | dereg46: | 381 | out_xfrm46: |
358 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | ||
359 | dereg6: | ||
360 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 382 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
361 | unreg: | 383 | out_xfrm6: |
362 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 384 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
363 | err: | 385 | out_type: |
364 | return -EAGAIN; | 386 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); |
387 | out_pernet: | ||
388 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
389 | return rv; | ||
365 | } | 390 | } |
366 | 391 | ||
367 | static void __exit xfrm6_tunnel_fini(void) | 392 | static void __exit xfrm6_tunnel_fini(void) |
368 | { | 393 | { |
369 | xfrm6_tunnel_spi_fini(); | ||
370 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); | 394 | xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); |
371 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); | 395 | xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); |
372 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); | 396 | xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); |
397 | unregister_pernet_subsys(&xfrm6_tunnel_net_ops); | ||
398 | kmem_cache_destroy(xfrm6_tunnel_spi_kmem); | ||
373 | } | 399 | } |
374 | 400 | ||
375 | module_init(xfrm6_tunnel_init); | 401 | module_init(xfrm6_tunnel_init); |