diff options
-rw-r--r-- | include/net/netns/xfrm.h | 4 | ||||
-rw-r--r-- | net/ipv6/ip6_vti.c | 17 | ||||
-rw-r--r-- | net/xfrm/xfrm_policy.c | 52 | ||||
-rw-r--r-- | net/xfrm/xfrm_user.c | 12 |
4 files changed, 56 insertions, 29 deletions
diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h index 9da798256f0e..730d82ad6ee5 100644 --- a/include/net/netns/xfrm.h +++ b/include/net/netns/xfrm.h | |||
@@ -50,8 +50,8 @@ struct netns_xfrm { | |||
50 | struct list_head policy_all; | 50 | struct list_head policy_all; |
51 | struct hlist_head *policy_byidx; | 51 | struct hlist_head *policy_byidx; |
52 | unsigned int policy_idx_hmask; | 52 | unsigned int policy_idx_hmask; |
53 | struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; | 53 | struct hlist_head policy_inexact[XFRM_POLICY_MAX]; |
54 | struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; | 54 | struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX]; |
55 | unsigned int policy_count[XFRM_POLICY_MAX * 2]; | 55 | unsigned int policy_count[XFRM_POLICY_MAX * 2]; |
56 | struct work_struct policy_hash_work; | 56 | struct work_struct policy_hash_work; |
57 | struct xfrm_policy_hthresh policy_hthresh; | 57 | struct xfrm_policy_hthresh policy_hthresh; |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 16a7e81e3f99..ace10d0b3aac 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -95,6 +95,7 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, | |||
95 | unsigned int hash = HASH(remote, local); | 95 | unsigned int hash = HASH(remote, local); |
96 | struct ip6_tnl *t; | 96 | struct ip6_tnl *t; |
97 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | 97 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); |
98 | struct in6_addr any; | ||
98 | 99 | ||
99 | for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { | 100 | for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { |
100 | if (ipv6_addr_equal(local, &t->parms.laddr) && | 101 | if (ipv6_addr_equal(local, &t->parms.laddr) && |
@@ -102,6 +103,22 @@ vti6_tnl_lookup(struct net *net, const struct in6_addr *remote, | |||
102 | (t->dev->flags & IFF_UP)) | 103 | (t->dev->flags & IFF_UP)) |
103 | return t; | 104 | return t; |
104 | } | 105 | } |
106 | |||
107 | memset(&any, 0, sizeof(any)); | ||
108 | hash = HASH(&any, local); | ||
109 | for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { | ||
110 | if (ipv6_addr_equal(local, &t->parms.laddr) && | ||
111 | (t->dev->flags & IFF_UP)) | ||
112 | return t; | ||
113 | } | ||
114 | |||
115 | hash = HASH(remote, &any); | ||
116 | for_each_vti6_tunnel_rcu(ip6n->tnls_r_l[hash]) { | ||
117 | if (ipv6_addr_equal(remote, &t->parms.raddr) && | ||
118 | (t->dev->flags & IFF_UP)) | ||
119 | return t; | ||
120 | } | ||
121 | |||
105 | t = rcu_dereference(ip6n->tnls_wc[0]); | 122 | t = rcu_dereference(ip6n->tnls_wc[0]); |
106 | if (t && (t->dev->flags & IFF_UP)) | 123 | if (t && (t->dev->flags & IFF_UP)) |
107 | return t; | 124 | return t; |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 88bf289abdc9..cee479bc655c 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
@@ -55,6 +55,7 @@ static int stale_bundle(struct dst_entry *dst); | |||
55 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); | 55 | static int xfrm_bundle_ok(struct xfrm_dst *xdst); |
56 | static void xfrm_policy_queue_process(unsigned long arg); | 56 | static void xfrm_policy_queue_process(unsigned long arg); |
57 | 57 | ||
58 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir); | ||
58 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | 59 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, |
59 | int dir); | 60 | int dir); |
60 | 61 | ||
@@ -561,7 +562,7 @@ static void xfrm_hash_resize(struct work_struct *work) | |||
561 | mutex_lock(&hash_resize_mutex); | 562 | mutex_lock(&hash_resize_mutex); |
562 | 563 | ||
563 | total = 0; | 564 | total = 0; |
564 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | 565 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
565 | if (xfrm_bydst_should_resize(net, dir, &total)) | 566 | if (xfrm_bydst_should_resize(net, dir, &total)) |
566 | xfrm_bydst_resize(net, dir); | 567 | xfrm_bydst_resize(net, dir); |
567 | } | 568 | } |
@@ -601,7 +602,7 @@ static void xfrm_hash_rebuild(struct work_struct *work) | |||
601 | write_lock_bh(&net->xfrm.xfrm_policy_lock); | 602 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
602 | 603 | ||
603 | /* reset the bydst and inexact table in all directions */ | 604 | /* reset the bydst and inexact table in all directions */ |
604 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | 605 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
605 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); | 606 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); |
606 | hmask = net->xfrm.policy_bydst[dir].hmask; | 607 | hmask = net->xfrm.policy_bydst[dir].hmask; |
607 | odst = net->xfrm.policy_bydst[dir].table; | 608 | odst = net->xfrm.policy_bydst[dir].table; |
@@ -779,8 +780,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
779 | hlist_add_behind(&policy->bydst, newpos); | 780 | hlist_add_behind(&policy->bydst, newpos); |
780 | else | 781 | else |
781 | hlist_add_head(&policy->bydst, chain); | 782 | hlist_add_head(&policy->bydst, chain); |
782 | xfrm_pol_hold(policy); | 783 | __xfrm_policy_link(policy, dir); |
783 | net->xfrm.policy_count[dir]++; | ||
784 | atomic_inc(&net->xfrm.flow_cache_genid); | 784 | atomic_inc(&net->xfrm.flow_cache_genid); |
785 | 785 | ||
786 | /* After previous checking, family can either be AF_INET or AF_INET6 */ | 786 | /* After previous checking, family can either be AF_INET or AF_INET6 */ |
@@ -799,7 +799,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) | |||
799 | policy->curlft.use_time = 0; | 799 | policy->curlft.use_time = 0; |
800 | if (!mod_timer(&policy->timer, jiffies + HZ)) | 800 | if (!mod_timer(&policy->timer, jiffies + HZ)) |
801 | xfrm_pol_hold(policy); | 801 | xfrm_pol_hold(policy); |
802 | list_add(&policy->walk.all, &net->xfrm.policy_all); | ||
803 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); | 802 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
804 | 803 | ||
805 | if (delpol) | 804 | if (delpol) |
@@ -1247,17 +1246,10 @@ out: | |||
1247 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) | 1246 | static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) |
1248 | { | 1247 | { |
1249 | struct net *net = xp_net(pol); | 1248 | struct net *net = xp_net(pol); |
1250 | struct hlist_head *chain = policy_hash_bysel(net, &pol->selector, | ||
1251 | pol->family, dir); | ||
1252 | 1249 | ||
1253 | list_add(&pol->walk.all, &net->xfrm.policy_all); | 1250 | list_add(&pol->walk.all, &net->xfrm.policy_all); |
1254 | hlist_add_head(&pol->bydst, chain); | ||
1255 | hlist_add_head(&pol->byidx, net->xfrm.policy_byidx+idx_hash(net, pol->index)); | ||
1256 | net->xfrm.policy_count[dir]++; | 1251 | net->xfrm.policy_count[dir]++; |
1257 | xfrm_pol_hold(pol); | 1252 | xfrm_pol_hold(pol); |
1258 | |||
1259 | if (xfrm_bydst_should_resize(net, dir, NULL)) | ||
1260 | schedule_work(&net->xfrm.policy_hash_work); | ||
1261 | } | 1253 | } |
1262 | 1254 | ||
1263 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | 1255 | static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, |
@@ -1265,17 +1257,31 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, | |||
1265 | { | 1257 | { |
1266 | struct net *net = xp_net(pol); | 1258 | struct net *net = xp_net(pol); |
1267 | 1259 | ||
1268 | if (hlist_unhashed(&pol->bydst)) | 1260 | if (list_empty(&pol->walk.all)) |
1269 | return NULL; | 1261 | return NULL; |
1270 | 1262 | ||
1271 | hlist_del_init(&pol->bydst); | 1263 | /* Socket policies are not hashed. */ |
1272 | hlist_del(&pol->byidx); | 1264 | if (!hlist_unhashed(&pol->bydst)) { |
1273 | list_del(&pol->walk.all); | 1265 | hlist_del(&pol->bydst); |
1266 | hlist_del(&pol->byidx); | ||
1267 | } | ||
1268 | |||
1269 | list_del_init(&pol->walk.all); | ||
1274 | net->xfrm.policy_count[dir]--; | 1270 | net->xfrm.policy_count[dir]--; |
1275 | 1271 | ||
1276 | return pol; | 1272 | return pol; |
1277 | } | 1273 | } |
1278 | 1274 | ||
1275 | static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) | ||
1276 | { | ||
1277 | __xfrm_policy_link(pol, XFRM_POLICY_MAX + dir); | ||
1278 | } | ||
1279 | |||
1280 | static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) | ||
1281 | { | ||
1282 | __xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir); | ||
1283 | } | ||
1284 | |||
1279 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) | 1285 | int xfrm_policy_delete(struct xfrm_policy *pol, int dir) |
1280 | { | 1286 | { |
1281 | struct net *net = xp_net(pol); | 1287 | struct net *net = xp_net(pol); |
@@ -1307,7 +1313,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
1307 | if (pol) { | 1313 | if (pol) { |
1308 | pol->curlft.add_time = get_seconds(); | 1314 | pol->curlft.add_time = get_seconds(); |
1309 | pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); | 1315 | pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); |
1310 | __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); | 1316 | xfrm_sk_policy_link(pol, dir); |
1311 | } | 1317 | } |
1312 | if (old_pol) { | 1318 | if (old_pol) { |
1313 | if (pol) | 1319 | if (pol) |
@@ -1316,7 +1322,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) | |||
1316 | /* Unlinking succeeds always. This is the only function | 1322 | /* Unlinking succeeds always. This is the only function |
1317 | * allowed to delete or replace socket policy. | 1323 | * allowed to delete or replace socket policy. |
1318 | */ | 1324 | */ |
1319 | __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); | 1325 | xfrm_sk_policy_unlink(old_pol, dir); |
1320 | } | 1326 | } |
1321 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); | 1327 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1322 | 1328 | ||
@@ -1349,7 +1355,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) | |||
1349 | memcpy(newp->xfrm_vec, old->xfrm_vec, | 1355 | memcpy(newp->xfrm_vec, old->xfrm_vec, |
1350 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); | 1356 | newp->xfrm_nr*sizeof(struct xfrm_tmpl)); |
1351 | write_lock_bh(&net->xfrm.xfrm_policy_lock); | 1357 | write_lock_bh(&net->xfrm.xfrm_policy_lock); |
1352 | __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); | 1358 | xfrm_sk_policy_link(newp, dir); |
1353 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); | 1359 | write_unlock_bh(&net->xfrm.xfrm_policy_lock); |
1354 | xfrm_pol_put(newp); | 1360 | xfrm_pol_put(newp); |
1355 | } | 1361 | } |
@@ -1878,7 +1884,6 @@ xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, | |||
1878 | 1884 | ||
1879 | static void xfrm_policy_queue_process(unsigned long arg) | 1885 | static void xfrm_policy_queue_process(unsigned long arg) |
1880 | { | 1886 | { |
1881 | int err = 0; | ||
1882 | struct sk_buff *skb; | 1887 | struct sk_buff *skb; |
1883 | struct sock *sk; | 1888 | struct sock *sk; |
1884 | struct dst_entry *dst; | 1889 | struct dst_entry *dst; |
@@ -1941,7 +1946,7 @@ static void xfrm_policy_queue_process(unsigned long arg) | |||
1941 | skb_dst_drop(skb); | 1946 | skb_dst_drop(skb); |
1942 | skb_dst_set(skb, dst); | 1947 | skb_dst_set(skb, dst); |
1943 | 1948 | ||
1944 | err = dst_output(skb); | 1949 | dst_output(skb); |
1945 | } | 1950 | } |
1946 | 1951 | ||
1947 | out: | 1952 | out: |
@@ -2966,10 +2971,11 @@ static int __net_init xfrm_policy_init(struct net *net) | |||
2966 | goto out_byidx; | 2971 | goto out_byidx; |
2967 | net->xfrm.policy_idx_hmask = hmask; | 2972 | net->xfrm.policy_idx_hmask = hmask; |
2968 | 2973 | ||
2969 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | 2974 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
2970 | struct xfrm_policy_hash *htab; | 2975 | struct xfrm_policy_hash *htab; |
2971 | 2976 | ||
2972 | net->xfrm.policy_count[dir] = 0; | 2977 | net->xfrm.policy_count[dir] = 0; |
2978 | net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0; | ||
2973 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); | 2979 | INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); |
2974 | 2980 | ||
2975 | htab = &net->xfrm.policy_bydst[dir]; | 2981 | htab = &net->xfrm.policy_bydst[dir]; |
@@ -3021,7 +3027,7 @@ static void xfrm_policy_fini(struct net *net) | |||
3021 | 3027 | ||
3022 | WARN_ON(!list_empty(&net->xfrm.policy_all)); | 3028 | WARN_ON(!list_empty(&net->xfrm.policy_all)); |
3023 | 3029 | ||
3024 | for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { | 3030 | for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { |
3025 | struct xfrm_policy_hash *htab; | 3031 | struct xfrm_policy_hash *htab; |
3026 | 3032 | ||
3027 | WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); | 3033 | WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); |
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index e812e988c111..8128594ab379 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -824,13 +824,15 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
824 | ret = xfrm_mark_put(skb, &x->mark); | 824 | ret = xfrm_mark_put(skb, &x->mark); |
825 | if (ret) | 825 | if (ret) |
826 | goto out; | 826 | goto out; |
827 | if (x->replay_esn) { | 827 | if (x->replay_esn) |
828 | ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL, | 828 | ret = nla_put(skb, XFRMA_REPLAY_ESN_VAL, |
829 | xfrm_replay_state_esn_len(x->replay_esn), | 829 | xfrm_replay_state_esn_len(x->replay_esn), |
830 | x->replay_esn); | 830 | x->replay_esn); |
831 | if (ret) | 831 | else |
832 | goto out; | 832 | ret = nla_put(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), |
833 | } | 833 | &x->replay); |
834 | if (ret) | ||
835 | goto out; | ||
834 | if (x->security) | 836 | if (x->security) |
835 | ret = copy_sec_ctx(x->security, skb); | 837 | ret = copy_sec_ctx(x->security, skb); |
836 | out: | 838 | out: |
@@ -2569,6 +2571,8 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) | |||
2569 | l += nla_total_size(sizeof(x->tfcpad)); | 2571 | l += nla_total_size(sizeof(x->tfcpad)); |
2570 | if (x->replay_esn) | 2572 | if (x->replay_esn) |
2571 | l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn)); | 2573 | l += nla_total_size(xfrm_replay_state_esn_len(x->replay_esn)); |
2574 | else | ||
2575 | l += nla_total_size(sizeof(struct xfrm_replay_state)); | ||
2572 | if (x->security) | 2576 | if (x->security) |
2573 | l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + | 2577 | l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + |
2574 | x->security->ctx_len); | 2578 | x->security->ctx_len); |