IKE_SA activation/deactivation magic using a fifo socket

This commit is contained in:
Martin Willi
2010-04-07 13:55:12 +02:00
committed by Martin Willi
parent c94fe198e9
commit aa98188af5
6 changed files with 331 additions and 12 deletions
+4 -3
View File
@@ -1,7 +1,7 @@
INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon
INCLUDES = -I${linuxdir} -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon
AM_CFLAGS = -rdynamic
AM_CFLAGS = -rdynamic -DIPSEC_PIDDIR=\"${piddir}\"
plugin_LTLIBRARIES = libstrongswan-ha-sync.la
libstrongswan_ha_sync_la_SOURCES = \
@@ -9,7 +9,8 @@ libstrongswan_ha_sync_la_SOURCES = \
ha_sync_message.h ha_sync_message.c \
ha_sync_socket.h ha_sync_socket.c \
ha_sync_dispatcher.h ha_sync_dispatcher.c \
ha_sync_dispatcher.h ha_sync_cache.c \
ha_sync_cache.h ha_sync_cache.c \
ha_sync_ctl.h ha_sync_ctl.c \
ha_sync_ike.h ha_sync_ike.c \
ha_sync_child.h ha_sync_child.c
libstrongswan_ha_sync_la_LDFLAGS = -module
+131 -8
View File
@@ -19,6 +19,13 @@
#include <utils/linked_list.h>
typedef u_int32_t u32;
typedef u_int8_t u8;
#include <linux/jhash.h>
#define MAX_SEGMENTS 16
typedef struct private_ha_sync_cache_t private_ha_sync_cache_t;
/**
@@ -35,6 +42,21 @@ struct private_ha_sync_cache_t {
* Linked list of IKE_SAs, ike_sa_t
*/
linked_list_t *list;
/**
* Init value for jhash
*/
u_int initval;
/**
* Total number of ClusterIP segments
*/
u_int segment_count;
/**
* mask of active segments
*/
u_int16_t active;
};
/**
@@ -108,18 +130,98 @@ static void delete_ike_sa(private_ha_sync_cache_t *this, ike_sa_id_t *id)
}
/**
* Implementation of ha_sync_cache_t.activate_segment
* Check if a host address is in the CLUSTERIP segment
*/
static void activate_segment(private_ha_sync_cache_t *this, u_int segment)
static bool in_segment(private_ha_sync_cache_t *this,
host_t *host, u_int segment)
{
if (host->get_family(host) == AF_INET)
{
unsigned long hash;
u_int32_t addr;
addr = *(u_int32_t*)host->get_address(host).ptr;
hash = jhash_1word(ntohl(addr), this->initval);
if ((((u_int64_t)hash * this->segment_count) >> 32) + 1 == segment)
{
return TRUE;
}
}
return FALSE;
}
/**
* Log currently active segments
*/
static void log_segments(private_ha_sync_cache_t *this, bool activated,
u_int segment)
{
char buf[64], *pos = buf;
int i;
bool first = TRUE;
for (i = 0; i < this->segment_count; i++)
{
if (this->active & 0x01 << i)
{
if (first)
{
first = FALSE;
}
else
{
pos += snprintf(pos, buf + sizeof(buf) - pos, ",");
}
pos += snprintf(pos, buf + sizeof(buf) - pos, "%d", i+1);
}
}
DBG1(DBG_CFG, "HA sync segments %d %sactivated, now active: %s",
segment, activated ? "" : "de", buf);
}
/**
* Implementation of ha_sync_cache_t.activate
*/
static void activate(private_ha_sync_cache_t *this, u_int segment)
{
ike_sa_t *ike_sa;
enumerator_t *enumerator;
u_int16_t mask = 0x01 << (segment - 1);
/* TODO: activate only segment, not all */
while (this->list->remove_last(this->list, (void**)&ike_sa) == SUCCESS)
DBG1(DBG_CFG, "activating segment %d", segment);
if (segment > 0 && segment <= this->segment_count && !(this->active & mask))
{
/* TODO: fix checkin of inexisting IKE_SA in manager */
/* TODO: do not activate SAs not in state CONNECTING */
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
this->active |= mask;
enumerator = this->list->create_enumerator(this->list);
while (enumerator->enumerate(enumerator, &ike_sa))
{
if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
in_segment(this, ike_sa->get_other_host(ike_sa), segment))
{
this->list->remove_at(this->list, enumerator);
ike_sa->set_state(ike_Sa, IKE_ESTABLISHED);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
}
}
enumerator->destroy(enumerator);
log_segments(this, TRUE, segment);
}
}
/**
* Implementation of ha_sync_cache_t.deactivate
*/
static void deactivate(private_ha_sync_cache_t *this, u_int segment)
{
u_int16_t mask = 0x01 << (segment - 1);
if (segment > 0 && segment <= this->segment_count && (this->active & mask))
{
this->active &= ~mask;
log_segments(this, FALSE, segment);
}
}
@@ -138,14 +240,35 @@ static void destroy(private_ha_sync_cache_t *this)
ha_sync_cache_t *ha_sync_cache_create()
{
private_ha_sync_cache_t *this = malloc_thing(private_ha_sync_cache_t);
enumerator_t *enumerator;
u_int segment;
char *str;
this->public.get_ike_sa = (ike_sa_t*(*)(ha_sync_cache_t*, ike_sa_id_t *id))get_ike_sa;
this->public.has_ike_sa = (bool(*)(ha_sync_cache_t*, ike_sa_id_t *id))has_ike_sa;
this->public.delete_ike_sa = (void(*)(ha_sync_cache_t*, ike_sa_id_t *id))delete_ike_sa;
this->public.activate_segment = (void(*)(ha_sync_cache_t*, u_int segment))activate_segment;
this->public.activate = (void(*)(ha_sync_cache_t*, u_int segment))activate;
this->public.deactivate = (void(*)(ha_sync_cache_t*, u_int segment))deactivate;
this->public.destroy = (void(*)(ha_sync_cache_t*))destroy;
this->list = linked_list_create();
this->initval = 0;
this->active = 0;
this->segment_count = lib->settings->get_int(lib->settings,
"charon.plugins.ha_sync.segment_count", 1);
this->segment_count = min(this->segment_count, MAX_SEGMENTS);
str = lib->settings->get_str(lib->settings,
"charon.plugins.ha_sync.active_segments", "1");
enumerator = enumerator_create_token(str, ",", " ");
while (enumerator->enumerate(enumerator, &str))
{
segment = atoi(str);
if (segment && segment < MAX_SEGMENTS)
{
this->active |= 0x01 << (segment - 1);
}
}
enumerator->destroy(enumerator);
return &this->public;
}
+8 -1
View File
@@ -66,7 +66,14 @@ struct ha_sync_cache_t {
*
* @param segment numerical segment to takeover
*/
void (*activate_segment)(ha_sync_cache_t *this, u_int segment);
void (*activate)(ha_sync_cache_t *this, u_int segment);
/**
* Deactivate a set of IKE_SAs identified by a segment.
*
* @param segment numerical segment to takeover
*/
void (*deactivate)(ha_sync_cache_t *this, u_int segment);
/**
* Destroy a ha_sync_cache_t.
+131
View File
@@ -0,0 +1,131 @@
/*
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* 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.
*
* $Id$
*/
#include "ha_sync_ctl.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <processing/jobs/callback_job.h>
#define HA_SYNC_FIFO IPSEC_PIDDIR "/charon.ha"
typedef struct private_ha_sync_ctl_t private_ha_sync_ctl_t;
/**
* Private data of an ha_sync_ctl_t object.
*/
struct private_ha_sync_ctl_t {
/**
* Public ha_sync_ctl_t interface.
*/
ha_sync_ctl_t public;
/**
* Cache to control
*/
ha_sync_cache_t *cache;
/**
* FIFO reader thread
*/
callback_job_t *job;
};
/**
* FIFO dispatching function
*/
static job_requeue_t dispatch_fifo(private_ha_sync_ctl_t *this)
{
int fifo, old;
char buf[8];
u_int segment;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old);
fifo = open(HA_SYNC_FIFO, O_RDONLY);
pthread_setcancelstate(old, NULL);
if (fifo == -1)
{
DBG1(DBG_CFG, "opening HA sync fifo failed: %s", strerror(errno));
sleep(1);
return JOB_REQUEUE_FAIR;
}
memset(buf, 0, sizeof(buf));
if (read(fifo, buf, sizeof(buf)-1) > 1)
{
segment = atoi(&buf[1]);
if (segment)
{
switch (buf[0])
{
case '+':
this->cache->activate(this->cache, segment);
break;
case '-':
this->cache->deactivate(this->cache, segment);
break;
default:
break;
}
}
}
close(fifo);
return JOB_REQUEUE_DIRECT;
}
/**
* Implementation of ha_sync_ctl_t.destroy.
*/
static void destroy(private_ha_sync_ctl_t *this)
{
this->job->cancel(this->job);
free(this);
}
/**
* See header
*/
ha_sync_ctl_t *ha_sync_ctl_create(ha_sync_cache_t *cache)
{
private_ha_sync_ctl_t *this = malloc_thing(private_ha_sync_ctl_t);
this->public.destroy = (void(*)(ha_sync_ctl_t*))destroy;
if (access(HA_SYNC_FIFO, R_OK|W_OK) != 0)
{
if (mkfifo(HA_SYNC_FIFO, 600) != 0)
{
DBG1(DBG_CFG, "creating HA sync FIFO %s failed: %s",
HA_SYNC_FIFO, strerror(errno));
}
}
this->cache = cache;
this->job = callback_job_create((callback_job_cb_t)dispatch_fifo,
this, NULL, NULL);
charon->processor->queue_job(charon->processor, (job_t*)this->job);
return &this->public;
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (C) 2008 Martin Willi
* Hochschule fuer Technik Rapperswil
*
* 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.
*
* $Id$
*/
/**
* @defgroup ha_sync_ctl ha_sync_ctl
* @{ @ingroup ha_sync
*/
#ifndef HA_SYNC_CTL_H_
#define HA_SYNC_CTL_H_
#include "ha_sync_cache.h"
typedef struct ha_sync_ctl_t ha_sync_ctl_t;
/**
* HA Sync control interface using a FIFO.
*/
struct ha_sync_ctl_t {
/**
* Destroy a ha_sync_ctl_t.
*/
void (*destroy)(ha_sync_ctl_t *this);
};
/**
* Create a ha_sync_ctl instance.
*
* @param cache cache to control in this socket
* @return HA sync control interface
*/
ha_sync_ctl_t *ha_sync_ctl_create(ha_sync_cache_t *cache);
#endif /* HA_SYNC_CTL_ @}*/
@@ -21,6 +21,7 @@
#include "ha_sync_socket.h"
#include "ha_sync_dispatcher.h"
#include "ha_sync_cache.h"
#include "ha_sync_ctl.h"
#include <daemon.h>
#include <config/child_cfg.h>
@@ -61,6 +62,11 @@ struct private_ha_sync_plugin_t {
* Local cache of a nodes synced SAs
*/
ha_sync_cache_t *cache;
/**
* Segment control interface via FIFO
*/
ha_sync_ctl_t *ctl;
};
/**
@@ -73,6 +79,7 @@ static void destroy(private_ha_sync_plugin_t *this)
this->ike->destroy(this->ike);
this->child->destroy(this->child);
this->dispatcher->destroy(this->dispatcher);
this->ctl->destroy(this->ctl);
this->cache->destroy(this->cache);
this->socket->destroy(this->socket);
free(this);
@@ -94,6 +101,7 @@ plugin_t *plugin_create()
return NULL;
}
this->cache = ha_sync_cache_create();
this->ctl = ha_sync_ctl_create(this->cache);
this->dispatcher = ha_sync_dispatcher_create(this->socket, this->cache);
this->ike = ha_sync_ike_create(this->socket, this->cache);
this->child = ha_sync_child_create(this->socket, this->cache);