Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Herbert Xu and committed by
Steffen Klassert
53c2e285 f293a5e3

+28 -20
+2 -2
include/net/netns/xfrm.h
··· 50 50 struct list_head policy_all; 51 51 struct hlist_head *policy_byidx; 52 52 unsigned int policy_idx_hmask; 53 - struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; 54 - struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; 53 + struct hlist_head policy_inexact[XFRM_POLICY_MAX]; 54 + struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX]; 55 55 unsigned int policy_count[XFRM_POLICY_MAX * 2]; 56 56 struct work_struct policy_hash_work; 57 57 struct xfrm_policy_hthresh policy_hthresh;
+26 -18
net/xfrm/xfrm_policy.c
··· 561 561 mutex_lock(&hash_resize_mutex); 562 562 563 563 total = 0; 564 - for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { 564 + for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { 565 565 if (xfrm_bydst_should_resize(net, dir, &total)) 566 566 xfrm_bydst_resize(net, dir); 567 567 } ··· 601 601 write_lock_bh(&net->xfrm.xfrm_policy_lock); 602 602 603 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 605 INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); 606 606 hmask = net->xfrm.policy_bydst[dir].hmask; 607 607 odst = net->xfrm.policy_bydst[dir].table; ··· 1247 1247 static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) 1248 1248 { 1249 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 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 1252 net->xfrm.policy_count[dir]++; 1257 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 1263 1256 static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, ··· 1258 1265 { 1259 1266 struct net *net = xp_net(pol); 1260 1267 1261 - if (hlist_unhashed(&pol->bydst)) 1268 + if (list_empty(&pol->walk.all)) 1262 1269 return NULL; 1263 1270 1264 - hlist_del_init(&pol->bydst); 1265 - hlist_del(&pol->byidx); 1266 - list_del(&pol->walk.all); 1271 + /* Socket policies are not hashed. */ 1272 + if (!hlist_unhashed(&pol->bydst)) { 1273 + hlist_del(&pol->bydst); 1274 + hlist_del(&pol->byidx); 1275 + } 1276 + 1277 + list_del_init(&pol->walk.all); 1267 1278 net->xfrm.policy_count[dir]--; 1268 1279 1269 1280 return pol; 1281 + } 1282 + 1283 + static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) 1284 + { 1285 + __xfrm_policy_link(pol, XFRM_POLICY_MAX + dir); 1286 + } 1287 + 1288 + static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) 1289 + { 1290 + __xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir); 1270 1291 } 1271 1292 1272 1293 int xfrm_policy_delete(struct xfrm_policy *pol, int dir) ··· 1314 1307 if (pol) { 1315 1308 pol->curlft.add_time = get_seconds(); 1316 1309 pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); 1317 - __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); 1310 + xfrm_sk_policy_link(pol, dir); 1318 1311 } 1319 1312 if (old_pol) { 1320 1313 if (pol) ··· 1323 1316 /* Unlinking succeeds always. This is the only function 1324 1317 * allowed to delete or replace socket policy. 1325 1318 */ 1326 - __xfrm_policy_unlink(old_pol, XFRM_POLICY_MAX+dir); 1319 + xfrm_sk_policy_unlink(old_pol, dir); 1327 1320 } 1328 1321 write_unlock_bh(&net->xfrm.xfrm_policy_lock); 1329 1322 ··· 1356 1349 memcpy(newp->xfrm_vec, old->xfrm_vec, 1357 1350 newp->xfrm_nr*sizeof(struct xfrm_tmpl)); 1358 1351 write_lock_bh(&net->xfrm.xfrm_policy_lock); 1359 - __xfrm_policy_link(newp, XFRM_POLICY_MAX+dir); 1352 + xfrm_sk_policy_link(newp, dir); 1360 1353 write_unlock_bh(&net->xfrm.xfrm_policy_lock); 1361 1354 xfrm_pol_put(newp); 1362 1355 } ··· 2972 2965 goto out_byidx; 2973 2966 net->xfrm.policy_idx_hmask = hmask; 2974 2967 2975 - for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { 2968 + for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { 2976 2969 struct xfrm_policy_hash *htab; 2977 2970 2978 2971 net->xfrm.policy_count[dir] = 0; 2972 + net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0; 2979 2973 INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); 2980 2974 2981 2975 htab = &net->xfrm.policy_bydst[dir]; ··· 3028 3020 3029 3021 WARN_ON(!list_empty(&net->xfrm.policy_all)); 3030 3022 3031 - for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { 3023 + for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { 3032 3024 struct xfrm_policy_hash *htab; 3033 3025 3034 3026 WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir]));