Commit cc1bb845 authored by Florian Westphal's avatar Florian Westphal Committed by Steffen Klassert

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: default avatarFlorian Westphal <fw@strlen.de>
Acked-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent a927d6af
...@@ -365,7 +365,7 @@ static struct hlist_head *policy_hash_bysel(struct net *net, ...@@ -365,7 +365,7 @@ static struct hlist_head *policy_hash_bysel(struct net *net,
hash = __sel_hash(sel, family, hmask, dbits, sbits); hash = __sel_hash(sel, family, hmask, dbits, sbits);
if (hash == hmask + 1) if (hash == hmask + 1)
return &net->xfrm.policy_inexact[dir]; return NULL;
return rcu_dereference_check(net->xfrm.policy_bydst[dir].table, return rcu_dereference_check(net->xfrm.policy_bydst[dir].table,
lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash; lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash;
...@@ -625,6 +625,8 @@ static void xfrm_hash_rebuild(struct work_struct *work) ...@@ -625,6 +625,8 @@ static void xfrm_hash_rebuild(struct work_struct *work)
chain = policy_hash_bysel(net, &policy->selector, chain = policy_hash_bysel(net, &policy->selector,
policy->family, policy->family,
xfrm_policy_id2dir(policy->index)); xfrm_policy_id2dir(policy->index));
if (!chain)
chain = &net->xfrm.policy_inexact[dir];
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
if (policy->priority >= pol->priority) if (policy->priority >= pol->priority)
newpos = &pol->bydst; newpos = &pol->bydst;
...@@ -781,7 +783,12 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) ...@@ -781,7 +783,12 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
spin_lock_bh(&net->xfrm.xfrm_policy_lock); spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); 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)) { if (IS_ERR(delpol)) {
spin_unlock_bh(&net->xfrm.xfrm_policy_lock); 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, ...@@ -829,6 +836,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u32 if_id,
*err = 0; *err = 0;
spin_lock_bh(&net->xfrm.xfrm_policy_lock); spin_lock_bh(&net->xfrm.xfrm_policy_lock);
chain = policy_hash_bysel(net, sel, sel->family, dir); chain = policy_hash_bysel(net, sel, sel->family, dir);
if (!chain)
chain = &net->xfrm.policy_inexact[dir];
ret = NULL; ret = NULL;
hlist_for_each_entry(pol, chain, bydst) { hlist_for_each_entry(pol, chain, bydst) {
if (pol->type == type && if (pol->type == type &&
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment