implemented the policy cache in kernel_netlink_ipsec_t with a hash table instead of a linked list.
This commit is contained in:
@@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
#include <daemon.h>
|
#include <daemon.h>
|
||||||
#include <utils/mutex.h>
|
#include <utils/mutex.h>
|
||||||
#include <utils/linked_list.h>
|
#include <utils/hashtable.h>
|
||||||
#include <processing/jobs/callback_job.h>
|
#include <processing/jobs/callback_job.h>
|
||||||
#include <processing/jobs/acquire_job.h>
|
#include <processing/jobs/acquire_job.h>
|
||||||
#include <processing/jobs/migrate_job.h>
|
#include <processing/jobs/migrate_job.h>
|
||||||
@@ -250,6 +250,24 @@ struct policy_entry_t {
|
|||||||
u_int refcount;
|
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;
|
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;
|
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
|
* 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,
|
ipsec_mode_t mode, u_int16_t ipcomp, u_int16_t cpi,
|
||||||
bool routed)
|
bool routed)
|
||||||
{
|
{
|
||||||
iterator_t *iterator;
|
|
||||||
policy_entry_t *current, *policy;
|
policy_entry_t *current, *policy;
|
||||||
bool found = FALSE;
|
bool found = FALSE;
|
||||||
netlink_buf_t request;
|
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 */
|
/* find the policy, which matches EXACTLY */
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
iterator = this->policies->create_iterator(this->policies, TRUE);
|
current = this->policies->get(this->policies, policy);
|
||||||
while (iterator->iterate(iterator, (void**)¤t))
|
if (current)
|
||||||
{
|
{
|
||||||
if (memeq(¤t->sel, &policy->sel, sizeof(struct xfrm_selector)) &&
|
/* use existing policy */
|
||||||
policy->direction == current->direction)
|
current->refcount++;
|
||||||
{
|
DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
|
||||||
/* use existing policy */
|
"refcount", src_ts, dst_ts,
|
||||||
current->refcount++;
|
policy_dir_names, direction);
|
||||||
DBG2(DBG_KNL, "policy %R === %R %N already exists, increasing "
|
free(policy);
|
||||||
"refcount", src_ts, dst_ts,
|
policy = current;
|
||||||
policy_dir_names, direction);
|
found = TRUE;
|
||||||
free(policy);
|
|
||||||
policy = current;
|
|
||||||
found = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
iterator->destroy(iterator);
|
else
|
||||||
if (!found)
|
|
||||||
{ /* apply the new one, if we have no such policy */
|
{ /* 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;
|
policy->refcount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1659,7 +1670,6 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this,
|
|||||||
netlink_buf_t request;
|
netlink_buf_t request;
|
||||||
struct nlmsghdr *hdr;
|
struct nlmsghdr *hdr;
|
||||||
struct xfrm_userpolicy_id *policy_id;
|
struct xfrm_userpolicy_id *policy_id;
|
||||||
enumerator_t *enumerator;
|
|
||||||
|
|
||||||
DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts,
|
DBG2(DBG_KNL, "deleting policy %R === %R %N", src_ts, dst_ts,
|
||||||
policy_dir_names, direction);
|
policy_dir_names, direction);
|
||||||
@@ -1671,28 +1681,21 @@ static status_t del_policy(private_kernel_netlink_ipsec_t *this,
|
|||||||
|
|
||||||
/* find the policy */
|
/* find the policy */
|
||||||
this->mutex->lock(this->mutex);
|
this->mutex->lock(this->mutex);
|
||||||
enumerator = this->policies->create_enumerator(this->policies);
|
current = this->policies->get(this->policies, &policy);
|
||||||
while (enumerator->enumerate(enumerator, ¤t))
|
if (current)
|
||||||
{
|
{
|
||||||
if (memeq(¤t->sel, &policy.sel, sizeof(struct xfrm_selector)) &&
|
to_delete = current;
|
||||||
policy.direction == current->direction)
|
if (--to_delete->refcount > 0)
|
||||||
{
|
{
|
||||||
to_delete = current;
|
/* is used by more SAs, keep in kernel */
|
||||||
if (--to_delete->refcount > 0)
|
DBG2(DBG_KNL, "policy still used by another CHILD_SA, not removed");
|
||||||
{
|
this->mutex->unlock(this->mutex);
|
||||||
/* is used by more SAs, keep in kernel */
|
return SUCCESS;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
/* remove if last reference */
|
||||||
|
this->policies->remove(this->policies, to_delete);
|
||||||
}
|
}
|
||||||
this->mutex->unlock(this->mutex);
|
this->mutex->unlock(this->mutex);
|
||||||
enumerator->destroy(enumerator);
|
|
||||||
if (!to_delete)
|
if (!to_delete)
|
||||||
{
|
{
|
||||||
DBG1(DBG_KNL, "deleting policy %R === %R %N failed, not found", src_ts,
|
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)
|
static void destroy(private_kernel_netlink_ipsec_t *this)
|
||||||
{
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
policy_entry_t *policy;
|
||||||
|
|
||||||
this->job->cancel(this->job);
|
this->job->cancel(this->job);
|
||||||
close(this->socket_xfrm_events);
|
close(this->socket_xfrm_events);
|
||||||
this->socket_xfrm->destroy(this->socket_xfrm);
|
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->policies->destroy(this->policies);
|
||||||
this->mutex->destroy(this->mutex);
|
this->mutex->destroy(this->mutex);
|
||||||
free(this);
|
free(this);
|
||||||
@@ -1834,7 +1846,8 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
|
|||||||
this->public.interface.destroy = (void(*)(kernel_ipsec_t*)) destroy;
|
this->public.interface.destroy = (void(*)(kernel_ipsec_t*)) destroy;
|
||||||
|
|
||||||
/* private members */
|
/* 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->mutex = mutex_create(MUTEX_DEFAULT);
|
||||||
this->install_routes = lib->settings->get_bool(lib->settings,
|
this->install_routes = lib->settings->get_bool(lib->settings,
|
||||||
"charon.install_routes", TRUE);
|
"charon.install_routes", TRUE);
|
||||||
|
|||||||
Reference in New Issue
Block a user