Implemented a HA enabled in-memory address pool
This commit is contained in:
parent
7455ab063f
commit
98d0343870
|
@ -21,6 +21,7 @@ libstrongswan_ha_la_SOURCES = \
|
|||
ha_kernel.h ha_kernel.c \
|
||||
ha_ctl.h ha_ctl.c \
|
||||
ha_ike.h ha_ike.c \
|
||||
ha_child.h ha_child.c
|
||||
ha_child.h ha_child.c \
|
||||
ha_attribute.h ha_attribute.c
|
||||
libstrongswan_ha_la_LDFLAGS = -module -avoid-version
|
||||
|
||||
|
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
* Copyright (C) 2010 revosec AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include "ha_attribute.h"
|
||||
|
||||
#include <utils/linked_list.h>
|
||||
#include <threading/mutex.h>
|
||||
|
||||
typedef struct private_ha_attribute_t private_ha_attribute_t;
|
||||
|
||||
/**
|
||||
* Private data of an ha_attribute_t object.
|
||||
*/
|
||||
struct private_ha_attribute_t {
|
||||
|
||||
/**
|
||||
* Public ha_attribute_t interface.
|
||||
*/
|
||||
ha_attribute_t public;
|
||||
|
||||
/**
|
||||
* List of pools, pool_t
|
||||
*/
|
||||
linked_list_t *pools;
|
||||
|
||||
/**
|
||||
* Mutex to lock mask
|
||||
*/
|
||||
mutex_t *mutex;
|
||||
|
||||
/**
|
||||
* Kernel helper
|
||||
*/
|
||||
ha_kernel_t *kernel;
|
||||
|
||||
/**
|
||||
* Segment responsibility
|
||||
*/
|
||||
ha_segments_t *segments;
|
||||
};
|
||||
|
||||
/**
|
||||
* In-memory pool.
|
||||
*/
|
||||
typedef struct {
|
||||
/** name of the pool */
|
||||
char *name;
|
||||
/** base address of pool */
|
||||
host_t *base;
|
||||
/** total number of addresses in this pool */
|
||||
int size;
|
||||
/** bitmask for address usage */
|
||||
u_char *mask;
|
||||
} pool_t;
|
||||
|
||||
/**
|
||||
* Clean up a pool entry
|
||||
*/
|
||||
static void pool_destroy(pool_t *pool)
|
||||
{
|
||||
pool->base->destroy(pool->base);
|
||||
free(pool->name);
|
||||
free(pool->mask);
|
||||
free(pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a pool offset to an address
|
||||
*/
|
||||
static host_t* offset2host(pool_t *pool, int offset)
|
||||
{
|
||||
chunk_t addr;
|
||||
host_t *host;
|
||||
u_int32_t *pos;
|
||||
|
||||
if (offset > pool->size)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr = chunk_clone(pool->base->get_address(pool->base));
|
||||
if (pool->base->get_family(pool->base) == AF_INET6)
|
||||
{
|
||||
pos = (u_int32_t*)(addr.ptr + 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = (u_int32_t*)addr.ptr;
|
||||
}
|
||||
*pos = htonl(offset + ntohl(*pos));
|
||||
host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
|
||||
free(addr.ptr);
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a host to a pool offset
|
||||
*/
|
||||
static int host2offset(pool_t *pool, host_t *addr)
|
||||
{
|
||||
chunk_t host, base;
|
||||
u_int32_t hosti, basei;
|
||||
|
||||
if (addr->get_family(addr) != pool->base->get_family(pool->base))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
host = addr->get_address(addr);
|
||||
base = pool->base->get_address(pool->base);
|
||||
if (addr->get_family(addr) == AF_INET6)
|
||||
{
|
||||
/* only look at last /32 block */
|
||||
if (!memeq(host.ptr, base.ptr, 12))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
host = chunk_skip(host, 12);
|
||||
base = chunk_skip(base, 12);
|
||||
}
|
||||
hosti = ntohl(*(u_int32_t*)(host.ptr));
|
||||
basei = ntohl(*(u_int32_t*)(base.ptr));
|
||||
if (hosti > basei + pool->size)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return hosti - basei;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a pool by its name
|
||||
*/
|
||||
static pool_t* get_pool(private_ha_attribute_t *this, char *name)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
pool_t *pool, *found = NULL;
|
||||
|
||||
enumerator = this->pools->create_enumerator(this->pools);
|
||||
while (enumerator->enumerate(enumerator, &pool))
|
||||
{
|
||||
if (streq(name, pool->name))
|
||||
{
|
||||
found = pool;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we are responsible for a bit in our bitmask
|
||||
*/
|
||||
static bool responsible_for(private_ha_attribute_t *this, int bit)
|
||||
{
|
||||
u_int segment;
|
||||
|
||||
segment = this->kernel->get_segment_int(this->kernel, bit);
|
||||
return this->segments->is_active(this->segments, segment);
|
||||
}
|
||||
|
||||
METHOD(attribute_provider_t, acquire_address, host_t*,
|
||||
private_ha_attribute_t *this, char *name, identification_t *id,
|
||||
host_t *requested)
|
||||
{
|
||||
pool_t *pool;
|
||||
int offset = -1, byte, bit;
|
||||
host_t *address;
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
pool = get_pool(this, name);
|
||||
if (pool)
|
||||
{
|
||||
for (byte = 0; byte < pool->size / 8; byte++)
|
||||
{
|
||||
if (pool->mask[byte] != 0xFF)
|
||||
{
|
||||
for (bit = 0; bit < 8; bit++)
|
||||
{
|
||||
if (!(pool->mask[byte] & 1 << bit) &&
|
||||
responsible_for(this, bit))
|
||||
{
|
||||
offset = byte * 8 + bit;
|
||||
pool->mask[byte] |= 1 << bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset != -1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (offset == -1)
|
||||
{
|
||||
DBG1(DBG_CFG, "no address left in HA pool '%s' belonging to"
|
||||
"a responsible segment", name);
|
||||
}
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
if (offset != -1)
|
||||
{
|
||||
address = offset2host(pool, offset);
|
||||
DBG1(DBG_CFG, "acquired address %H from HA pool '%s'", address, name);
|
||||
return address;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
METHOD(attribute_provider_t, release_address, bool,
|
||||
private_ha_attribute_t *this, char *name, host_t *address,
|
||||
identification_t *id)
|
||||
{
|
||||
pool_t *pool;
|
||||
int offset;
|
||||
bool found = FALSE;
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
pool = get_pool(this, name);
|
||||
if (pool)
|
||||
{
|
||||
offset = host2offset(pool, address);
|
||||
if (offset > 0 && offset < pool->size)
|
||||
{
|
||||
pool->mask[offset / 8] &= ~(1 << (offset % 8));
|
||||
DBG1(DBG_CFG, "released address %H to HA pool '%s'", address, name);
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
return found;
|
||||
}
|
||||
|
||||
METHOD(ha_attribute_t, reserve, void,
|
||||
private_ha_attribute_t *this, char *name, host_t *address)
|
||||
{
|
||||
pool_t *pool;
|
||||
int offset;
|
||||
|
||||
this->mutex->lock(this->mutex);
|
||||
pool = get_pool(this, name);
|
||||
if (pool)
|
||||
{
|
||||
offset = host2offset(pool, address);
|
||||
if (offset > 0 && offset < pool->size)
|
||||
{
|
||||
pool->mask[offset / 8] |= 1 << (offset % 8);
|
||||
DBG1(DBG_CFG, "reserved address %H in HA pool '%s'", address, name);
|
||||
}
|
||||
}
|
||||
this->mutex->unlock(this->mutex);
|
||||
}
|
||||
|
||||
METHOD(ha_attribute_t, destroy, void,
|
||||
private_ha_attribute_t *this)
|
||||
{
|
||||
this->pools->destroy_function(this->pools, (void*)pool_destroy);
|
||||
this->mutex->destroy(this->mutex);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the configured pools.
|
||||
*/
|
||||
static void load_pools(private_ha_attribute_t *this)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
char *name, *net, *bits;
|
||||
host_t *base;
|
||||
int mask, maxbits;
|
||||
pool_t *pool;
|
||||
|
||||
enumerator = lib->settings->create_key_value_enumerator(lib->settings,
|
||||
"charon.plugins.ha.pools");
|
||||
while (enumerator->enumerate(enumerator, &name, &net))
|
||||
{
|
||||
net = strdup(net);
|
||||
bits = strchr(net, '/');
|
||||
if (!bits)
|
||||
{
|
||||
DBG1(DBG_CFG, "invalid HA pool '%s' subnet, skipped", name);
|
||||
free(net);
|
||||
continue;
|
||||
}
|
||||
*bits++ = '\0';
|
||||
|
||||
base = host_create_from_string(net, 0);
|
||||
mask = atoi(bits);
|
||||
free(net);
|
||||
if (!base || !mask)
|
||||
{
|
||||
DESTROY_IF(base);
|
||||
DBG1(DBG_CFG, "invalid HA pool '%s', skipped", name);
|
||||
continue;
|
||||
}
|
||||
maxbits = base->get_family(base) == AF_INET ? 32 : 128;
|
||||
mask = maxbits - mask;
|
||||
if (mask > 24)
|
||||
{
|
||||
mask = 24;
|
||||
DBG1(DBG_CFG, "size of HA pool '%s' limited to /%d",
|
||||
name, maxbits - mask);
|
||||
}
|
||||
if (mask < 3)
|
||||
{
|
||||
DBG1(DBG_CFG, "HA pool '%s' too small, skipped", name);
|
||||
base->destroy(base);
|
||||
continue;
|
||||
}
|
||||
|
||||
INIT(pool,
|
||||
.name = strdup(name),
|
||||
.base = base,
|
||||
.size = (1 << mask),
|
||||
);
|
||||
pool->mask = calloc(pool->size / 8, 1);
|
||||
/* do not use first/last address of pool */
|
||||
pool->mask[0] |= 0x01;
|
||||
pool->mask[pool->size / 8 - 1] |= 0x80;
|
||||
|
||||
DBG1(DBG_CFG, "loaded HA pool '%s' %H/%d (%d addresses)",
|
||||
pool->name, pool->base, maxbits - mask, pool->size - 2);
|
||||
this->pools->insert_last(this->pools, pool);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
ha_attribute_t *ha_attribute_create(ha_kernel_t *kernel, ha_segments_t *segments)
|
||||
{
|
||||
private_ha_attribute_t *this;
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.provider = {
|
||||
.acquire_address = _acquire_address,
|
||||
.release_address = _release_address,
|
||||
.create_attribute_enumerator = enumerator_create_empty,
|
||||
},
|
||||
.reserve = _reserve,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
||||
.pools = linked_list_create(),
|
||||
.kernel = kernel,
|
||||
.segments = segments,
|
||||
);
|
||||
|
||||
load_pools(this);
|
||||
|
||||
return &this->public;
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* Copyright (C) 2010 Martin Willi
|
||||
* Copyright (C) 2010 revosec AG
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup ha_attribute ha_attribute
|
||||
* @{ @ingroup ha
|
||||
*/
|
||||
|
||||
#ifndef HA_ATTRIBUTE_H_
|
||||
#define HA_ATTRIBUTE_H_
|
||||
|
||||
#include "ha_kernel.h"
|
||||
#include "ha_segments.h"
|
||||
|
||||
#include <attributes/attribute_provider.h>
|
||||
|
||||
typedef struct ha_attribute_t ha_attribute_t;
|
||||
|
||||
/**
|
||||
* A HA enabled in memory address pool attribute provider.
|
||||
*/
|
||||
struct ha_attribute_t {
|
||||
|
||||
/**
|
||||
* Implements attribute provider interface.
|
||||
*/
|
||||
attribute_provider_t provider;
|
||||
|
||||
/**
|
||||
* Reserve an address for a passive IKE_SA.
|
||||
*
|
||||
* @param name pool name to reserve address in
|
||||
* @param address address to reserve
|
||||
*/
|
||||
void (*reserve)(ha_attribute_t *this, char *name, host_t *address);
|
||||
|
||||
/**
|
||||
* Destroy a ha_attribute_t.
|
||||
*/
|
||||
void (*destroy)(ha_attribute_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a ha_attribute instance.
|
||||
*/
|
||||
ha_attribute_t *ha_attribute_create(ha_kernel_t *kernel, ha_segments_t *segments);
|
||||
|
||||
#endif /** HA_ATTRIBUTE_H_ @}*/
|
|
@ -50,6 +50,11 @@ struct private_ha_dispatcher_t {
|
|||
*/
|
||||
ha_kernel_t *kernel;
|
||||
|
||||
/**
|
||||
* HA enabled pool
|
||||
*/
|
||||
ha_attribute_t *attr;
|
||||
|
||||
/**
|
||||
* Dispatcher job
|
||||
*/
|
||||
|
@ -215,6 +220,7 @@ static void process_ike_update(private_ha_dispatcher_t *this,
|
|||
ike_sa_t *ike_sa = NULL;
|
||||
peer_cfg_t *peer_cfg = NULL;
|
||||
auth_cfg_t *auth;
|
||||
bool received_vip = FALSE;
|
||||
|
||||
enumerator = message->create_attribute_enumerator(message);
|
||||
while (enumerator->enumerate(enumerator, &attribute, &value))
|
||||
|
@ -252,6 +258,7 @@ static void process_ike_update(private_ha_dispatcher_t *this,
|
|||
break;
|
||||
case HA_REMOTE_VIP:
|
||||
ike_sa->set_virtual_ip(ike_sa, FALSE, value.host);
|
||||
received_vip = TRUE;
|
||||
break;
|
||||
case HA_ADDITIONAL_ADDR:
|
||||
ike_sa->add_additional_address(ike_sa,
|
||||
|
@ -301,6 +308,22 @@ static void process_ike_update(private_ha_dispatcher_t *this,
|
|||
ike_sa->get_other_host(ike_sa), ike_sa->get_other_id(ike_sa));
|
||||
ike_sa->set_state(ike_sa, IKE_PASSIVE);
|
||||
}
|
||||
if (received_vip)
|
||||
{
|
||||
host_t *vip;
|
||||
char *pool;
|
||||
|
||||
peer_cfg = ike_sa->get_peer_cfg(ike_sa);
|
||||
vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
|
||||
if (peer_cfg && vip)
|
||||
{
|
||||
pool = peer_cfg->get_pool(peer_cfg);
|
||||
if (pool)
|
||||
{
|
||||
this->attr->reserve(this->attr, pool, vip);
|
||||
}
|
||||
}
|
||||
}
|
||||
this->cache->cache(this->cache, ike_sa, message);
|
||||
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
|
||||
}
|
||||
|
@ -828,7 +851,8 @@ METHOD(ha_dispatcher_t, destroy, void,
|
|||
* See header
|
||||
*/
|
||||
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
||||
ha_segments_t *segments, ha_cache_t *cache, ha_kernel_t *kernel)
|
||||
ha_segments_t *segments, ha_cache_t *cache,
|
||||
ha_kernel_t *kernel, ha_attribute_t *attr)
|
||||
{
|
||||
private_ha_dispatcher_t *this;
|
||||
|
||||
|
@ -841,6 +865,7 @@ ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
|||
.segments = segments,
|
||||
.cache = cache,
|
||||
.kernel = kernel,
|
||||
.attr = attr,
|
||||
);
|
||||
this->job = callback_job_create((callback_job_cb_t)dispatch,
|
||||
this, NULL, NULL);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "ha_segments.h"
|
||||
#include "ha_cache.h"
|
||||
#include "ha_kernel.h"
|
||||
#include "ha_attribute.h"
|
||||
|
||||
typedef struct ha_dispatcher_t ha_dispatcher_t;
|
||||
|
||||
|
@ -46,9 +47,11 @@ struct ha_dispatcher_t {
|
|||
* @param segments segments to control based on received messages
|
||||
* @param cache message cache to use for resynchronization
|
||||
* @param kernel kernel helper
|
||||
* @param attr HA enabled pool
|
||||
* @return dispatcher object
|
||||
*/
|
||||
ha_dispatcher_t *ha_dispatcher_create(ha_socket_t *socket,
|
||||
ha_segments_t *segments, ha_cache_t *cache, ha_kernel_t *kernel);
|
||||
ha_segments_t *segments, ha_cache_t *cache,
|
||||
ha_kernel_t *kernel, ha_attribute_t *attr);
|
||||
|
||||
#endif /** HA_DISPATCHER_ @}*/
|
||||
|
|
|
@ -22,8 +22,10 @@
|
|||
#include "ha_segments.h"
|
||||
#include "ha_ctl.h"
|
||||
#include "ha_cache.h"
|
||||
#include "ha_attribute.h"
|
||||
|
||||
#include <daemon.h>
|
||||
#include <hydra.h>
|
||||
#include <config/child_cfg.h>
|
||||
|
||||
typedef struct private_ha_plugin_t private_ha_plugin_t;
|
||||
|
@ -82,18 +84,25 @@ struct private_ha_plugin_t {
|
|||
* Message cache for resynchronization
|
||||
*/
|
||||
ha_cache_t *cache;
|
||||
|
||||
/**
|
||||
* Attribute provider
|
||||
*/
|
||||
ha_attribute_t *attr;
|
||||
};
|
||||
|
||||
METHOD(plugin_t, destroy, void,
|
||||
private_ha_plugin_t *this)
|
||||
{
|
||||
DESTROY_IF(this->ctl);
|
||||
hydra->attributes->remove_provider(hydra->attributes, &this->attr->provider);
|
||||
charon->bus->remove_listener(charon->bus, &this->segments->listener);
|
||||
charon->bus->remove_listener(charon->bus, &this->ike->listener);
|
||||
charon->bus->remove_listener(charon->bus, &this->child->listener);
|
||||
this->ike->destroy(this->ike);
|
||||
this->child->destroy(this->child);
|
||||
this->dispatcher->destroy(this->dispatcher);
|
||||
this->attr->destroy(this->attr);
|
||||
this->cache->destroy(this->cache);
|
||||
this->segments->destroy(this->segments);
|
||||
this->kernel->destroy(this->kernel);
|
||||
|
@ -155,14 +164,16 @@ plugin_t *ha_plugin_create()
|
|||
{
|
||||
this->ctl = ha_ctl_create(this->segments, this->cache);
|
||||
}
|
||||
this->attr = ha_attribute_create(this->kernel, this->segments);
|
||||
this->dispatcher = ha_dispatcher_create(this->socket, this->segments,
|
||||
this->cache, this->kernel);
|
||||
this->cache, this->kernel, this->attr);
|
||||
this->ike = ha_ike_create(this->socket, this->tunnel, this->cache);
|
||||
this->child = ha_child_create(this->socket, this->tunnel, this->segments,
|
||||
this->kernel);
|
||||
charon->bus->add_listener(charon->bus, &this->segments->listener);
|
||||
charon->bus->add_listener(charon->bus, &this->ike->listener);
|
||||
charon->bus->add_listener(charon->bus, &this->child->listener);
|
||||
hydra->attributes->add_provider(hydra->attributes, &this->attr->provider);
|
||||
|
||||
return &this->public.plugin;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue