summaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2018-11-07 23:00:34 +0100
committerSteffen Klassert <steffen.klassert@secunet.com>2018-11-09 11:57:38 +0100
commitcc1bb845adc9b3a005cbb67fd18c69af1c3aec94 (patch)
tree1b1df1df439b2b48baa662c432b39bc1d63b3c9a /net/xfrm/xfrm_policy.c
parenta927d6af53eec08661628e3992d74736e848a743 (diff)
downloadlinux-cc1bb845adc9b3a005cbb67fd18c69af1c3aec94.tar.gz
linux-cc1bb845adc9b3a005cbb67fd18c69af1c3aec94.tar.bz2
linux-cc1bb845adc9b3a005cbb67fd18c69af1c3aec94.zip
xfrm: policy: return NULL when inexact search needed
currently policy_hash_bysel() returns the hash bucket list (for exact policies), or the inexact list (when policy uses a prefix). Searching this inexact list is slow, so it might be better to pre-sort inexact lists into a tree or another data structure for faster searching. However, due to 'any' policies, that need to be searched in any case, doing so will require that 'inexact' policies need to be handled specially to decide the best search strategy. So change hash_bysel() and return NULL if the policy can't be handled via the policy hash table. Right now, we simply use the inexact list when this happens, but future patch can then implement a different strategy. Signed-off-by: Florian Westphal <fw@strlen.de> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 20d6815be0d7..b00c265f6be3 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -365,7 +365,7 @@ static struct hlist_head *policy_hash_bysel(struct net *net,
hash = __sel_hash(sel, family, hmask, dbits, sbits);
if (hash == hmask + 1)
- return &net->xfrm.policy_inexact[dir];
+ return NULL;
return rcu_dereference_check(net->xfrm.policy_bydst[dir].table,
lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash;
@@ -625,6 +625,8 @@ static void xfrm_hash_rebuild(struct work_struct *work)
chain = policy_hash_bysel(net, &policy->selector,
policy->family,
xfrm_policy_id2dir(policy->index));
+ if (!chain)
+ chain = &net->xfrm.policy_inexact[dir];
hlist_for_each_entry(pol, chain, bydst) {
if (policy->priority >= pol->priority)
newpos = &pol->bydst;
@@ -781,7 +783,12 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
- delpol = xfrm_policy_insert_list(chain, policy, excl);
+ if (chain) {
+ delpol = xfrm_policy_insert_list(chain, policy, excl);
+ } else {
+ chain = &net->xfrm.policy_inexact[dir];
+ delpol = xfrm_policy_insert_list(chain, policy, excl);
+ }
if (IS_ERR(delpol)) {
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
@@ -829,6 +836,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
*err = 0;
spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, sel, sel->family, dir);
+ if (!chain)
+ chain = &net->xfrm.policy_inexact[dir];
ret = NULL;
hlist_for_each_entry(pol, chain, bydst) {
if (pol->type == type &&