Remove policies in kernel interfaces based on their priority.
authorTobias Brunner <tobias@strongswan.org>
Wed, 27 Jul 2011 11:41:35 +0000 (13:41 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 27 Jul 2011 11:41:35 +0000 (13:41 +0200)
This allows to unroute a connection while the same connection is
currently established.  In this case both CHILD_SAs share the same
reqid but the installed policies have different priorities.

src/libcharon/plugins/load_tester/load_tester_ipsec.c
src/libcharon/sa/child_sa.c
src/libcharon/sa/shunt_manager.c
src/libhydra/kernel/kernel_interface.c
src/libhydra/kernel/kernel_interface.h
src/libhydra/kernel/kernel_ipsec.h
src/libhydra/plugins/kernel_klips/kernel_klips_ipsec.c
src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/libhydra/plugins/kernel_pfkey/kernel_pfkey_ipsec.c
src/pluto/kernel.c

index e8c02b9..f76f298 100644 (file)
@@ -86,7 +86,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
           private_load_tester_ipsec_t *this, host_t *src, host_t *dst,
           traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
           policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
-          mark_t mark, bool routed)
+          mark_t mark, policy_priority_t priority)
 {
        return SUCCESS;
 }
@@ -103,7 +103,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
 METHOD(kernel_ipsec_t, del_policy, status_t,
           private_load_tester_ipsec_t *this, traffic_selector_t *src_ts,
           traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
-          mark_t mark, bool unrouted)
+          mark_t mark, policy_priority_t priority)
 {
        return SUCCESS;
 }
index 870ba8d..4c97b52 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2010 Tobias Brunner
+ * Copyright (C) 2006-2011 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2006 Daniel Roethlisberger
  * Copyright (C) 2005 Jan Hutter
@@ -664,7 +664,6 @@ METHOD(child_sa_t, add_policies, status_t,
        enumerator_t *enumerator;
        traffic_selector_t *my_ts, *other_ts;
        status_t status = SUCCESS;
-       bool routed = (this->state == CHILD_CREATED);
 
        /* apply traffic selectors */
        enumerator = my_ts_list->create_enumerator(my_ts_list);
@@ -682,6 +681,7 @@ METHOD(child_sa_t, add_policies, status_t,
 
        if (this->config->install_policy(this->config))
        {
+               policy_priority_t priority;
                ipsec_sa_cfg_t my_sa = {
                        .mode = this->mode,
                        .reqid = this->reqid,
@@ -708,6 +708,9 @@ METHOD(child_sa_t, add_policies, status_t,
                        other_sa.ah.spi = this->other_spi;
                }
 
+               priority = this->state == CHILD_CREATED ? POLICY_PRIORITY_ROUTED
+                                                                                               : POLICY_PRIORITY_DEFAULT;
+
                /* enumerate pairs of traffic selectors */
                enumerator = create_policy_enumerator(this);
                while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
@@ -717,20 +720,20 @@ METHOD(child_sa_t, add_policies, status_t,
                                                        hydra->kernel_interface,
                                                        this->my_addr, this->other_addr, my_ts, other_ts,
                                                        POLICY_OUT, POLICY_IPSEC, &other_sa,
-                                                       this->mark_out, routed);
+                                                       this->mark_out, priority);
 
                        status |= hydra->kernel_interface->add_policy(
                                                        hydra->kernel_interface,
                                                        this->other_addr, this->my_addr, other_ts, my_ts,
                                                        POLICY_IN, POLICY_IPSEC, &my_sa,
-                                                       this->mark_in, routed);
+                                                       this->mark_in, priority);
                        if (this->mode != MODE_TRANSPORT)
                        {
                                status |= hydra->kernel_interface->add_policy(
                                                        hydra->kernel_interface,
                                                        this->other_addr, this->my_addr, other_ts, my_ts,
                                                        POLICY_FWD, POLICY_IPSEC, &my_sa,
-                                                       this->mark_in, routed);
+                                                       this->mark_in, priority);
                        }
 
                        if (status != SUCCESS)
@@ -838,15 +841,15 @@ METHOD(child_sa_t, update, status_t,
                                /* remove old policies first */
                                hydra->kernel_interface->del_policy(hydra->kernel_interface,
                                                        my_ts, other_ts, POLICY_OUT, this->reqid,
-                                                       this->mark_out, FALSE);
+                                                       this->mark_out, POLICY_PRIORITY_DEFAULT);
                                hydra->kernel_interface->del_policy(hydra->kernel_interface,
                                                        other_ts, my_ts,  POLICY_IN, this->reqid,
-                                                       this->mark_in, FALSE);
+                                                       this->mark_in, POLICY_PRIORITY_DEFAULT);
                                if (this->mode != MODE_TRANSPORT)
                                {
                                        hydra->kernel_interface->del_policy(hydra->kernel_interface,
                                                        other_ts, my_ts, POLICY_FWD, this->reqid,
-                                                       this->mark_in, FALSE);
+                                                       this->mark_in, POLICY_PRIORITY_DEFAULT);
                                }
 
                                /* check whether we have to update a "dynamic" traffic selector */
@@ -872,15 +875,15 @@ METHOD(child_sa_t, update, status_t,
                                /* reinstall updated policies */
                                hydra->kernel_interface->add_policy(hydra->kernel_interface,
                                                me, other, my_ts, other_ts, POLICY_OUT, POLICY_IPSEC,
-                                               &other_sa, this->mark_out, FALSE);
+                                               &other_sa, this->mark_out, POLICY_PRIORITY_DEFAULT);
                                hydra->kernel_interface->add_policy(hydra->kernel_interface,
                                                other, me, other_ts, my_ts, POLICY_IN, POLICY_IPSEC,
-                                               &my_sa, this->mark_in, FALSE);
+                                               &my_sa, this->mark_in, POLICY_PRIORITY_DEFAULT);
                                if (this->mode != MODE_TRANSPORT)
                                {
                                        hydra->kernel_interface->add_policy(hydra->kernel_interface,
                                                other, me, other_ts, my_ts, POLICY_FWD, POLICY_IPSEC,
-                                               &my_sa, this->mark_in, FALSE);
+                                               &my_sa, this->mark_in, POLICY_PRIORITY_DEFAULT);
                                }
                        }
                        enumerator->destroy(enumerator);
@@ -913,7 +916,10 @@ METHOD(child_sa_t, destroy, void,
 {
        enumerator_t *enumerator;
        traffic_selector_t *my_ts, *other_ts;
-       bool unrouted = (this->state == CHILD_ROUTED);
+       policy_priority_t priority;
+
+       priority = this->state == CHILD_ROUTED ? POLICY_PRIORITY_ROUTED
+                                                                                  : POLICY_PRIORITY_DEFAULT;
 
        set_state(this, CHILD_DESTROYING);
 
@@ -947,15 +953,15 @@ METHOD(child_sa_t, destroy, void,
                {
                        hydra->kernel_interface->del_policy(hydra->kernel_interface,
                                                my_ts, other_ts, POLICY_OUT, this->reqid,
-                                               this->mark_out, unrouted);
+                                               this->mark_out, priority);
                        hydra->kernel_interface->del_policy(hydra->kernel_interface,
                                                other_ts, my_ts, POLICY_IN, this->reqid,
-                                               this->mark_in, unrouted);
+                                               this->mark_in, priority);
                        if (this->mode != MODE_TRANSPORT)
                        {
                                hydra->kernel_interface->del_policy(hydra->kernel_interface,
                                                other_ts, my_ts, POLICY_FWD, this->reqid,
-                                               this->mark_in, unrouted);
+                                               this->mark_in, priority);
                        }
                }
                enumerator->destroy(enumerator);
index accebe6..52b2ecd 100644 (file)
@@ -69,19 +69,22 @@ static bool install_shunt_policy(child_cfg_t *child)
                        status |= hydra->kernel_interface->add_policy(
                                                                hydra->kernel_interface, host_any, host_any,
                                                                my_ts, other_ts, POLICY_OUT, policy_type,
-                                                               &sa, child->get_mark(child, FALSE), FALSE);
+                                                               &sa, child->get_mark(child, FALSE),
+                                                               POLICY_PRIORITY_DEFAULT);
 
                        /* install in policy */
                        status |= hydra->kernel_interface->add_policy(
                                                                hydra->kernel_interface, host_any, host_any,
                                                                other_ts, my_ts, POLICY_IN, policy_type,
-                                                               &sa, child->get_mark(child, TRUE), FALSE);
+                                                               &sa, child->get_mark(child, TRUE),
+                                                               POLICY_PRIORITY_DEFAULT);
 
                        /* install forward policy */
                        status |= hydra->kernel_interface->add_policy(
                                                                hydra->kernel_interface, host_any, host_any,
                                                                other_ts, my_ts, POLICY_FWD, policy_type,
-                                                               &sa, child->get_mark(child, TRUE), FALSE);
+                                                               &sa, child->get_mark(child, TRUE),
+                                                               POLICY_PRIORITY_DEFAULT);
                }
                e_other_ts->destroy(e_other_ts);
        }
@@ -150,19 +153,19 @@ static void uninstall_shunt_policy(child_cfg_t *child)
                        status |= hydra->kernel_interface->del_policy(
                                                        hydra->kernel_interface, my_ts, other_ts,
                                                        POLICY_OUT, 0, child->get_mark(child, FALSE),
-                                                       FALSE);
+                                                       POLICY_PRIORITY_DEFAULT);
 
                        /* uninstall in policy */
                        status |= hydra->kernel_interface->del_policy(
                                                        hydra->kernel_interface, other_ts, my_ts,
                                                        POLICY_IN, 0, child->get_mark(child, TRUE),
-                                                       FALSE);
+                                                       POLICY_PRIORITY_DEFAULT);
 
                        /* uninstall forward policy */
                        status |= hydra->kernel_interface->del_policy(
                                                        hydra->kernel_interface, other_ts, my_ts,
                                                        POLICY_FWD, 0, child->get_mark(child, TRUE),
-                                                       FALSE);
+                                                       POLICY_PRIORITY_DEFAULT);
                }
                e_other_ts->destroy(e_other_ts);
        }
index 8228d26..ebe653e 100644 (file)
@@ -132,14 +132,14 @@ METHOD(kernel_interface_t, add_policy, status_t,
        private_kernel_interface_t *this, host_t *src, host_t *dst,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
        policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
-       mark_t mark, bool routed)
+       mark_t mark, policy_priority_t priority)
 {
        if (!this->ipsec)
        {
                return NOT_SUPPORTED;
        }
        return this->ipsec->add_policy(this->ipsec, src, dst, src_ts, dst_ts,
-                                                                  direction, type, sa, mark, routed);
+                                                                  direction, type, sa, mark, priority);
 }
 
 METHOD(kernel_interface_t, query_policy, status_t,
@@ -158,14 +158,14 @@ METHOD(kernel_interface_t, query_policy, status_t,
 METHOD(kernel_interface_t, del_policy, status_t,
        private_kernel_interface_t *this, traffic_selector_t *src_ts,
        traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
-       mark_t mark, bool unrouted)
+       mark_t mark, policy_priority_t priority)
 {
        if (!this->ipsec)
        {
                return NOT_SUPPORTED;
        }
        return this->ipsec->del_policy(this->ipsec, src_ts, dst_ts,
-                                                                  direction, reqid, mark, unrouted);
+                                                                  direction, reqid, mark, priority);
 }
 
 METHOD(kernel_interface_t, get_source_addr, host_t*,
index a7f8e26..4c2f7ef 100644 (file)
@@ -188,7 +188,7 @@ struct kernel_interface_t {
         * @param type                  type of policy, POLICY_(IPSEC|PASS|DROP)
         * @param sa                    details about the SA(s) tied to this policy
         * @param mark                  mark for this policy
-        * @param routed                TRUE, if this policy is routed in the kernel
+        * @param priority              priority of this policy
         * @return                              SUCCESS if operation completed
         */
        status_t (*add_policy) (kernel_interface_t *this,
@@ -196,7 +196,8 @@ struct kernel_interface_t {
                                                        traffic_selector_t *src_ts,
                                                        traffic_selector_t *dst_ts,
                                                        policy_dir_t direction, policy_type_t type,
-                                                       ipsec_sa_cfg_t *sa, mark_t mark, bool routed);
+                                                       ipsec_sa_cfg_t *sa, mark_t mark,
+                                                       policy_priority_t priority);
 
        /**
         * Query the use time of a policy.
@@ -230,14 +231,14 @@ struct kernel_interface_t {
         * @param direction             direction of traffic, POLICY_(IN|OUT|FWD)
         * @param reqid                 unique ID of the associated SA
         * @param mark                  optional mark
-        * @param unrouted              TRUE, if this policy is unrouted from the kernel
+        * @param priority              priority of the policy
         * @return                              SUCCESS if operation completed
         */
        status_t (*del_policy) (kernel_interface_t *this,
                                                        traffic_selector_t *src_ts,
                                                        traffic_selector_t *dst_ts,
                                                        policy_dir_t direction, u_int32_t reqid,
-                                                       mark_t mark, bool unrouted);
+                                                       mark_t mark, policy_priority_t priority);
 
        /**
         * Get our outgoing source address for a destination.
index f1122db..3759459 100644 (file)
@@ -27,6 +27,7 @@
 typedef enum ipsec_mode_t ipsec_mode_t;
 typedef enum policy_dir_t policy_dir_t;
 typedef enum policy_type_t policy_type_t;
+typedef enum policy_priority_t policy_priority_t;
 typedef enum ipcomp_transform_t ipcomp_transform_t;
 typedef struct kernel_ipsec_t kernel_ipsec_t;
 typedef struct ipsec_sa_cfg_t ipsec_sa_cfg_t;
@@ -90,6 +91,16 @@ enum policy_type_t {
 };
 
 /**
+ * High-level priority of a policy.
+ */
+enum policy_priority_t {
+       /** Default priority */
+       POLICY_PRIORITY_DEFAULT,
+       /** Priority for trap policies */
+       POLICY_PRIORITY_ROUTED,
+};
+
+/**
  * IPComp transform IDs, as in RFC 4306
  */
 enum ipcomp_transform_t {
@@ -305,7 +316,7 @@ struct kernel_ipsec_t {
         * @param type                  type of policy, POLICY_(IPSEC|PASS|DROP)
         * @param sa                    details about the SA(s) tied to this policy
         * @param mark                  mark for this policy
-        * @param routed                TRUE, if this policy is routed in the kernel
+        * @param priority              priority of this policy
         * @return                              SUCCESS if operation completed
         */
        status_t (*add_policy) (kernel_ipsec_t *this,
@@ -313,7 +324,8 @@ struct kernel_ipsec_t {
                                                        traffic_selector_t *src_ts,
                                                        traffic_selector_t *dst_ts,
                                                        policy_dir_t direction, policy_type_t type,
-                                                       ipsec_sa_cfg_t *sa, mark_t mark, bool routed);
+                                                       ipsec_sa_cfg_t *sa, mark_t mark,
+                                                       policy_priority_t priority);
 
        /**
         * Query the use time of a policy.
@@ -348,14 +360,14 @@ struct kernel_ipsec_t {
         * @param direction             direction of traffic, POLICY_(IN|OUT|FWD)
         * @param reqid                 unique ID of the associated SA
         * @param mark                  optional mark
-        * @param unrouted              TRUE, if this policy is unrouted from the kernel
+        * @param priority              priority of the policy
         * @return                              SUCCESS if operation completed
         */
        status_t (*del_policy) (kernel_ipsec_t *this,
                                                        traffic_selector_t *src_ts,
                                                        traffic_selector_t *dst_ts,
                                                        policy_dir_t direction, u_int32_t reqid,
-                                                       mark_t mark, bool unrouted);
+                                                       mark_t mark, policy_priority_t priority);
 
        /**
         * Install a bypass policy for the given socket.
index aca00dd..25287aa 100644 (file)
@@ -1971,7 +1971,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        private_kernel_klips_ipsec_t *this, host_t *src, host_t *dst,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
        policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
-       mark_t mark, bool routed)
+       mark_t mark, policy_priority_t priority)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
        struct sadb_msg *msg, *out;
@@ -2013,7 +2013,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
                this->policies->insert_last(this->policies, policy);
        }
 
-       if (routed)
+       if (priority == POLICY_PRIORITY_ROUTED)
        {
                /* we install this as a %trap eroute in the kernel, later to be
                 * triggered by packets matching the policy (-> ACQUIRE). */
@@ -2049,9 +2049,11 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        msg = (struct sadb_msg*)request;
 
        /* FIXME: SADB_X_SAFLAGS_INFLOW may be required, if we add an inbound policy for an IPIP SA */
-       build_addflow(msg, satype, spi, routed ? NULL : src, routed ? NULL : dst,
-                       policy->src.net, policy->src.mask, policy->dst.net, policy->dst.mask,
-                       policy->src.proto, found != NULL);
+       build_addflow(msg, satype, spi,
+                                 priority == POLICY_PRIORITY_ROUTED ? NULL : src,
+                                 priority == POLICY_PRIORITY_ROUTED ? NULL : dst,
+                                 policy->src.net, policy->src.mask, policy->dst.net,
+                                 policy->dst.mask, policy->src.proto, found != NULL);
 
        this->mutex->unlock(this->mutex);
 
@@ -2348,7 +2350,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
 METHOD(kernel_ipsec_t, del_policy, status_t,
        private_kernel_klips_ipsec_t *this, traffic_selector_t *src_ts,
        traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
-       mark_t mark, bool unrouted)
+       mark_t mark, policy_priority_t priority)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
        struct sadb_msg *msg = (struct sadb_msg*)request, *out;
@@ -2382,7 +2384,8 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        policy_entry_destroy(policy);
 
        /* decrease appropriate counter */
-       unrouted ? found->trapcount-- : found->activecount--;
+       priority == POLICY_PRIORITY_ROUTED ? found->trapcount--
+                                                                          : found->activecount--;
 
        if (found->trapcount == 0)
        {
index 9f906fc..26919a6 100644 (file)
@@ -59,8 +59,7 @@
 #endif /*IPV6_XFRM_POLICY*/
 
 /** Default priority of installed policies */
-#define PRIO_LOW 1024
-#define PRIO_HIGH 512
+#define PRIO_BASE 512
 
 /** Default replay window size, if not set using charon.replay_window */
 #define DEFAULT_REPLAY_WINDOW 32
@@ -568,6 +567,30 @@ static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
 }
 
 /**
+ * Calculate the priority of a policy
+ */
+static inline u_int32_t get_priority(policy_entry_t *policy,
+                                                                        policy_priority_t prio)
+{
+       u_int32_t priority = PRIO_BASE;
+       switch (prio)
+       {
+               case POLICY_PRIORITY_ROUTED:
+                       priority <<= 1;
+                       /* fall-through */
+               case POLICY_PRIORITY_DEFAULT:
+                       break;
+       }
+       /* calculate priority based on selector size, small size = high prio */
+       priority -= policy->sel.prefixlen_s;
+       priority -= policy->sel.prefixlen_d;
+       priority <<= 2; /* make some room for the two flags */
+       priority += policy->sel.sport_mask || policy->sel.dport_mask ? 0 : 2;
+       priority += policy->sel.proto ? 0 : 1;
+       return priority;
+}
+
+/**
  * Convert the general ipsec mode to the one defined in xfrm.h
  */
 static u_int8_t mode2kernel(ipsec_mode_t mode)
@@ -2149,7 +2172,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        private_kernel_netlink_ipsec_t *this, host_t *src, host_t *dst,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
        policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
-       mark_t mark, bool routed)
+       mark_t mark, policy_priority_t priority)
 {
        policy_entry_t *policy, *current;
        policy_sa_t *assigned_sa, *current_sa;
@@ -2195,15 +2218,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        /* cache the assigned IPsec SA */
        assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
                                                                   dst_ts, mark, sa);
-
-       /* calculate priority based on selector size, small size = high prio */
-       assigned_sa->priority = routed ? PRIO_LOW : PRIO_HIGH;
-       assigned_sa->priority -= policy->sel.prefixlen_s;
-       assigned_sa->priority -= policy->sel.prefixlen_d;
-       assigned_sa->priority <<= 2; /* make some room for the two flags */
-       assigned_sa->priority += policy->sel.sport_mask ||
-                                                        policy->sel.dport_mask ? 0 : 2;
-       assigned_sa->priority += policy->sel.proto ? 0 : 1;
+       assigned_sa->priority = get_priority(policy, priority);
 
        /* insert the SA according to its priority */
        enumerator = policy->used_by->create_enumerator(policy->used_by);
@@ -2354,7 +2369,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
 METHOD(kernel_ipsec_t, del_policy, status_t,
        private_kernel_netlink_ipsec_t *this, traffic_selector_t *src_ts,
        traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
-       mark_t mark, bool unrouted)
+       mark_t mark, policy_priority_t prio)
 {
        policy_entry_t *current, policy;
        enumerator_t *enumerator;
@@ -2363,6 +2378,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        struct nlmsghdr *hdr;
        struct xfrm_userpolicy_id *policy_id;
        bool is_installed = TRUE;
+       u_int32_t priority;
 
        if (mark.value)
        {
@@ -2402,11 +2418,12 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
                return NOT_FOUND;
        }
 
-       /* remove mapping to SA by reqid */
+       /* remove mapping to SA by reqid and priority */
+       priority = get_priority(current, prio);
        enumerator = current->used_by->create_enumerator(current->used_by);
        while (enumerator->enumerate(enumerator, (void**)&mapping))
        {
-               if (reqid == mapping->sa->cfg.reqid)
+               if (reqid == mapping->sa->cfg.reqid && priority == mapping->priority)
                {
                        current->used_by->remove_at(current->used_by, enumerator);
                        policy_sa_destroy(mapping, &direction, this);
index efdf9c9..f96dbcf 100644 (file)
 #endif
 
 /** default priority of installed policies */
-#define PRIO_LOW 1024
-#define PRIO_HIGH 512
+#define PRIO_BASE 512
 
 #ifdef __APPLE__
 /** from xnu/bsd/net/pfkeyv2.h */
@@ -501,6 +500,32 @@ static inline bool policy_entry_match_byindex(policy_entry_t *current,
        return current->index == *index;
 }
 
+/**
+ * Calculate the priority of a policy
+ */
+static inline u_int32_t get_priority(policy_entry_t *policy,
+                                                                        policy_priority_t prio)
+{
+       u_int32_t priority = PRIO_BASE;
+       switch (prio)
+       {
+               case POLICY_PRIORITY_ROUTED:
+                       priority <<= 1;
+                       /* fall-through */
+               case POLICY_PRIORITY_DEFAULT:
+                       break;
+       }
+       /* calculate priority based on selector size, small size = high prio */
+       priority -= policy->src.mask;
+       priority -= policy->dst.mask;
+       priority <<= 2; /* make some room for the two flags */
+       priority += policy->src.net->get_port(policy->src.net) ||
+                               policy->dst.net->get_port(policy->dst.net) ?
+                               0 : 2;
+       priority += policy->src.proto != IPSEC_PROTO_ANY ? 0 : 1;
+       return priority;
+}
+
 typedef struct pfkey_msg_t pfkey_msg_t;
 
 struct pfkey_msg_t
@@ -2008,7 +2033,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        private_kernel_pfkey_ipsec_t *this, host_t *src, host_t *dst,
        traffic_selector_t *src_ts, traffic_selector_t *dst_ts,
        policy_dir_t direction, policy_type_t type, ipsec_sa_cfg_t *sa,
-       mark_t mark, bool routed)
+       mark_t mark, policy_priority_t priority)
 {
        policy_entry_t *policy, *found = NULL;
        policy_sa_t *assigned_sa, *current_sa;
@@ -2043,17 +2068,7 @@ METHOD(kernel_ipsec_t, add_policy, status_t,
        /* cache the assigned IPsec SA */
        assigned_sa = policy_sa_create(this, direction, type, src, dst, src_ts,
                                                                   dst_ts, sa);
-
-
-       /* calculate priority based on selector size, small size = high prio */
-       assigned_sa->priority = routed ? PRIO_LOW : PRIO_HIGH;
-       assigned_sa->priority -= policy->src.mask;
-       assigned_sa->priority -= policy->dst.mask;
-       assigned_sa->priority <<= 2; /* make some room for the two flags */
-       assigned_sa->priority += policy->src.net->get_port(policy->src.net) ||
-                                                        policy->dst.net->get_port(policy->dst.net) ?
-                                                        0 : 2;
-       assigned_sa->priority += policy->src.proto != IPSEC_PROTO_ANY ? 0 : 1;
+       assigned_sa->priority = get_priority(policy, priority);
 
        /* insert the SA according to its priority */
        enumerator = policy->used_by->create_enumerator(policy->used_by);
@@ -2197,7 +2212,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
 METHOD(kernel_ipsec_t, del_policy, status_t,
        private_kernel_pfkey_ipsec_t *this, traffic_selector_t *src_ts,
        traffic_selector_t *dst_ts, policy_dir_t direction, u_int32_t reqid,
-       mark_t mark, bool unrouted)
+       mark_t mark, policy_priority_t prio)
 {
        unsigned char request[PFKEY_BUFFER_SIZE];
        struct sadb_msg *msg, *out;
@@ -2206,6 +2221,7 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        policy_sa_t *mapping;
        enumerator_t *enumerator;
        bool is_installed = TRUE;
+       u_int32_t priority;
        size_t len;
 
        if (dir2kernel(direction) == IPSEC_DIR_INVALID)
@@ -2234,11 +2250,12 @@ METHOD(kernel_ipsec_t, del_policy, status_t,
        policy_entry_destroy(policy, this);
        policy = found;
 
-       /* remove mapping to SA by reqid */
+       /* remove mapping to SA by reqid and priority */
+       priority = get_priority(policy, prio);
        enumerator = policy->used_by->create_enumerator(policy->used_by);
        while (enumerator->enumerate(enumerator, (void**)&mapping))
        {
-               if (reqid == mapping->sa->cfg.reqid)
+               if (reqid == mapping->sa->cfg.reqid && priority == mapping->priority)
                {
                        policy->used_by->remove_at(policy->used_by, enumerator);
                        break;
index c458b2d..13574f1 100644 (file)
@@ -780,8 +780,9 @@ static bool raw_eroute(const ip_address *this_host,
        host_t *host_src, *host_dst;
        policy_type_t type = POLICY_IPSEC;
        policy_dir_t dir = POLICY_OUT;
+       policy_priority_t priority = POLICY_PRIORITY_DEFAULT;
        char text_said[SATOT_BUF];
-       bool ok = TRUE, routed = FALSE,
+       bool ok = TRUE,
                 deleting = (op & ERO_MASK) == ERO_DELETE,
                 replacing = op & (SADB_X_SAFLAGS_REPLACEFLOW << ERO_FLAG_SHIFT);
 
@@ -819,7 +820,7 @@ static bool raw_eroute(const ip_address *this_host,
                                {
                                        return TRUE;
                                }
-                               routed = TRUE;
+                               priority = POLICY_PRIORITY_ROUTED;
                                break;
                }
        }
@@ -837,14 +838,14 @@ static bool raw_eroute(const ip_address *this_host,
        if (deleting || replacing)
        {
                hydra->kernel_interface->del_policy(hydra->kernel_interface,
-                                               ts_src, ts_dst, dir, sa->reqid, mark, routed);
+                                               ts_src, ts_dst, dir, sa->reqid, mark, priority);
        }
 
        if (!deleting)
        {
                ok = hydra->kernel_interface->add_policy(hydra->kernel_interface,
                                                host_src, host_dst, ts_src, ts_dst, dir, type, sa,
-                                               mark, routed) == SUCCESS;
+                                               mark, priority) == SUCCESS;
        }
 
        if (dir == POLICY_IN)
@@ -853,7 +854,7 @@ static bool raw_eroute(const ip_address *this_host,
                if (deleting || replacing)
                {
                        hydra->kernel_interface->del_policy(hydra->kernel_interface,
-                                               ts_src, ts_dst, dir, sa->reqid, mark, routed);
+                                               ts_src, ts_dst, dir, sa->reqid, mark, priority);
                }
 
                if (!deleting && ok &&
@@ -861,7 +862,7 @@ static bool raw_eroute(const ip_address *this_host,
                {
                        ok = hydra->kernel_interface->add_policy(hydra->kernel_interface,
                                                host_src, host_dst, ts_src, ts_dst, dir, type, sa,
-                                               mark, routed) == SUCCESS;
+                                               mark, priority) == SUCCESS;
                }
        }