diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r-- | net/xfrm/xfrm_policy.c | 127 |
1 files changed, 99 insertions, 28 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index cb81ca35b0d6..843e066649cb 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -469,16 +469,16 @@ static inline int xfrm_byidx_should_resize(struct net *net, int total) | |||
469 | return 0; | 469 | return 0; |
470 | } | 470 | } |
471 | 471 | ||
472 | void xfrm_spd_getinfo(struct xfrmk_spdinfo *si) | 472 | void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) |
473 | { | 473 | { |
474 | read_lock_bh(&xfrm_policy_lock); | 474 | read_lock_bh(&xfrm_policy_lock); |
475 | si->incnt = init_net.xfrm.policy_count[XFRM_POLICY_IN]; | 475 | si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; |
476 | si->outcnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT]; | 476 | si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; |
477 | si->fwdcnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD]; | 477 | si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; |
478 | si->inscnt = init_net.xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; | 478 | si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; |
479 | si->outscnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; | 479 | si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; |
480 | si->fwdscnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; | 480 | si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; |
481 | si->spdhcnt = init_net.xfrm.policy_idx_hmask; | 481 | si->spdhcnt = net->xfrm.policy_idx_hmask; |
482 | si->spdhmcnt = xfrm_policy_hashmax; | 482 | si->spdhmcnt = xfrm_policy_hashmax; |
483 | read_unlock_bh(&xfrm_policy_lock); | 483 | read_unlock_bh(&xfrm_policy_lock); |
484 | } | 484 | } |
@@ -556,6 +556,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
556 | struct hlist_head *chain; | 556 | struct hlist_head *chain; |
557 | struct hlist_node *entry, *newpos; | 557 | struct hlist_node *entry, *newpos; |
558 | struct dst_entry *gc_list; | 558 | struct dst_entry *gc_list; |
559 | u32 mark = policy->mark.v & policy->mark.m; | ||
559 | 560 | ||
560 | write_lock_bh(&xfrm_policy_lock); | 561 | write_lock_bh(&xfrm_policy_lock); |
561 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); | 562 | chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); |
@@ -564,6 +565,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
564 | hlist_for_each_entry(pol, entry, chain, bydst) { | 565 | hlist_for_each_entry(pol, entry, chain, bydst) { |
565 | if (pol->type == policy->type && | 566 | if (pol->type == policy->type && |
566 | !selector_cmp(&pol->selector, &policy->selector) && | 567 | !selector_cmp(&pol->selector, &policy->selector) && |
568 | (mark & pol->mark.m) == pol->mark.v && | ||
567 | xfrm_sec_ctx_match(pol->security, policy->security) && | 569 | xfrm_sec_ctx_match(pol->security, policy->security) && |
568 | !WARN_ON(delpol)) { | 570 | !WARN_ON(delpol)) { |
569 | if (excl) { | 571 | if (excl) { |
@@ -635,8 +637,8 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
635 | } | 637 | } |
636 | EXPORT_SYMBOL(xfrm_policy_insert); | 638 | EXPORT_SYMBOL(xfrm_policy_insert); |
637 | 639 | ||
638 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, | 640 | struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, |
639 | struct xfrm_selector *sel, | 641 | int dir, struct xfrm_selector *sel, |
640 | struct xfrm_sec_ctx *ctx, int delete, | 642 | struct xfrm_sec_ctx *ctx, int delete, |
641 | int *err) | 643 | int *err) |
642 | { | 644 | { |
@@ -650,6 +652,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, | |||
650 | ret = NULL; | 652 | ret = NULL; |
651 | hlist_for_each_entry(pol, entry, chain, bydst) { | 653 | hlist_for_each_entry(pol, entry, chain, bydst) { |
652 | if (pol->type == type && | 654 | if (pol->type == type && |
655 | (mark & pol->mark.m) == pol->mark.v && | ||
653 | !selector_cmp(sel, &pol->selector) && | 656 | !selector_cmp(sel, &pol->selector) && |
654 | xfrm_sec_ctx_match(ctx, pol->security)) { | 657 | xfrm_sec_ctx_match(ctx, pol->security)) { |
655 | xfrm_pol_hold(pol); | 658 | xfrm_pol_hold(pol); |
@@ -676,8 +679,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, | |||
676 | } | 679 | } |
677 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); | 680 | EXPORT_SYMBOL(xfrm_policy_bysel_ctx); |
678 | 681 | ||
679 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id, | 682 | struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, |
680 | int delete, int *err) | 683 | int dir, u32 id, int delete, int *err) |
681 | { | 684 | { |
682 | struct xfrm_policy *pol, *ret; | 685 | struct xfrm_policy *pol, *ret; |
683 | struct hlist_head *chain; | 686 | struct hlist_head *chain; |
@@ -692,7 +695,8 @@ struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id, | |||
692 | chain = net->xfrm.policy_byidx + idx_hash(net, id); | 695 | chain = net->xfrm.policy_byidx + idx_hash(net, id); |
693 | ret = NULL; | 696 | ret = NULL; |
694 | hlist_for_each_entry(pol, entry, chain, byidx) { | 697 | hlist_for_each_entry(pol, entry, chain, byidx) { |
695 | if (pol->type == type && pol->index == id) { | 698 | if (pol->type == type && pol->index == id && |
699 | (mark & pol->mark.m) == pol->mark.v) { | ||
696 | xfrm_pol_hold(pol); | 700 | xfrm_pol_hold(pol); |
697 | if (delete) { | 701 | if (delete) { |
698 | *err = security_xfrm_policy_delete( | 702 | *err = security_xfrm_policy_delete( |
@@ -771,7 +775,8 @@ xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audi | |||
771 | 775 | ||
772 | int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | 776 | int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) |
773 | { | 777 | { |
774 | int dir, err = 0; | 778 | int dir, err = 0, cnt = 0; |
779 | struct xfrm_policy *dp; | ||
775 | 780 | ||
776 | write_lock_bh(&xfrm_policy_lock); | 781 | write_lock_bh(&xfrm_policy_lock); |
777 | 782 | ||
@@ -789,8 +794,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
789 | &net->xfrm.policy_inexact[dir], bydst) { | 794 | &net->xfrm.policy_inexact[dir], bydst) { |
790 | if (pol->type != type) | 795 | if (pol->type != type) |
791 | continue; | 796 | continue; |
792 | __xfrm_policy_unlink(pol, dir); | 797 | dp = __xfrm_policy_unlink(pol, dir); |
793 | write_unlock_bh(&xfrm_policy_lock); | 798 | write_unlock_bh(&xfrm_policy_lock); |
799 | if (dp) | ||
800 | cnt++; | ||
794 | 801 | ||
795 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, | 802 | xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, |
796 | audit_info->sessionid, | 803 | audit_info->sessionid, |
@@ -809,8 +816,10 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
809 | bydst) { | 816 | bydst) { |
810 | if (pol->type != type) | 817 | if (pol->type != type) |
811 | continue; | 818 | continue; |
812 | __xfrm_policy_unlink(pol, dir); | 819 | dp = __xfrm_policy_unlink(pol, dir); |
813 | write_unlock_bh(&xfrm_policy_lock); | 820 | write_unlock_bh(&xfrm_policy_lock); |
821 | if (dp) | ||
822 | cnt++; | ||
814 | 823 | ||
815 | xfrm_audit_policy_delete(pol, 1, | 824 | xfrm_audit_policy_delete(pol, 1, |
816 | audit_info->loginuid, | 825 | audit_info->loginuid, |
@@ -824,6 +833,8 @@ int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) | |||
824 | } | 833 | } |
825 | 834 | ||
826 | } | 835 | } |
836 | if (!cnt) | ||
837 | err = -ESRCH; | ||
827 | atomic_inc(&flow_cache_genid); | 838 | atomic_inc(&flow_cache_genid); |
828 | out: | 839 | out: |
829 | write_unlock_bh(&xfrm_policy_lock); | 840 | write_unlock_bh(&xfrm_policy_lock); |
@@ -909,6 +920,7 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, | |||
909 | int match, ret = -ESRCH; | 920 | int match, ret = -ESRCH; |
910 | 921 | ||
911 | if (pol->family != family || | 922 | if (pol->family != family || |
923 | (fl->mark & pol->mark.m) != pol->mark.v || | ||
912 | pol->type != type) | 924 | pol->type != type) |
913 | return ret; | 925 | return ret; |
914 | 926 | ||
@@ -1033,6 +1045,10 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
1033 | int err = 0; | 1045 | int err = 0; |
1034 | 1046 | ||
1035 | if (match) { | 1047 | if (match) { |
1048 | if ((sk->sk_mark & pol->mark.m) != pol->mark.v) { | ||
1049 | pol = NULL; | ||
1050 | goto out; | ||
1051 | } | ||
1036 | err = security_xfrm_policy_lookup(pol->security, | 1052 | err = security_xfrm_policy_lookup(pol->security, |
1037 | fl->secid, | 1053 | fl->secid, |
1038 | policy_to_flow_dir(dir)); | 1054 | policy_to_flow_dir(dir)); |
@@ -1045,6 +1061,7 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc | |||
1045 | } else | 1061 | } else |
1046 | pol = NULL; | 1062 | pol = NULL; |
1047 | } | 1063 | } |
1064 | out: | ||
1048 | read_unlock_bh(&xfrm_policy_lock); | 1065 | read_unlock_bh(&xfrm_policy_lock); |
1049 | return pol; | 1066 | return pol; |
1050 | } | 1067 | } |
@@ -1137,6 +1154,7 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) | |||
1137 | } | 1154 | } |
1138 | newp->lft = old->lft; | 1155 | newp->lft = old->lft; |
1139 | newp->curlft = old->curlft; | 1156 | newp->curlft = old->curlft; |
1157 | newp->mark = old->mark; | ||
1140 | newp->action = old->action; | 1158 | newp->action = old->action; |
1141 | newp->flags = old->flags; | 1159 | newp->flags = old->flags; |
1142 | newp->xfrm_nr = old->xfrm_nr; | 1160 | newp->xfrm_nr = old->xfrm_nr; |
@@ -1309,15 +1327,28 @@ static inline int xfrm_get_tos(struct flowi *fl, int family) | |||
1309 | return tos; | 1327 | return tos; |
1310 | } | 1328 | } |
1311 | 1329 | ||
1312 | static inline struct xfrm_dst *xfrm_alloc_dst(int family) | 1330 | static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) |
1313 | { | 1331 | { |
1314 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); | 1332 | struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); |
1333 | struct dst_ops *dst_ops; | ||
1315 | struct xfrm_dst *xdst; | 1334 | struct xfrm_dst *xdst; |
1316 | 1335 | ||
1317 | if (!afinfo) | 1336 | if (!afinfo) |
1318 | return ERR_PTR(-EINVAL); | 1337 | return ERR_PTR(-EINVAL); |
1319 | 1338 | ||
1320 | xdst = dst_alloc(afinfo->dst_ops) ?: ERR_PTR(-ENOBUFS); | 1339 | switch (family) { |
1340 | case AF_INET: | ||
1341 | dst_ops = &net->xfrm.xfrm4_dst_ops; | ||
1342 | break; | ||
1343 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
1344 | case AF_INET6: | ||
1345 | dst_ops = &net->xfrm.xfrm6_dst_ops; | ||
1346 | break; | ||
1347 | #endif | ||
1348 | default: | ||
1349 | BUG(); | ||
1350 | } | ||
1351 | xdst = dst_alloc(dst_ops) ?: ERR_PTR(-ENOBUFS); | ||
1321 | 1352 | ||
1322 | xfrm_policy_put_afinfo(afinfo); | 1353 | xfrm_policy_put_afinfo(afinfo); |
1323 | 1354 | ||
@@ -1341,7 +1372,8 @@ static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, | |||
1341 | return err; | 1372 | return err; |
1342 | } | 1373 | } |
1343 | 1374 | ||
1344 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | 1375 | static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, |
1376 | struct flowi *fl) | ||
1345 | { | 1377 | { |
1346 | struct xfrm_policy_afinfo *afinfo = | 1378 | struct xfrm_policy_afinfo *afinfo = |
1347 | xfrm_policy_get_afinfo(xdst->u.dst.ops->family); | 1379 | xfrm_policy_get_afinfo(xdst->u.dst.ops->family); |
@@ -1350,7 +1382,7 @@ static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) | |||
1350 | if (!afinfo) | 1382 | if (!afinfo) |
1351 | return -EINVAL; | 1383 | return -EINVAL; |
1352 | 1384 | ||
1353 | err = afinfo->fill_dst(xdst, dev); | 1385 | err = afinfo->fill_dst(xdst, dev, fl); |
1354 | 1386 | ||
1355 | xfrm_policy_put_afinfo(afinfo); | 1387 | xfrm_policy_put_afinfo(afinfo); |
1356 | 1388 | ||
@@ -1366,6 +1398,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1366 | struct flowi *fl, | 1398 | struct flowi *fl, |
1367 | struct dst_entry *dst) | 1399 | struct dst_entry *dst) |
1368 | { | 1400 | { |
1401 | struct net *net = xp_net(policy); | ||
1369 | unsigned long now = jiffies; | 1402 | unsigned long now = jiffies; |
1370 | struct net_device *dev; | 1403 | struct net_device *dev; |
1371 | struct dst_entry *dst_prev = NULL; | 1404 | struct dst_entry *dst_prev = NULL; |
@@ -1389,7 +1422,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1389 | dst_hold(dst); | 1422 | dst_hold(dst); |
1390 | 1423 | ||
1391 | for (; i < nx; i++) { | 1424 | for (; i < nx; i++) { |
1392 | struct xfrm_dst *xdst = xfrm_alloc_dst(family); | 1425 | struct xfrm_dst *xdst = xfrm_alloc_dst(net, family); |
1393 | struct dst_entry *dst1 = &xdst->u.dst; | 1426 | struct dst_entry *dst1 = &xdst->u.dst; |
1394 | 1427 | ||
1395 | err = PTR_ERR(xdst); | 1428 | err = PTR_ERR(xdst); |
@@ -1445,7 +1478,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1445 | if (!dev) | 1478 | if (!dev) |
1446 | goto free_dst; | 1479 | goto free_dst; |
1447 | 1480 | ||
1448 | /* Copy neighbout for reachability confirmation */ | 1481 | /* Copy neighbour for reachability confirmation */ |
1449 | dst0->neighbour = neigh_clone(dst->neighbour); | 1482 | dst0->neighbour = neigh_clone(dst->neighbour); |
1450 | 1483 | ||
1451 | xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); | 1484 | xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); |
@@ -1454,7 +1487,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, | |||
1454 | for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { | 1487 | for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { |
1455 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev; | 1488 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev; |
1456 | 1489 | ||
1457 | err = xfrm_fill_dst(xdst, dev); | 1490 | err = xfrm_fill_dst(xdst, dev, fl); |
1458 | if (err) | 1491 | if (err) |
1459 | goto free_dst; | 1492 | goto free_dst; |
1460 | 1493 | ||
@@ -2031,8 +2064,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) | |||
2031 | int res; | 2064 | int res; |
2032 | 2065 | ||
2033 | if (xfrm_decode_session(skb, &fl, family) < 0) { | 2066 | if (xfrm_decode_session(skb, &fl, family) < 0) { |
2034 | /* XXX: we should have something like FWDHDRERROR here. */ | 2067 | XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); |
2035 | XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); | ||
2036 | return 0; | 2068 | return 0; |
2037 | } | 2069 | } |
2038 | 2070 | ||
@@ -2279,6 +2311,7 @@ EXPORT_SYMBOL(xfrm_bundle_ok); | |||
2279 | 2311 | ||
2280 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | 2312 | int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) |
2281 | { | 2313 | { |
2314 | struct net *net; | ||
2282 | int err = 0; | 2315 | int err = 0; |
2283 | if (unlikely(afinfo == NULL)) | 2316 | if (unlikely(afinfo == NULL)) |
2284 | return -EINVAL; | 2317 | return -EINVAL; |
@@ -2302,6 +2335,27 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2302 | xfrm_policy_afinfo[afinfo->family] = afinfo; | 2335 | xfrm_policy_afinfo[afinfo->family] = afinfo; |
2303 | } | 2336 | } |
2304 | write_unlock_bh(&xfrm_policy_afinfo_lock); | 2337 | write_unlock_bh(&xfrm_policy_afinfo_lock); |
2338 | |||
2339 | rtnl_lock(); | ||
2340 | for_each_net(net) { | ||
2341 | struct dst_ops *xfrm_dst_ops; | ||
2342 | |||
2343 | switch (afinfo->family) { | ||
2344 | case AF_INET: | ||
2345 | xfrm_dst_ops = &net->xfrm.xfrm4_dst_ops; | ||
2346 | break; | ||
2347 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
2348 | case AF_INET6: | ||
2349 | xfrm_dst_ops = &net->xfrm.xfrm6_dst_ops; | ||
2350 | break; | ||
2351 | #endif | ||
2352 | default: | ||
2353 | BUG(); | ||
2354 | } | ||
2355 | *xfrm_dst_ops = *afinfo->dst_ops; | ||
2356 | } | ||
2357 | rtnl_unlock(); | ||
2358 | |||
2305 | return err; | 2359 | return err; |
2306 | } | 2360 | } |
2307 | EXPORT_SYMBOL(xfrm_policy_register_afinfo); | 2361 | EXPORT_SYMBOL(xfrm_policy_register_afinfo); |
@@ -2332,6 +2386,22 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) | |||
2332 | } | 2386 | } |
2333 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); | 2387 | EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); |
2334 | 2388 | ||
2389 | static void __net_init xfrm_dst_ops_init(struct net *net) | ||
2390 | { | ||
2391 | struct xfrm_policy_afinfo *afinfo; | ||
2392 | |||
2393 | read_lock_bh(&xfrm_policy_afinfo_lock); | ||
2394 | afinfo = xfrm_policy_afinfo[AF_INET]; | ||
2395 | if (afinfo) | ||
2396 | net->xfrm.xfrm4_dst_ops = *afinfo->dst_ops; | ||
2397 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | ||
2398 | afinfo = xfrm_policy_afinfo[AF_INET6]; | ||
2399 | if (afinfo) | ||
2400 | net->xfrm.xfrm6_dst_ops = *afinfo->dst_ops; | ||
2401 | #endif | ||
2402 | read_unlock_bh(&xfrm_policy_afinfo_lock); | ||
2403 | } | ||
2404 | |||
2335 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) | 2405 | static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) |
2336 | { | 2406 | { |
2337 | struct xfrm_policy_afinfo *afinfo; | 2407 | struct xfrm_policy_afinfo *afinfo; |
@@ -2369,19 +2439,19 @@ static int __net_init xfrm_statistics_init(struct net *net) | |||
2369 | { | 2439 | { |
2370 | int rv; | 2440 | int rv; |
2371 | 2441 | ||
2372 | if (snmp_mib_init((void **)net->mib.xfrm_statistics, | 2442 | if (snmp_mib_init((void __percpu **)net->mib.xfrm_statistics, |
2373 | sizeof(struct linux_xfrm_mib)) < 0) | 2443 | sizeof(struct linux_xfrm_mib)) < 0) |
2374 | return -ENOMEM; | 2444 | return -ENOMEM; |
2375 | rv = xfrm_proc_init(net); | 2445 | rv = xfrm_proc_init(net); |
2376 | if (rv < 0) | 2446 | if (rv < 0) |
2377 | snmp_mib_free((void **)net->mib.xfrm_statistics); | 2447 | snmp_mib_free((void __percpu **)net->mib.xfrm_statistics); |
2378 | return rv; | 2448 | return rv; |
2379 | } | 2449 | } |
2380 | 2450 | ||
2381 | static void xfrm_statistics_fini(struct net *net) | 2451 | static void xfrm_statistics_fini(struct net *net) |
2382 | { | 2452 | { |
2383 | xfrm_proc_fini(net); | 2453 | xfrm_proc_fini(net); |
2384 | snmp_mib_free((void **)net->mib.xfrm_statistics); | 2454 | snmp_mib_free((void __percpu **)net->mib.xfrm_statistics); |
2385 | } | 2455 | } |
2386 | #else | 2456 | #else |
2387 | static int __net_init xfrm_statistics_init(struct net *net) | 2457 | static int __net_init xfrm_statistics_init(struct net *net) |
@@ -2494,6 +2564,7 @@ static int __net_init xfrm_net_init(struct net *net) | |||
2494 | rv = xfrm_policy_init(net); | 2564 | rv = xfrm_policy_init(net); |
2495 | if (rv < 0) | 2565 | if (rv < 0) |
2496 | goto out_policy; | 2566 | goto out_policy; |
2567 | xfrm_dst_ops_init(net); | ||
2497 | rv = xfrm_sysctl_init(net); | 2568 | rv = xfrm_sysctl_init(net); |
2498 | if (rv < 0) | 2569 | if (rv < 0) |
2499 | goto out_sysctl; | 2570 | goto out_sysctl; |