diff options
| -rw-r--r-- | include/net/netns/xfrm.h | 6 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_policy.c | 14 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_policy.c | 25 | ||||
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 59 |
4 files changed, 84 insertions, 20 deletions
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 56f8e5585df7..74f119a2829a 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <linux/wait.h> | 5 | #include <linux/wait.h> |
| 6 | #include <linux/workqueue.h> | 6 | #include <linux/workqueue.h> |
| 7 | #include <linux/xfrm.h> | 7 | #include <linux/xfrm.h> |
| 8 | #include <net/dst_ops.h> | ||
| 8 | 9 | ||
| 9 | struct ctl_table_header; | 10 | struct ctl_table_header; |
| 10 | 11 | ||
| @@ -42,6 +43,11 @@ struct netns_xfrm { | |||
| 42 | unsigned int policy_count[XFRM_POLICY_MAX * 2]; | 43 | unsigned int policy_count[XFRM_POLICY_MAX * 2]; |
| 43 | struct work_struct policy_hash_work; | 44 | struct work_struct policy_hash_work; |
| 44 | 45 | ||
| 46 | struct dst_ops xfrm4_dst_ops; | ||
| 47 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 48 | struct dst_ops xfrm6_dst_ops; | ||
| 49 | #endif | ||
| 50 | |||
| 45 | struct sock *nlsk; | 51 | struct sock *nlsk; |
| 46 | struct sock *nlsk_stash; | 52 | struct sock *nlsk_stash; |
| 47 | 53 | ||
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 8c08a28d8f83..67107d63c1cd 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #include <net/xfrm.h> | 15 | #include <net/xfrm.h> |
| 16 | #include <net/ip.h> | 16 | #include <net/ip.h> |
| 17 | 17 | ||
| 18 | static struct dst_ops xfrm4_dst_ops; | ||
| 19 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo; | 18 | static struct xfrm_policy_afinfo xfrm4_policy_afinfo; |
| 20 | 19 | ||
| 21 | static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, | 20 | static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, |
| @@ -190,8 +189,10 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
| 190 | 189 | ||
| 191 | static inline int xfrm4_garbage_collect(struct dst_ops *ops) | 190 | static inline int xfrm4_garbage_collect(struct dst_ops *ops) |
| 192 | { | 191 | { |
| 193 | xfrm4_policy_afinfo.garbage_collect(&init_net); | 192 | struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops); |
| 194 | return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2); | 193 | |
| 194 | xfrm4_policy_afinfo.garbage_collect(net); | ||
| 195 | return (atomic_read(&ops->entries) > ops->gc_thresh * 2); | ||
| 195 | } | 196 | } |
| 196 | 197 | ||
| 197 | static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) | 198 | static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) |
| @@ -268,7 +269,7 @@ static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { | |||
| 268 | static struct ctl_table xfrm4_policy_table[] = { | 269 | static struct ctl_table xfrm4_policy_table[] = { |
| 269 | { | 270 | { |
| 270 | .procname = "xfrm4_gc_thresh", | 271 | .procname = "xfrm4_gc_thresh", |
| 271 | .data = &xfrm4_dst_ops.gc_thresh, | 272 | .data = &init_net.xfrm.xfrm4_dst_ops.gc_thresh, |
| 272 | .maxlen = sizeof(int), | 273 | .maxlen = sizeof(int), |
| 273 | .mode = 0644, | 274 | .mode = 0644, |
| 274 | .proc_handler = proc_dointvec, | 275 | .proc_handler = proc_dointvec, |
| @@ -295,8 +296,6 @@ static void __exit xfrm4_policy_fini(void) | |||
| 295 | 296 | ||
| 296 | void __init xfrm4_init(int rt_max_size) | 297 | void __init xfrm4_init(int rt_max_size) |
| 297 | { | 298 | { |
| 298 | xfrm4_state_init(); | ||
| 299 | xfrm4_policy_init(); | ||
| 300 | /* | 299 | /* |
| 301 | * Select a default value for the gc_thresh based on the main route | 300 | * Select a default value for the gc_thresh based on the main route |
| 302 | * table hash size. It seems to me the worst case scenario is when | 301 | * table hash size. It seems to me the worst case scenario is when |
| @@ -308,6 +307,9 @@ void __init xfrm4_init(int rt_max_size) | |||
| 308 | * and start cleaning when were 1/2 full | 307 | * and start cleaning when were 1/2 full |
| 309 | */ | 308 | */ |
| 310 | xfrm4_dst_ops.gc_thresh = rt_max_size/2; | 309 | xfrm4_dst_ops.gc_thresh = rt_max_size/2; |
| 310 | |||
| 311 | xfrm4_state_init(); | ||
| 312 | xfrm4_policy_init(); | ||
| 311 | #ifdef CONFIG_SYSCTL | 313 | #ifdef CONFIG_SYSCTL |
| 312 | sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path, | 314 | sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv4_ctl_path, |
| 313 | xfrm4_policy_table); | 315 | xfrm4_policy_table); |
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 7254e3f899a7..dbdc696f5fc5 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #include <net/mip6.h> | 24 | #include <net/mip6.h> |
| 25 | #endif | 25 | #endif |
| 26 | 26 | ||
| 27 | static struct dst_ops xfrm6_dst_ops; | ||
| 28 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; | 27 | static struct xfrm_policy_afinfo xfrm6_policy_afinfo; |
| 29 | 28 | ||
| 30 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, | 29 | static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, |
| @@ -224,8 +223,10 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) | |||
| 224 | 223 | ||
| 225 | static inline int xfrm6_garbage_collect(struct dst_ops *ops) | 224 | static inline int xfrm6_garbage_collect(struct dst_ops *ops) |
| 226 | { | 225 | { |
| 227 | xfrm6_policy_afinfo.garbage_collect(&init_net); | 226 | struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); |
| 228 | return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2); | 227 | |
| 228 | xfrm6_policy_afinfo.garbage_collect(net); | ||
| 229 | return (atomic_read(&ops->entries) > ops->gc_thresh * 2); | ||
| 229 | } | 230 | } |
| 230 | 231 | ||
| 231 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) | 232 | static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) |
| @@ -310,7 +311,7 @@ static void xfrm6_policy_fini(void) | |||
| 310 | static struct ctl_table xfrm6_policy_table[] = { | 311 | static struct ctl_table xfrm6_policy_table[] = { |
| 311 | { | 312 | { |
| 312 | .procname = "xfrm6_gc_thresh", | 313 | .procname = "xfrm6_gc_thresh", |
| 313 | .data = &xfrm6_dst_ops.gc_thresh, | 314 | .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, |
| 314 | .maxlen = sizeof(int), | 315 | .maxlen = sizeof(int), |
| 315 | .mode = 0644, | 316 | .mode = 0644, |
| 316 | .proc_handler = proc_dointvec, | 317 | .proc_handler = proc_dointvec, |
| @@ -326,13 +327,6 @@ int __init xfrm6_init(void) | |||
| 326 | int ret; | 327 | int ret; |
| 327 | unsigned int gc_thresh; | 328 | unsigned int gc_thresh; |
| 328 | 329 | ||
| 329 | ret = xfrm6_policy_init(); | ||
| 330 | if (ret) | ||
| 331 | goto out; | ||
| 332 | |||
| 333 | ret = xfrm6_state_init(); | ||
| 334 | if (ret) | ||
| 335 | goto out_policy; | ||
| 336 | /* | 330 | /* |
| 337 | * We need a good default value for the xfrm6 gc threshold. | 331 | * We need a good default value for the xfrm6 gc threshold. |
| 338 | * In ipv4 we set it to the route hash table size * 8, which | 332 | * In ipv4 we set it to the route hash table size * 8, which |
| @@ -346,6 +340,15 @@ int __init xfrm6_init(void) | |||
| 346 | */ | 340 | */ |
| 347 | gc_thresh = FIB6_TABLE_HASHSZ * 8; | 341 | gc_thresh = FIB6_TABLE_HASHSZ * 8; |
| 348 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; | 342 | xfrm6_dst_ops.gc_thresh = (gc_thresh < 1024) ? 1024 : gc_thresh; |
| 343 | |||
| 344 | ret = xfrm6_policy_init(); | ||
| 345 | if (ret) | ||
| 346 | goto out; | ||
| 347 | |||
| 348 | ret = xfrm6_state_init(); | ||
| 349 | if (ret) | ||
| 350 | goto out_policy; | ||
| 351 | |||
| 349 | #ifdef CONFIG_SYSCTL | 352 | #ifdef CONFIG_SYSCTL |
| 350 | sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path, | 353 | sysctl_hdr = register_net_sysctl_table(&init_net, net_ipv6_ctl_path, |
| 351 | xfrm6_policy_table); | 354 | xfrm6_policy_table); |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d2c8cb57ee4c..0ecb16a9a883 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -1309,15 +1309,28 @@ static inline int xfrm_get_tos(struct flowi *fl, int family) | |||
| 1309 | return tos; | 1309 | return tos; |
| 1310 | } | 1310 | } |
| 1311 | 1311 | ||
| 1312 | static inline struct xfrm_dst *xfrm_alloc_dst(int family) | 1312 | static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) |
| 1313 | { | 1313 | { |
| 1314 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 1314 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
| 1315 | struct dst_ops *dst_ops; | ||
| 1315 | struct xfrm_dst *xdst; | 1316 | struct xfrm_dst *xdst; |
| 1316 | 1317 | ||
| 1317 | if (!afinfo) | 1318 | if (!afinfo) |
| 1318 | return ERR_PTR(-EINVAL); | 1319 | return ERR_PTR(-EINVAL); |
| 1319 | 1320 | ||
| 1320 | xdst = dst_alloc(afinfo->dst_ops) ?: ERR_PTR(-ENOBUFS); | 1321 | switch (family) { |
| 1322 | case AF_INET: | ||
| 1323 | dst_ops = &net->xfrm.xfrm4_dst_ops; | ||
| 1324 | break; | ||
| 1325 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 1326 | case AF_INET6: | ||
| 1327 | dst_ops = &net->xfrm.xfrm6_dst_ops; | ||
| 1328 | break; | ||
| 1329 | #endif | ||
| 1330 | default: | ||
| 1331 | BUG(); | ||
| 1332 | } | ||
| 1333 | xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS); | ||
| 1321 | 1334 | ||
| 1322 | xfrm_policy_put_afinfo(afinfo); | 1335 | xfrm_policy_put_afinfo(afinfo); |
| 1323 | 1336 | ||
| @@ -1366,6 +1379,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
| 1366 | struct flowi *fl, | 1379 | struct flowi *fl, |
| 1367 | struct dst_entry *dst) | 1380 | struct dst_entry *dst) |
| 1368 | { | 1381 | { |
| 1382 | struct net *net = xp_net(policy); | ||
| 1369 | unsigned long now = jiffies; | 1383 | unsigned long now = jiffies; |
| 1370 | struct net_device *dev; | 1384 | struct net_device *dev; |
| 1371 | struct dst_entry *dst_prev = NULL; | 1385 | struct dst_entry *dst_prev = NULL; |
| @@ -1389,7 +1403,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
| 1389 | dst_hold(dst); | 1403 | dst_hold(dst); |
| 1390 | 1404 | ||
| 1391 | for (; i < nx; i++) { | 1405 | for (; i < nx; i++) { |
| 1392 | struct xfrm_dst *xdst = xfrm_alloc_dst(family); | 1406 | struct xfrm_dst *xdst = xfrm_alloc_dst(net, family); |
| 1393 | struct dst_entry *dst1 = &xdst->u.dst; | 1407 | struct dst_entry *dst1 = &xdst->u.dst; |
| 1394 | 1408 | ||
| 1395 | err = PTR_ERR(xdst); | 1409 | err = PTR_ERR(xdst); |
| @@ -2279,6 +2293,7 @@ EXPORT_SYMBOL(xfrm_bundle_ok); | |||
| 2279 | 2293 | ||
| 2280 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | 2294 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) |
| 2281 | { | 2295 | { |
| 2296 | struct net *net; | ||
| 2282 | int err = 0; | 2297 | int err = 0; |
| 2283 | if (unlikely(afinfo == NULL)) | 2298 | if (unlikely(afinfo == NULL)) |
| 2284 | return -EINVAL; | 2299 | return -EINVAL; |
| @@ -2302,6 +2317,27 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
| 2302 | xfrm_policy_afinfo[afinfo->family] = afinfo; | 2317 | xfrm_policy_afinfo[afinfo->family] = afinfo; |
| 2303 | } | 2318 | } |
| 2304 | write_unlock_bh(&xfrm_policy_afinfo_lock); | 2319 | write_unlock_bh(&xfrm_policy_afinfo_lock); |
| 2320 | |||
| 2321 | rtnl_lock(); | ||
| 2322 | for_each_net(net) { | ||
| 2323 | struct dst_ops *xfrm_dst_ops; | ||
| 2324 | |||
| 2325 | switch (afinfo->family) { | ||
| 2326 | case AF_INET: | ||
| 2327 | xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops; | ||
| 2328 | break; | ||
| 2329 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 2330 | case AF_INET6: | ||
| 2331 | xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops; | ||
| 2332 | break; | ||
| 2333 | #endif | ||
| 2334 | default: | ||
| 2335 | BUG(); | ||
| 2336 | } | ||
| 2337 | *xfrm_dst_ops = *afinfo->dst_ops; | ||
| 2338 | } | ||
| 2339 | rtnl_unlock(); | ||
| 2340 | |||
| 2305 | return err; | 2341 | return err; |
| 2306 | } | 2342 | } |
| 2307 | EXPORT_SYMBOL(xfrm_policy_register_afinfo); | 2343 | EXPORT_SYMBOL(xfrm_policy_register_afinfo); |
| @@ -2332,6 +2368,22 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
| 2332 | } | 2368 | } |
| 2333 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); | 2369 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); |
| 2334 | 2370 | ||
| 2371 | static void __net_init xfrm_dst_ops_init(struct net *net) | ||
| 2372 | { | ||
| 2373 | struct xfrm_policy_afinfo *afinfo; | ||
| 2374 | |||
| 2375 | read_lock_bh(&xfrm_policy_afinfo_lock); | ||
| 2376 | afinfo = xfrm_policy_afinfo[AF_INET]; | ||
| 2377 | if (afinfo) | ||
| 2378 | net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops; | ||
| 2379 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
| 2380 | afinfo = xfrm_policy_afinfo[AF_INET6]; | ||
| 2381 | if (afinfo) | ||
| 2382 | net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops; | ||
| 2383 | #endif | ||
| 2384 | read_unlock_bh(&xfrm_policy_afinfo_lock); | ||
| 2385 | } | ||
| 2386 | |||
| 2335 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) | 2387 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) |
| 2336 | { | 2388 | { |
| 2337 | struct xfrm_policy_afinfo *afinfo; | 2389 | struct xfrm_policy_afinfo *afinfo; |
| @@ -2494,6 +2546,7 @@ static int __net_init xfrm_net_init(struct net *net) | |||
| 2494 | rv = xfrm_policy_init(net); | 2546 | rv = xfrm_policy_init(net); |
| 2495 | if (rv < 0) | 2547 | if (rv < 0) |
| 2496 | goto out_policy; | 2548 | goto out_policy; |
| 2549 | xfrm_dst_ops_init(net); | ||
| 2497 | rv = xfrm_sysctl_init(net); | 2550 | rv = xfrm_sysctl_init(net); |
| 2498 | if (rv < 0) | 2551 | if (rv < 0) |
| 2499 | goto out_sysctl; | 2552 | goto out_sysctl; |
