aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2014-11-13 04:09:49 -0500
committerSteffen Klassert <steffen.klassert@secunet.com>2014-11-13 05:25:03 -0500
commit53c2e285f9703001e1bb48d04696c5f9d8f3aef7 (patch)
treedce531b10da3a88562a15986ff85cc986bbf73e3
parentf293a5e33e084ef84b802e3002e5fe3eef086171 (diff)
xfrm: Do not hash socket policies
Back in 2003 when I added policy expiration, I half-heartedly did a clean-up and renamed xfrm_sk_policy_link/xfrm_sk_policy_unlink to __xfrm_policy_link/__xfrm_policy_unlink, because the latter could be reused for all policies. I never actually got around to using __xfrm_policy_link for non-socket policies. Later on hashing was added to all xfrm policies, including socket policies. In fact, we don't need hashing on socket policies at all since they're always looked up via a linked list. This patch restores xfrm_sk_policy_link/xfrm_sk_policy_unlink as wrappers around __xfrm_policy_link/__xfrm_policy_unlink so that it's obvious we're dealing with socket policies. This patch also removes hashing from __xfrm_policy_link as for now it's only used by socket policies which do not need to be hashed. Ironically this will in fact allow us to use this helper for non-socket policies which I shall do later. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
-rw-r--r--include/net/netns/xfrm.h4
-rw-r--r--net/xfrm/xfrm_policy.c44
2 files changed, 28 insertions, 20 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/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index dc653249e845..f4d3a125e49c 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -561,7 +561,7 @@ static void xfrm_hash_resize(struct work_struct *work)
561 mutex_lock(&hash_resize_mutex); 561 mutex_lock(&hash_resize_mutex);
562 562
563 total = 0; 563 total = 0;
564 for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { 564 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
565 if (xfrm_bydst_should_resize(net, dir, &total)) 565 if (xfrm_bydst_should_resize(net, dir, &total))
566 xfrm_bydst_resize(net, dir); 566 xfrm_bydst_resize(net, dir);
567 } 567 }
@@ -601,7 +601,7 @@ static void xfrm_hash_rebuild(struct work_struct *work)
601 write_lock_bh(&net->xfrm.xfrm_policy_lock); 601 write_lock_bh(&net->xfrm.xfrm_policy_lock);
602 602
603 /* reset the bydst and inexact table in all directions */ 603 /* reset the bydst and inexact table in all directions */
604 for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { 604 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
605 INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); 605 INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
606 hmask = net->xfrm.policy_bydst[dir].hmask; 606 hmask = net->xfrm.policy_bydst[dir].hmask;
607 odst = net->xfrm.policy_bydst[dir].table; 607 odst = net->xfrm.policy_bydst[dir].table;
@@ -1247,17 +1247,10 @@ out:
1247static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) 1247static void __xfrm_policy_link(struct xfrm_policy *pol, int dir)
1248{ 1248{
1249 struct net *net = xp_net(pol); 1249 struct net *net = xp_net(pol);
1250 struct hlist_head *chain = policy_hash_bysel(net, &pol->selector,
1251 pol->family, dir);
1252 1250
1253 list_add(&pol->walk.all, &net->xfrm.policy_all); 1251 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]++; 1252 net->xfrm.policy_count[dir]++;
1257 xfrm_pol_hold(pol); 1253 xfrm_pol_hold(pol);
1258
1259 if (xfrm_bydst_should_resize(net, dir, NULL))
1260 schedule_work(&net->xfrm.policy_hash_work);
1261} 1254}
1262 1255
1263static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, 1256static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
@@ -1265,17 +1258,31 @@ static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol,
1265{ 1258{
1266 struct net *net = xp_net(pol); 1259 struct net *net = xp_net(pol);
1267 1260
1268 if (hlist_unhashed(&pol->bydst)) 1261 if (list_empty(&pol->walk.all))
1269 return NULL; 1262 return NULL;
1270 1263
1271 hlist_del_init(&pol->bydst); 1264 /* Socket policies are not hashed. */
1272 hlist_del(&pol->byidx); 1265 if (!hlist_unhashed(&pol->bydst)) {
1273 list_del(&pol->walk.all); 1266 hlist_del(&pol->bydst);
1267 hlist_del(&pol->byidx);
1268 }
1269
1270 list_del_init(&pol->walk.all);
1274 net->xfrm.policy_count[dir]--; 1271 net->xfrm.policy_count[dir]--;
1275 1272
1276 return pol; 1273 return pol;
1277} 1274}
1278 1275
1276static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir)
1277{
1278 __xfrm_policy_link(pol, XFRM_POLICY_MAX + dir);
1279}
1280
1281static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir)
1282{
1283 __xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir);
1284}
1285
1279int xfrm_policy_delete(struct xfrm_policy *pol, int dir) 1286int xfrm_policy_delete(struct xfrm_policy *pol, int dir)
1280{ 1287{
1281 struct net *net = xp_net(pol); 1288 struct net *net = xp_net(pol);
@@ -1307,7 +1314,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
1307 if (pol) { 1314 if (pol) {
1308 pol->curlft.add_time = get_seconds(); 1315 pol->curlft.add_time = get_seconds();
1309 pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); 1316 pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0);
1310 __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); 1317 xfrm_sk_policy_link(pol, dir);
1311 } 1318 }
1312 if (old_pol) { 1319 if (old_pol) {
1313 if (pol) 1320 if (pol)
@@ -1316,7 +1323,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
1316 /* Unlinking succeeds always. This is the only function 1323 /* Unlinking succeeds always. This is the only function
1317 * allowed to delete or replace socket policy. 1324 * allowed to delete or replace socket policy.
1318 */ 1325 */
1319 __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); 1326 xfrm_sk_policy_unlink(old_pol, dir);
1320 } 1327 }
1321 write_unlock_bh(&net->xfrm.xfrm_policy_lock); 1328 write_unlock_bh(&net->xfrm.xfrm_policy_lock);
1322 1329
@@ -1349,7 +1356,7 @@ static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir)
1349 memcpy(newp->xfrm_vec, old->xfrm_vec, 1356 memcpy(newp->xfrm_vec, old->xfrm_vec,
1350 newp->xfrm_nr*sizeof(struct xfrm_tmpl)); 1357 newp->xfrm_nr*sizeof(struct xfrm_tmpl));
1351 write_lock_bh(&net->xfrm.xfrm_policy_lock); 1358 write_lock_bh(&net->xfrm.xfrm_policy_lock);
1352 __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); 1359 xfrm_sk_policy_link(newp, dir);
1353 write_unlock_bh(&net->xfrm.xfrm_policy_lock); 1360 write_unlock_bh(&net->xfrm.xfrm_policy_lock);
1354 xfrm_pol_put(newp); 1361 xfrm_pol_put(newp);
1355 } 1362 }
@@ -2965,10 +2972,11 @@ static int __net_init xfrm_policy_init(struct net *net)
2965 goto out_byidx; 2972 goto out_byidx;
2966 net->xfrm.policy_idx_hmask = hmask; 2973 net->xfrm.policy_idx_hmask = hmask;
2967 2974
2968 for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { 2975 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
2969 struct xfrm_policy_hash *htab; 2976 struct xfrm_policy_hash *htab;
2970 2977
2971 net->xfrm.policy_count[dir] = 0; 2978 net->xfrm.policy_count[dir] = 0;
2979 net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0;
2972 INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); 2980 INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]);
2973 2981
2974 htab = &net->xfrm.policy_bydst[dir]; 2982 htab = &net->xfrm.policy_bydst[dir];
@@ -3020,7 +3028,7 @@ static void xfrm_policy_fini(struct net *net)
3020 3028
3021 WARN_ON(!list_empty(&net->xfrm.policy_all)); 3029 WARN_ON(!list_empty(&net->xfrm.policy_all));
3022 3030
3023 for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { 3031 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
3024 struct xfrm_policy_hash *htab; 3032 struct xfrm_policy_hash *htab;
3025 3033
3026 WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); 3034 WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));