xfrm: Allow inserting policies with matching mark and different priorities
authorSteffen Klassert <steffen.klassert@secunet.com>
Mon, 11 Feb 2013 06:02:36 +0000 (07:02 +0100)
committerSteffen Klassert <steffen.klassert@secunet.com>
Mon, 11 Feb 2013 13:07:01 +0000 (14:07 +0100)
We currently can not insert policies with mark and mask
such that some flows would be matched from both policies.
We make this possible when the priority of these policies
are different. If both policies match a flow, the one with
the higher priority is used.

Reported-by: Emmanuel Thierry <emmanuel.thierry@telecom-bretagne.eu>
Reported-by: Romain Kuntz <r.kuntz@ipflavors.com>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
net/xfrm/xfrm_policy.c

index 456b11b0f049341d7ba731b66c3ab0f26b2c468a..257dfb18aef440dc2dd290a051ad4b8df9e4b4dc 100644 (file)
@@ -607,6 +607,21 @@ static void xfrm_policy_requeue(struct xfrm_policy *old,
        spin_unlock_bh(&pq->hold_queue.lock);
 }
 
+static bool xfrm_policy_mark_match(struct xfrm_policy *policy,
+                                  struct xfrm_policy *pol)
+{
+       u32 mark = policy->mark.v & policy->mark.m;
+
+       if (policy->mark.v == pol->mark.v && policy->mark.m == pol->mark.m)
+               return true;
+
+       if ((mark & pol->mark.m) == pol->mark.v &&
+           policy->priority == pol->priority)
+               return true;
+
+       return false;
+}
+
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
 {
        struct net *net = xp_net(policy);
@@ -614,7 +629,6 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        struct xfrm_policy *delpol;
        struct hlist_head *chain;
        struct hlist_node *entry, *newpos;
-       u32 mark = policy->mark.v & policy->mark.m;
 
        write_lock_bh(&xfrm_policy_lock);
        chain = policy_hash_bysel(net, &policy->selector, policy->family, dir);
@@ -623,7 +637,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        hlist_for_each_entry(pol, entry, chain, bydst) {
                if (pol->type == policy->type &&
                    !selector_cmp(&pol->selector, &policy->selector) &&
-                   (mark & pol->mark.m) == pol->mark.v &&
+                   xfrm_policy_mark_match(policy, pol) &&
                    xfrm_sec_ctx_match(pol->security, policy->security) &&
                    !WARN_ON(delpol)) {
                        if (excl) {