From: Martin Willi Date: Thu, 27 Nov 2008 09:57:31 +0000 (+0000) Subject: IKE_SA activation/deactivation magic using a fifo socket X-Git-Tag: 4.4.0~103 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=aa98188af50e75ff9ac28207edf05b2026996240;p=thirdparty%2Fstrongswan.git IKE_SA activation/deactivation magic using a fifo socket --- diff --git a/src/charon/plugins/ha_sync/Makefile.am b/src/charon/plugins/ha_sync/Makefile.am index b48a6cf4bb..e30376d1ac 100644 --- a/src/charon/plugins/ha_sync/Makefile.am +++ b/src/charon/plugins/ha_sync/Makefile.am @@ -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 diff --git a/src/charon/plugins/ha_sync/ha_sync_cache.c b/src/charon/plugins/ha_sync/ha_sync_cache.c index 2626ceffa6..8ada9fee19 100644 --- a/src/charon/plugins/ha_sync/ha_sync_cache.c +++ b/src/charon/plugins/ha_sync/ha_sync_cache.c @@ -19,6 +19,13 @@ #include +typedef u_int32_t u32; +typedef u_int8_t u8; + +#include + +#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 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_segment(private_ha_sync_cache_t *this, u_int segment) +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); + + DBG1(DBG_CFG, "activating segment %d", segment); + + if (segment > 0 && segment <= this->segment_count && !(this->active & mask)) + { + 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); - /* TODO: activate only segment, not all */ - while (this->list->remove_last(this->list, (void**)&ike_sa) == SUCCESS) + 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; + 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; } diff --git a/src/charon/plugins/ha_sync/ha_sync_cache.h b/src/charon/plugins/ha_sync/ha_sync_cache.h index 8508c7f22f..cf9e0d72be 100644 --- a/src/charon/plugins/ha_sync/ha_sync_cache.h +++ b/src/charon/plugins/ha_sync/ha_sync_cache.h @@ -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. diff --git a/src/charon/plugins/ha_sync/ha_sync_ctl.c b/src/charon/plugins/ha_sync/ha_sync_ctl.c new file mode 100644 index 0000000000..cf747f20f3 --- /dev/null +++ b/src/charon/plugins/ha_sync/ha_sync_ctl.c @@ -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 . + * + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#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; +} + diff --git a/src/charon/plugins/ha_sync/ha_sync_ctl.h b/src/charon/plugins/ha_sync/ha_sync_ctl.h new file mode 100644 index 0000000000..cd2c7a28ff --- /dev/null +++ b/src/charon/plugins/ha_sync/ha_sync_ctl.h @@ -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 . + * + * 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_ @}*/ diff --git a/src/charon/plugins/ha_sync/ha_sync_plugin.c b/src/charon/plugins/ha_sync/ha_sync_plugin.c index 9bbc7f8e43..2164a4b243 100644 --- a/src/charon/plugins/ha_sync/ha_sync_plugin.c +++ b/src/charon/plugins/ha_sync/ha_sync_plugin.c @@ -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 #include @@ -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);