-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 = \
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
#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;
/**
* 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;
};
/**
}
/**
- * 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);
}
}
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;
}
*
* @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.
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+/*
+ * 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_ @}*/
#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>
* Local cache of a nodes synced SAs
*/
ha_sync_cache_t *cache;
+
+ /**
+ * Segment control interface via FIFO
+ */
+ ha_sync_ctl_t *ctl;
};
/**
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);
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);