[XFRM]: Respect priority in policy lookups.
authorDavid S. Miller <davem@sunset.davemloft.net>
Fri, 25 Aug 2006 22:46:46 +0000 (15:46 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Fri, 22 Sep 2006 22:18:05 +0000 (15:18 -0700)
Even if we find an exact match in the hash table,
we must inspect the inexact list to look for a match
with a better priority.

Noticed by Masahide NAKAMURA <nakam@linux-ipv6.org>.

Signed-off-by: David S. Miller <davem@davemloft.net>
net/xfrm/xfrm_policy.c

index b446ca3..1cf3209 100644 (file)
@@ -908,6 +908,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
        xfrm_address_t *daddr, *saddr;
        struct hlist_node *entry;
        struct hlist_head *chain;
+       u32 priority = ~0U;
 
        daddr = xfrm_flowi_daddr(fl, family);
        saddr = xfrm_flowi_saddr(fl, family);
@@ -919,21 +920,21 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
        ret = NULL;
        hlist_for_each_entry(pol, entry, chain, bydst) {
                if (xfrm_policy_match(pol, fl, type, family, dir)) {
-                       xfrm_pol_hold(pol);
                        ret = pol;
+                       priority = ret->priority;
                        break;
                }
        }
-       if (!ret) {
-               chain = &xfrm_policy_inexact[dir];
-               hlist_for_each_entry(pol, entry, chain, bydst) {
-                       if (xfrm_policy_match(pol, fl, type, family, dir)) {
-                               xfrm_pol_hold(pol);
-                               ret = pol;
-                               break;
-                       }
+       chain = &xfrm_policy_inexact[dir];
+       hlist_for_each_entry(pol, entry, chain, bydst) {
+               if (xfrm_policy_match(pol, fl, type, family, dir) &&
+                   pol->priority < priority) {
+                       ret = pol;
+                       break;
                }
        }
+       if (ret)
+               xfrm_pol_hold(ret);
        read_unlock_bh(&xfrm_policy_lock);
 
        return ret;