implemented the policy cache in kernel_netlink_ipsec_t with a hash table instead...
authorTobias Brunner <tobias@strongswan.org>
Thu, 4 Dec 2008 16:46:08 +0000 (16:46 -0000)
committerTobias Brunner <tobias@strongswan.org>
Thu, 4 Dec 2008 16:46:08 +0000 (16:46 -0000)
src/charon/plugins/kernel_netlink/kernel_netlink_ipsec.c

index 2abbab4..8c472f2 100644 (file)
@@ -39,7 +39,7 @@
 
 #include <daemon.h>
 #include <utils/mutex.h>
-#include <utils/linked_list.h>
+#include <utils/hashtable.h>
 #include <processing/jobs/callback_job.h>
 #include <processing/jobs/acquire_job.h>
 #include <processing/jobs/migrate_job.h>
@@ -250,6 +250,24 @@ struct policy_entry_t {
        u_int refcount;
 };
 
+/**
+ * Hash function for policy_entry_t objects
+ */
+static u_int policy_hash(policy_entry_t *key)
+{
+       chunk_t chunk = chunk_create((void*)&key->sel, sizeof(struct xfrm_selector));
+       return chunk_hash(chunk);
+}
+
+/**
+ * Equality function for policy_entry_t objects
+ */
+static bool policy_equals(policy_entry_t *key, policy_entry_t *other_key)
+{
+       return memeq(&key->sel, &other_key->sel, sizeof(struct xfrm_selector)) &&
+                  key->direction == other_key->direction;
+}
+
 typedef struct private_kernel_netlink_ipsec_t private_kernel_netlink_ipsec_t;
 
 /**
@@ -267,9 +285,9 @@ struct private_kernel_netlink_ipsec_t {
        mutex_t *mutex;
        
        /**
-        * List of installed policies (policy_entry_t)
+        * Hash table of installed policies (policy_entry_t)
         */
-       linked_list_t *policies;
+       hashtable_t *policies;
                 
        /**
         * job receiving netlink events
@@ -1396,7 +1414,6 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this,
                                                   ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
                                                   bool routed)
 {
-       iterator_t *iterator;
        policy_entry_t *current, *policy;
        bool found = FALSE;
        netlink_buf_t request;
@@ -1411,27 +1428,21 @@ static status_t add_policy(private_kernel_netlink_ipsec_t *this,
        
        /* find the policy, which matches EXACTLY */
        this->mutex->lock(this->mutex);
-       iterator = this->policies->create_iterator(this->policies, TRUE);
-       while (iterator->iterate(iterator, (void**)&current))
+       current = this->policies->get(this->policies, policy);
+       if (current)
        {
-               if (memeq(&current->sel, &policy->sel, sizeof(struct xfrm_selector)) &&
-                       policy->direction == current->direction)
-               {
-                       /* use existing policy */
-                       current->refcount++;
-                       DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
-                                                 "refcount", src_ts, dst_ts,
-                                                  policy_dir_names, direction);
-                       free(policy);
-                       policy = current;
-                       found = TRUE;
-                       break;
-               }
+               /* use existing policy */
+               current->refcount++;
+               DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
+                                         "refcount", src_ts, dst_ts,
+                                          policy_dir_names, direction);
+               free(policy);
+               policy = current;
+               found = TRUE;
        }
-       iterator->destroy(iterator);
-       if (!found)
+       else
        {       /* apply the new one, if we have no such policy */
-               this->policies->insert_last(this->policies, policy);
+               this->policies->put(this->policies, policy, policy);
                policy->refcount = 1;
        }
        
@@ -1659,7 +1670,6 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this,
        netlink_buf_t request;
        struct nlmsghdr *hdr;
        struct xfrm_userpolicy_id *policy_id;
-       enumerator_t *enumerator;
        
        DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts,
                                   policy_dir_names, direction);
@@ -1671,28 +1681,21 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this,
        
        /* find the policy */
        this->mutex->lock(this->mutex);
-       enumerator = this->policies->create_enumerator(this->policies);
-       while (enumerator->enumerate(enumerator, &current))
+       current = this->policies->get(this->policies, &policy);
+       if (current)
        {
-               if (memeq(&current->sel, &policy.sel, sizeof(struct xfrm_selector)) &&
-                       policy.direction == current->direction)
+               to_delete = current;
+               if (--to_delete->refcount > 0)
                {
-                       to_delete = current;
-                       if (--to_delete->refcount > 0)
-                       {
-                               /* is used by more SAs, keep in kernel */
-                               DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
-                               this->mutex->unlock(this->mutex);
-                               enumerator->destroy(enumerator);
-                               return SUCCESS;
-                       }
-                       /* remove if last reference */
-                       this->policies->remove_at(this->policies, enumerator);
-                       break;
+                       /* is used by more SAs, keep in kernel */
+                       DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
+                       this->mutex->unlock(this->mutex);
+                       return SUCCESS;
                }
+               /* remove if last reference */
+               this->policies->remove(this->policies, to_delete);
        }
        this->mutex->unlock(this->mutex);
-       enumerator->destroy(enumerator);
        if (!to_delete)
        {
                DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts,
@@ -1741,9 +1744,18 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this,
  */
 static void destroy(private_kernel_netlink_ipsec_t *this)
 {
+       enumerator_t *enumerator;
+       policy_entry_t *policy;
+       
        this->job->cancel(this->job);
        close(this->socket_xfrm_events);
        this->socket_xfrm->destroy(this->socket_xfrm);
+       enumerator = this->policies->create_enumerator(this->policies);
+       while (enumerator->enumerate(enumerator, (void**)&policy))
+       {
+               free(policy);
+       }
+       enumerator->destroy(enumerator);
        this->policies->destroy(this->policies);
        this->mutex->destroy(this->mutex);
        free(this);
@@ -1834,7 +1846,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
        this->public.interface.destroy = (void(*)(kernel_ipsec_t*)) destroy;
 
        /* private members */
-       this->policies = linked_list_create();
+       this->policies = hashtable_create((hashtable_hash_t)policy_hash,
+                                                                         (hashtable_equals_t)policy_equals, 1);
        this->mutex = mutex_create(MUTEX_DEFAULT);
        this->install_routes = lib->settings->get_bool(lib->settings,
                                        "charon.install_routes", TRUE);