aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/netns/xfrm.h4
-rw-r--r--net/ipv6/ip6_vti.c17
-rw-r--r--net/xfrm/xfrm_policy.c52
-rw-r--r--net/xfrm/xfrm_user.c12
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);
55static int xfrm_bundle_ok(struct xfrm_dst *xdst); 55static int xfrm_bundle_ok(struct xfrm_dst *xdst);
56static void xfrm_policy_queue_process(unsigned long arg); 56static void xfrm_policy_queue_process(unsigned long arg);
57 57
58static void __xfrm_policy_link(struct xfrm_policy *pol, int dir);
58static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, 59static 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:
1247static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) 1246static 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
1263static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, 1255static 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
1275static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir)
1276{
1277 __xfrm_policy_link(pol, XFRM_POLICY_MAX + dir);
1278}
1279
1280static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir)
1281{
1282 __xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir);
1283}
1284
1279int xfrm_policy_delete(struct xfrm_policy *pol, int dir) 1285int 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
1879static void xfrm_policy_queue_process(unsigned long arg) 1885static 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
1947out: 1952out:
@@ -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);
836out: 838out:
@@ -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);