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

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>

authored by

Florian Westphal and committed by
Steffen Klassert
cc1bb845 a927d6af

+11 -2
+11 -2
net/xfrm/xfrm_policy.c
··· 365 365 hash = __sel_hash(sel, family, hmask, dbits, sbits); 366 366 367 367 if (hash == hmask + 1) 368 - return &net->xfrm.policy_inexact[dir]; 368 + return NULL; 369 369 370 370 return rcu_dereference_check(net->xfrm.policy_bydst[dir].table, 371 371 lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash; ··· 625 625 chain = policy_hash_bysel(net, &policy->selector, 626 626 policy->family, 627 627 xfrm_policy_id2dir(policy->index)); 628 + if (!chain) 629 + chain = &net->xfrm.policy_inexact[dir]; 628 630 hlist_for_each_entry(pol, chain, bydst) { 629 631 if (policy->priority >= pol->priority) 630 632 newpos = &pol->bydst; ··· 783 781 784 782 spin_lock_bh(&net->xfrm.xfrm_policy_lock); 785 783 chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); 786 - delpol = xfrm_policy_insert_list(chain, policy, excl); 784 + if (chain) { 785 + delpol = xfrm_policy_insert_list(chain, policy, excl); 786 + } else { 787 + chain = &net->xfrm.policy_inexact[dir]; 788 + delpol = xfrm_policy_insert_list(chain, policy, excl); 789 + } 787 790 788 791 if (IS_ERR(delpol)) { 789 792 spin_unlock_bh(&net->xfrm.xfrm_policy_lock); ··· 836 829 *err = 0; 837 830 spin_lock_bh(&net->xfrm.xfrm_policy_lock); 838 831 chain = policy_hash_bysel(net, sel, sel->family, dir); 832 + if (!chain) 833 + chain = &net->xfrm.policy_inexact[dir]; 839 834 ret = NULL; 840 835 hlist_for_each_entry(pol, chain, bydst) { 841 836 if (pol->type == type &&