manage synced SAs in IKE_SA Manager, tag them with IKE_PASSIVE state
authorMartin Willi <martin@strongswan.org>
Fri, 28 Nov 2008 15:45:17 +0000 (15:45 +0000)
committerMartin Willi <martin@revosec.ch>
Wed, 7 Apr 2010 11:55:12 +0000 (13:55 +0200)
17 files changed:
src/charon/plugins/ha_sync/Makefile.am
src/charon/plugins/ha_sync/ha_sync_cache.c [deleted file]
src/charon/plugins/ha_sync/ha_sync_cache.h [deleted file]
src/charon/plugins/ha_sync/ha_sync_child.c
src/charon/plugins/ha_sync/ha_sync_child.h
src/charon/plugins/ha_sync/ha_sync_ctl.c
src/charon/plugins/ha_sync/ha_sync_ctl.h
src/charon/plugins/ha_sync/ha_sync_dispatcher.c
src/charon/plugins/ha_sync/ha_sync_dispatcher.h
src/charon/plugins/ha_sync/ha_sync_ike.c
src/charon/plugins/ha_sync/ha_sync_ike.h
src/charon/plugins/ha_sync/ha_sync_message.c
src/charon/plugins/ha_sync/ha_sync_message.h
src/charon/plugins/ha_sync/ha_sync_plugin.c
src/charon/plugins/ha_sync/ha_sync_segments.c [new file with mode: 0644]
src/charon/plugins/ha_sync/ha_sync_segments.h [new file with mode: 0644]
src/libcharon/sa/child_sa.h

index e30376d..15f4096 100644 (file)
@@ -9,7 +9,7 @@ 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_cache.h ha_sync_cache.c \
+  ha_sync_segments.h ha_sync_segments.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
diff --git a/src/charon/plugins/ha_sync/ha_sync_cache.c b/src/charon/plugins/ha_sync/ha_sync_cache.c
deleted file mode 100644 (file)
index a36c825..0000000
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * 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_cache.h"
-
-#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;
-
-/**
- * Private data of an ha_sync_cache_t object.
- */
-struct private_ha_sync_cache_t {
-
-       /**
-        * Public ha_sync_cache_t interface.
-        */
-       ha_sync_cache_t public;
-
-       /**
-        * 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.get_ike_sa
- */
-static ike_sa_t* get_ike_sa(private_ha_sync_cache_t *this, ike_sa_id_t *id)
-{
-       enumerator_t *enumerator;
-       ike_sa_t *current, *found = NULL;
-
-       enumerator = this->list->create_enumerator(this->list);
-       while (enumerator->enumerate(enumerator, &current))
-       {
-               if (id->equals(id, current->get_id(current)))
-               {
-                       found = current;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-
-       if (!found)
-       {
-               found = ike_sa_create(id);
-               this->list->insert_first(this->list, found);
-       }
-       return found;
-}
-
-/**
- * Implementation of ha_sync_cache_t.has_ike_sa
- */
-static bool has_ike_sa(private_ha_sync_cache_t *this, ike_sa_id_t *id)
-{
-       enumerator_t *enumerator;
-       ike_sa_t *ike_sa;
-       bool found = FALSE;
-
-       enumerator = this->list->create_enumerator(this->list);
-       while (enumerator->enumerate(enumerator, &ike_sa))
-       {
-               if (id->equals(id, ike_sa->get_id(ike_sa)))
-               {
-                       found = TRUE;
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-       return found;
-}
-
-/**
- * Implementation of ha_sync_cache_t.delete_ike_sa
- */
-static void delete_ike_sa(private_ha_sync_cache_t *this, ike_sa_id_t *id)
-{
-       enumerator_t *enumerator;
-       ike_sa_t *ike_sa;
-
-       enumerator = this->list->create_enumerator(this->list);
-       while (enumerator->enumerate(enumerator, &ike_sa))
-       {
-               if (id->equals(id, ike_sa->get_id(ike_sa)))
-               {
-                       this->list->remove_at(this->list, enumerator);
-                       ike_sa->destroy(ike_sa);
-                       break;
-               }
-       }
-       enumerator->destroy(enumerator);
-}
-
-/**
- * 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(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);
-
-       if (segment > 0 && segment <= this->segment_count && (this->active & mask))
-       {
-               this->active &= ~mask;
-               log_segments(this, FALSE, segment);
-       }
-}
-
-/**
- * Implementation of ha_sync_cache_t.destroy.
- */
-static void destroy(private_ha_sync_cache_t *this)
-{
-       this->list->destroy_offset(this->list, offsetof(ike_sa_t, destroy));
-       free(this);
-}
-
-/**
- * See header
- */
-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 = (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
deleted file mode 100644 (file)
index cf9e0d7..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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_cache ha_sync_cache
- * @{ @ingroup ha_sync
- */
-
-#ifndef HA_SYNC_CACHE_H_
-#define HA_SYNC_CACHE_H_
-
-#include <daemon.h>
-
-typedef struct ha_sync_cache_t ha_sync_cache_t;
-
-/**
- * Locally cached HA state synced from other nodes.
- */
-struct ha_sync_cache_t {
-
-       /**
-        * Get a synced and cached IKE_SA entry.
-        *
-        * If no cached IKE_SA with such an id exists, it gets created.
-        *
-        * @param id            IKE_SA identifier of cached SA.
-        * @return                      cached IKE_SA
-        */
-       ike_sa_t* (*get_ike_sa)(ha_sync_cache_t *this, ike_sa_id_t *id);
-
-       /**
-        * Check if an IKE_SA is in the cache.
-        *
-        * @param id            IKE_SA identifier of cached SA.
-        * @return                      TRUE if IKE_SA found
-        */
-       bool (*has_ike_sa)(ha_sync_cache_t *this, ike_sa_id_t *id);
-
-       /**
-        * Delete a synced and cached IKE_SA entry.
-        *
-        * @param id            IKE_SA identifier of cached SA to delete.
-        */
-       void (*delete_ike_sa)(ha_sync_cache_t *this, ike_sa_id_t *id);
-
-       /**
-        * Activate a set of IKE_SAs identified by a segment.
-        *
-        * Activating means do a takeover of SAs as the responsible node has failed.
-        * This involves moving all SAs to the daemons IKE_SA manager and handle
-        * them actively now.
-        *
-        * @param segment       numerical segment to takeover
-        */
-       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.
-        */
-       void (*destroy)(ha_sync_cache_t *this);
-};
-
-/**
- * Create a ha_sync_cache instance.
- */
-ha_sync_cache_t *ha_sync_cache_create();
-
-#endif /* HA_SYNC_CACHE_ @}*/
index b3ace72..1c1c6fc 100644 (file)
@@ -33,11 +33,6 @@ struct private_ha_sync_child_t {
         * socket we use for syncing
         */
        ha_sync_socket_t *socket;
-
-       /**
-        * synced and cached IKE_SA state
-        */
-       ha_sync_cache_t *cache;
 };
 
 /**
@@ -55,11 +50,6 @@ static bool child_keys(private_ha_sync_child_t *this, ike_sa_t *ike_sa,
        enumerator_t *enumerator;
        traffic_selector_t *ts;
 
-       if (this->cache->has_ike_sa(this->cache, ike_sa->get_id(ike_sa)))
-       {       /* IKE_SA is cached, do not sync */
-               return TRUE;
-       }
-
        m = ha_sync_message_create(HA_SYNC_CHILD_ADD);
 
        m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
@@ -119,8 +109,8 @@ static bool child_keys(private_ha_sync_child_t *this, ike_sa_t *ike_sa,
 static bool child_state_change(private_ha_sync_child_t *this, ike_sa_t *ike_sa,
                                                           child_sa_t *child_sa, child_sa_state_t state)
 {
-       if (this->cache->has_ike_sa(this->cache, ike_sa->get_id(ike_sa)))
-       {       /* IKE_SA is cached, do not sync */
+       if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
+       {       /* only sync active IKE_SAs */
                return TRUE;
        }
 
@@ -150,8 +140,7 @@ static void destroy(private_ha_sync_child_t *this)
 /**
  * See header
  */
-ha_sync_child_t *ha_sync_child_create(ha_sync_socket_t *socket,
-                                                                         ha_sync_cache_t *cache)
+ha_sync_child_t *ha_sync_child_create(ha_sync_socket_t *socket)
 {
        private_ha_sync_child_t *this = malloc_thing(private_ha_sync_child_t);
 
@@ -161,7 +150,6 @@ ha_sync_child_t *ha_sync_child_create(ha_sync_socket_t *socket,
        this->public.destroy = (void(*)(ha_sync_child_t*))destroy;
 
        this->socket = socket;
-       this->cache = cache;
 
        return &this->public;
 }
index fe7e5ec..13faa91 100644 (file)
@@ -24,7 +24,7 @@
 #define HA_SYNC_CHILD_H_
 
 #include "ha_sync_socket.h"
-#include "ha_sync_cache.h"
+#include "ha_sync_segments.h"
 
 #include <daemon.h>
 
@@ -50,10 +50,8 @@ struct ha_sync_child_t {
  * Create a ha_sync_child instance.
  *
  * @param socket               socket to use for sending synchronization messages
- * @param cache                        synced and cached SAs
  * @return                             CHILD listener
  */
-ha_sync_child_t *ha_sync_child_create(ha_sync_socket_t *socket,
-                                                                         ha_sync_cache_t *cache);
+ha_sync_child_t *ha_sync_child_create(ha_sync_socket_t *socket);
 
 #endif /* HA_SYNC_CHILD_ @}*/
index cf747f2..30c9261 100644 (file)
@@ -42,9 +42,9 @@ struct private_ha_sync_ctl_t {
        ha_sync_ctl_t public;
 
        /**
-        * Cache to control
+        * Segments to control
         */
-       ha_sync_cache_t *cache;
+       ha_sync_segments_t *segments;
 
        /**
         * FIFO reader thread
@@ -80,10 +80,10 @@ static job_requeue_t dispatch_fifo(private_ha_sync_ctl_t *this)
                        switch (buf[0])
                        {
                                case '+':
-                                       this->cache->activate(this->cache, segment);
+                                       this->segments->activate(this->segments, segment);
                                        break;
                                case '-':
-                                       this->cache->deactivate(this->cache, segment);
+                                       this->segments->deactivate(this->segments, segment);
                                        break;
                                default:
                                        break;
@@ -107,7 +107,7 @@ static void destroy(private_ha_sync_ctl_t *this)
 /**
  * See header
  */
-ha_sync_ctl_t *ha_sync_ctl_create(ha_sync_cache_t *cache)
+ha_sync_ctl_t *ha_sync_ctl_create(ha_sync_segments_t *segments)
 {
        private_ha_sync_ctl_t *this = malloc_thing(private_ha_sync_ctl_t);
 
@@ -122,7 +122,7 @@ ha_sync_ctl_t *ha_sync_ctl_create(ha_sync_cache_t *cache)
                }
        }
 
-       this->cache = cache;
+       this->segments = segments;
        this->job = callback_job_create((callback_job_cb_t)dispatch_fifo,
                                                                        this, NULL, NULL);
        charon->processor->queue_job(charon->processor, (job_t*)this->job);
index cd2c7a2..5aa3aac 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef HA_SYNC_CTL_H_
 #define HA_SYNC_CTL_H_
 
-#include "ha_sync_cache.h"
+#include "ha_sync_segments.h"
 
 typedef struct ha_sync_ctl_t ha_sync_ctl_t;
 
@@ -41,9 +41,9 @@ struct ha_sync_ctl_t {
 /**
  * Create a ha_sync_ctl instance.
  *
- * @param cache                cache to control in this socket
+ * @param segments     segments to control
  * @return                     HA sync control interface
  */
-ha_sync_ctl_t *ha_sync_ctl_create(ha_sync_cache_t *cache);
+ha_sync_ctl_t *ha_sync_ctl_create(ha_sync_segments_t *segments);
 
 #endif /* HA_SYNC_CTL_ @}*/
index 7873216..78c62c0 100644 (file)
@@ -38,11 +38,6 @@ struct private_ha_sync_dispatcher_t {
        ha_sync_socket_t *socket;
 
        /**
-        * Synced SA state cache
-        */
-       ha_sync_cache_t *cache;
-
-       /**
         * Dispatcher job
         */
        callback_job_t *job;
@@ -77,14 +72,11 @@ static void process_ike_add(private_ha_sync_dispatcher_t *this,
                switch (attribute)
                {
                        case HA_SYNC_IKE_ID:
-                               ike_sa = this->cache->get_ike_sa(this->cache, value.ike_sa_id);
-                               DBG2(DBG_IKE, "got HA_SYNC_IKE_ADD: %llx:%llx - %p",
-                                        value.ike_sa_id->get_initiator_spi(value.ike_sa_id),
-                                        value.ike_sa_id->get_responder_spi(value.ike_sa_id),
-                                        ike_sa);
+                               ike_sa = ike_sa_create(value.ike_sa_id);
                                break;
                        case HA_SYNC_IKE_REKEY_ID:
-                               old_sa = this->cache->get_ike_sa(this->cache, value.ike_sa_id);
+                               old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                                                 value.ike_sa_id);
                                break;
                        case HA_SYNC_NONCE_I:
                                nonce_i = value.chunk;
@@ -142,19 +134,30 @@ static void process_ike_add(private_ha_sync_dispatcher_t *this,
                        proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0);
                }
                charon->bus->set_sa(charon->bus, ike_sa);
-               if (!keymat->derive_ike_keys(keymat, proposal, &dh, nonce_i, nonce_r,
+               if (keymat->derive_ike_keys(keymat, proposal, &dh, nonce_i, nonce_r,
                                                                         ike_sa->get_id(ike_sa), old_prf, old_skd))
                {
+                       if (old_sa)
+                       {
+                               ike_sa->inherit(ike_sa, old_sa);
+                               charon->ike_sa_manager->checkin_and_destroy(
+                                                                                               charon->ike_sa_manager, old_sa);
+                               old_sa = NULL;
+                       }
+                       ike_sa->set_state(ike_sa, IKE_CONNECTING);
+                       charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+               }
+               else
+               {
                        DBG1(DBG_IKE, "HA sync keymat derivation failed");
+                       ike_sa->destroy(ike_sa);
                }
                charon->bus->set_sa(charon->bus, NULL);
                proposal->destroy(proposal);
-
-               if (old_sa)
-               {
-                       ike_sa->inherit(ike_sa, old_sa);
-                       this->cache->delete_ike_sa(this->cache, old_sa->get_id(old_sa));
-               }
+       }
+       if (old_sa)
+       {
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, old_sa);
        }
 }
 
@@ -196,17 +199,14 @@ static void process_ike_update(private_ha_sync_dispatcher_t *this,
        {
                if (attribute != HA_SYNC_IKE_ID && ike_sa == NULL)
                {
-                       DBG1(DBG_IKE, "HA_SYNC_IKE_ID must be first attribute");
+                       /* must be first attribute */
                        break;
                }
                switch (attribute)
                {
                        case HA_SYNC_IKE_ID:
-                               ike_sa = this->cache->get_ike_sa(this->cache, value.ike_sa_id);
-                               DBG2(DBG_IKE, "got HA_SYNC_IKE_UPDATE: %llx:%llx - %p",
-                                        value.ike_sa_id->get_initiator_spi(value.ike_sa_id),
-                                        value.ike_sa_id->get_responder_spi(value.ike_sa_id),
-                                        ike_sa);
+                               ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                                                 value.ike_sa_id);
                                break;
                        case HA_SYNC_LOCAL_ID:
                                ike_sa->set_my_id(ike_sa, value.id->clone(value.id));
@@ -235,6 +235,15 @@ static void process_ike_update(private_ha_sync_dispatcher_t *this,
                        case HA_SYNC_CONFIG_NAME:
                                peer_cfg = charon->backends->get_peer_cfg_by_name(
                                                                                                charon->backends, value.str);
+                               if (peer_cfg)
+                               {
+                                       ike_sa->set_peer_cfg(ike_sa, peer_cfg);
+                                       peer_cfg->destroy(peer_cfg);
+                               }
+                               else
+                               {
+                                       DBG1(DBG_IKE, "HA sync is missing nodes peer configuration");
+                               }
                                break;
                        case HA_SYNC_CONDITIONS:
                                set_condition(ike_sa, value.u32, EXT_NATT);
@@ -250,26 +259,26 @@ static void process_ike_update(private_ha_sync_dispatcher_t *this,
                                set_extension(ike_sa, value.u32, COND_CERTREQ_SEEN);
                                set_extension(ike_sa, value.u32, COND_ORIGINAL_INITIATOR);
                                break;
+                       case HA_SYNC_INITIATE_MID:
+                               ike_sa->set_message_id(ike_sa, TRUE, value.u32);
+                               break;
+                       case HA_SYNC_RESPOND_MID:
+                               ike_sa->set_message_id(ike_sa, FALSE, value.u32);
+                               break;
                        default:
                                break;
                }
        }
        enumerator->destroy(enumerator);
 
-       if (peer_cfg)
-       {
-               ike_sa->set_peer_cfg(ike_sa, peer_cfg);
-               peer_cfg->destroy(peer_cfg);
-
-               charon->bus->set_sa(charon->bus, ike_sa);
-               /* we use the CONNECTING state to indicate sync is complete. */
-               /* TODO: add an additional HOT_COPY state? */
-               ike_sa->set_state(ike_sa, IKE_CONNECTING);
-               charon->bus->set_sa(charon->bus, NULL);
-       }
-       else
+       if (ike_sa)
        {
-               DBG1(DBG_IKE, "HA sync is missing nodes peer configuration");
+               if (ike_sa->get_state(ike_sa) == IKE_CONNECTING &&
+                       ike_sa->get_peer_cfg(ike_sa))
+               {
+                       ike_sa->set_state(ike_sa, IKE_PASSIVE);
+               }
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
        }
 }
 
@@ -282,6 +291,7 @@ static void process_ike_delete(private_ha_sync_dispatcher_t *this,
        ha_sync_message_attribute_t attribute;
        ha_sync_message_value_t value;
        enumerator_t *enumerator;
+       ike_sa_t *ike_sa;
 
        enumerator = message->create_attribute_enumerator(message);
        while (enumerator->enumerate(enumerator, &attribute, &value))
@@ -289,10 +299,13 @@ static void process_ike_delete(private_ha_sync_dispatcher_t *this,
                switch (attribute)
                {
                        case HA_SYNC_IKE_ID:
-                               DBG2(DBG_IKE, "got HA_SYNC_IKE_DELETE: %llx:%llx",
-                                        value.ike_sa_id->get_initiator_spi(value.ike_sa_id),
-                                        value.ike_sa_id->get_responder_spi(value.ike_sa_id));
-                               this->cache->delete_ike_sa(this->cache, value.ike_sa_id);
+                               ike_sa = charon->ike_sa_manager->checkout(
+                                                                       charon->ike_sa_manager, value.ike_sa_id);
+                               if (ike_sa)
+                               {
+                                       charon->ike_sa_manager->checkin_and_destroy(
+                                                                       charon->ike_sa_manager, ike_sa);
+                               }
                                break;
                        default:
                                break;
@@ -301,17 +314,16 @@ static void process_ike_delete(private_ha_sync_dispatcher_t *this,
        enumerator->destroy(enumerator);
 }
 
-
 /**
- * get the child_cfg with the same name as the peer cfg
+ * Lookup a child cfg from the peer cfg by name
  */
-static child_cfg_t* find_child_cfg(char *name)
+static child_cfg_t* find_child_cfg(ike_sa_t *ike_sa, char *name)
 {
        peer_cfg_t *peer_cfg;
        child_cfg_t *current, *found = NULL;
        enumerator_t *enumerator;
 
-       peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name);
+       peer_cfg = ike_sa->get_peer_cfg(ike_sa);
        if (peer_cfg)
        {
                enumerator = peer_cfg->create_child_cfg_enumerator(peer_cfg);
@@ -320,12 +332,10 @@ static child_cfg_t* find_child_cfg(char *name)
                        if (streq(current->get_name(current), name))
                        {
                                found = current;
-                               found->get_ref(found);
                                break;
                        }
                }
                enumerator->destroy(enumerator);
-               peer_cfg->destroy(peer_cfg);
        }
        return found;
 }
@@ -340,6 +350,7 @@ static void process_child_add(private_ha_sync_dispatcher_t *this,
        ha_sync_message_value_t value;
        enumerator_t *enumerator;
        ike_sa_t *ike_sa = NULL;
+       char *config_name;
        child_cfg_t *config = NULL;
        child_sa_t *child_sa;
        proposal_t *proposal;
@@ -362,15 +373,12 @@ static void process_child_add(private_ha_sync_dispatcher_t *this,
                switch (attribute)
                {
                        case HA_SYNC_IKE_ID:
-                               ike_sa = this->cache->get_ike_sa(this->cache, value.ike_sa_id);
+                               ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                                                 value.ike_sa_id);
                                initiator = value.ike_sa_id->is_initiator(value.ike_sa_id);
-                               DBG2(DBG_CHD, "got HA_SYNC_CHILD_ADD: %llx:%llx - %p",
-                                        value.ike_sa_id->get_initiator_spi(value.ike_sa_id),
-                                        value.ike_sa_id->get_responder_spi(value.ike_sa_id),
-                                        ike_sa);
                                break;
                        case HA_SYNC_CONFIG_NAME:
-                               config = find_child_cfg(value.str);
+                               config_name = value.str;
                                break;
                        case HA_SYNC_INBOUND_SPI:
                                inbound_spi = value.u32;
@@ -414,22 +422,22 @@ static void process_child_add(private_ha_sync_dispatcher_t *this,
        }
        enumerator->destroy(enumerator);
 
-       if (!config)
+       if (!ike_sa)
        {
-               DBG1(DBG_CHD, "HA sync is missing nodes child configuration");
+               DBG1(DBG_CHD, "IKE_SA for HA sync CHILD_SA not found");
                return;
        }
-       if (!ike_sa)
+       config = find_child_cfg(ike_sa, config_name);
+       if (!config)
        {
-               config->destroy(config);
-               DBG1(DBG_CHD, "IKE_SA for HA sync CHILD_SA not found");
+               DBG1(DBG_CHD, "HA sync is missing nodes child configuration");
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                return;
        }
-       charon->bus->set_sa(charon->bus, ike_sa);
+
        child_sa = child_sa_create(ike_sa->get_my_host(ike_sa),
                                                           ike_sa->get_other_host(ike_sa), config, 0,
                                                           ike_sa->has_condition(ike_sa, COND_NAT_ANY));
-       config->destroy(config);
        child_sa->set_mode(child_sa, mode);
        child_sa->set_protocol(child_sa, PROTO_ESP);
        child_sa->set_ipcomp(child_sa, ipcomp);
@@ -451,7 +459,7 @@ static void process_child_add(private_ha_sync_dispatcher_t *this,
                DBG1(DBG_CHD, "HA sync CHILD_SA key derivation failed");
                child_sa->destroy(child_sa);
                proposal->destroy(proposal);
-               charon->bus->set_sa(charon->bus, NULL);
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                return;
        }
        child_sa->set_proposal(child_sa, proposal);
@@ -487,7 +495,7 @@ static void process_child_add(private_ha_sync_dispatcher_t *this,
        {
                DBG1(DBG_CHD, "HA sync CHILD_SA installation failed");
                child_sa->destroy(child_sa);
-               charon->bus->set_sa(charon->bus, NULL);
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
                return;
        }
 
@@ -516,7 +524,7 @@ static void process_child_add(private_ha_sync_dispatcher_t *this,
 
        child_sa->set_state(child_sa, CHILD_INSTALLED);
        ike_sa->add_child_sa(ike_sa, child_sa);
-       charon->bus->set_sa(charon->bus, NULL);
+       charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
 }
 
 /**
@@ -536,15 +544,8 @@ static void process_child_delete(private_ha_sync_dispatcher_t *this,
                switch (attribute)
                {
                        case HA_SYNC_IKE_ID:
-                               if (this->cache->has_ike_sa(this->cache, value.ike_sa_id))
-                               {
-                                       ike_sa = this->cache->get_ike_sa(this->cache, value.ike_sa_id);
-                                       DBG2(DBG_CHD, "got HA_SYNC_CHILD_DELETE: %llx:%llx - %p",
-                                                value.ike_sa_id->get_initiator_spi(value.ike_sa_id),
-                                                value.ike_sa_id->get_responder_spi(value.ike_sa_id),
-                                                ike_sa);
-                                       continue;
-                               }
+                               ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager,
+                                                                                                                 value.ike_sa_id);
                                break;
                        case HA_SYNC_INBOUND_SPI:
                                if (!ike_sa || ike_sa->destroy_child_sa(ike_sa, PROTO_ESP,
@@ -559,6 +560,10 @@ static void process_child_delete(private_ha_sync_dispatcher_t *this,
                }
                break;
        }
+       if (ike_sa)
+       {
+               charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
+       }
        enumerator->destroy(enumerator);
 }
 
@@ -609,15 +614,13 @@ static void destroy(private_ha_sync_dispatcher_t *this)
 /**
  * See header
  */
-ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket,
-                                                                                               ha_sync_cache_t *cache)
+ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket)
 {
        private_ha_sync_dispatcher_t *this = malloc_thing(private_ha_sync_dispatcher_t);
 
        this->public.destroy = (void(*)(ha_sync_dispatcher_t*))destroy;
 
        this->socket = socket;
-       this->cache = cache;
        this->job = callback_job_create((callback_job_cb_t)dispatch,
                                                                        this, NULL, NULL);
        charon->processor->queue_job(charon->processor, (job_t*)this->job);
index eda4c4d..eb2817e 100644 (file)
@@ -24,7 +24,6 @@
 #define HA_SYNC_DISPATCHER_H_
 
 #include "ha_sync_socket.h"
-#include "ha_sync_cache.h"
 
 typedef struct ha_sync_dispatcher_t ha_sync_dispatcher_t;
 
@@ -43,10 +42,8 @@ struct ha_sync_dispatcher_t {
  * Create a ha_sync_dispatcher instance pulling from socket.
  *
  * @param socket               socket to pull messages from
- * @param cache                        cache to push synced SAs to
  * @return                             dispatcher object
  */
-ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket,
-                                                                                               ha_sync_cache_t *cache);
+ha_sync_dispatcher_t *ha_sync_dispatcher_create(ha_sync_socket_t *socket);
 
 #endif /* HA_SYNC_DISPATCHER_ @}*/
index b528a33..fb518e6 100644 (file)
@@ -33,11 +33,6 @@ struct private_ha_sync_ike_t {
         * socket we use for syncing
         */
        ha_sync_socket_t *socket;
-
-       /**
-        * Synced and cached SAs
-        */
-       ha_sync_cache_t *cache;
 };
 
 /**
@@ -76,11 +71,6 @@ static bool ike_keys(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
        proposal_t *proposal;
        u_int16_t alg, len;
 
-       if (this->cache->has_ike_sa(this->cache, ike_sa->get_id(ike_sa)))
-       {       /* IKE_SA is cached, do not sync */
-               return TRUE;
-       }
-
        if (dh->get_shared_secret(dh, &secret) != SUCCESS)
        {
                return TRUE;
@@ -136,8 +126,8 @@ static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
 {
        ha_sync_message_t *m;
 
-       if (this->cache->has_ike_sa(this->cache, ike_sa->get_id(ike_sa)))
-       {       /* IKE_SA is cached, do not sync */
+       if (ike_sa->get_state(ike_sa) == IKE_PASSIVE)
+       {       /* only sync active IKE_SAs */
                return TRUE;
        }
 
@@ -148,8 +138,9 @@ static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
                        iterator_t *iterator;
                        peer_cfg_t *peer_cfg;
                        u_int32_t extension, condition;
-                       host_t *local_vip, *remote_vip, *addr;
+                       host_t *addr;
                        identification_t *eap_id;
+                       ike_sa_id_t *id;
 
                        peer_cfg = ike_sa->get_peer_cfg(ike_sa);
 
@@ -165,12 +156,11 @@ static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
                                          | copy_extension(ike_sa, EXT_MOBIKE)
                                          | copy_extension(ike_sa, EXT_HASH_AND_URL);
 
-                       local_vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
-                       remote_vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
                        eap_id = ike_sa->get_eap_identity(ike_sa);
+                       id = ike_sa->get_id(ike_sa);
 
                        m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
-                       m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
+                       m->add_attribute(m, HA_SYNC_IKE_ID, id);
                        m->add_attribute(m, HA_SYNC_LOCAL_ID, ike_sa->get_my_id(ike_sa));
                        m->add_attribute(m, HA_SYNC_REMOTE_ID, ike_sa->get_other_id(ike_sa));
                        m->add_attribute(m, HA_SYNC_LOCAL_ADDR, ike_sa->get_my_host(ike_sa));
@@ -178,14 +168,6 @@ static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
                        m->add_attribute(m, HA_SYNC_CONDITIONS, condition);
                        m->add_attribute(m, HA_SYNC_EXTENSIONS, extension);
                        m->add_attribute(m, HA_SYNC_CONFIG_NAME, peer_cfg->get_name(peer_cfg));
-                       if (local_vip)
-                       {
-                               m->add_attribute(m, HA_SYNC_LOCAL_VIP, local_vip);
-                       }
-                       if (remote_vip)
-                       {
-                               m->add_attribute(m, HA_SYNC_REMOTE_VIP, remote_vip);
-                       }
                        if (eap_id)
                        {
                                m->add_attribute(m, HA_SYNC_EAP_ID, eap_id);
@@ -213,6 +195,54 @@ static bool ike_state_change(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
 }
 
 /**
+ * Implementation of listener_t.message
+ */
+static bool message_hook(private_ha_sync_ike_t *this, ike_sa_t *ike_sa,
+                                                message_t *message, bool incoming)
+{
+       if (message->get_exchange_type(message) != IKE_SA_INIT &&
+               message->get_request(message))
+       {       /* we sync on requests, but skip it on IKE_SA_INIT */
+               ha_sync_message_t *m;
+               u_int32_t mid;
+
+               m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
+               m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
+               mid = message->get_message_id(message) + 1;
+               if (incoming)
+               {
+                       m->add_attribute(m, HA_SYNC_RESPOND_MID, mid);
+               }
+               else
+               {
+                       m->add_attribute(m, HA_SYNC_INITIATE_MID, mid);
+               }
+               this->socket->push(this->socket, m);
+               m->destroy(m);
+       }
+       if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+               message->get_exchange_type(message) == IKE_AUTH &&
+               !message->get_request(message))
+       {       /* After IKE_SA has been established, sync peers virtual IP.
+                * We cannot sync it in the state_change hook, it is installed later.
+                * TODO: where to sync local VIP? */
+               ha_sync_message_t *m;
+               host_t *vip;
+
+               vip = ike_sa->get_virtual_ip(ike_sa, FALSE);
+               if (vip)
+               {
+                       m = ha_sync_message_create(HA_SYNC_IKE_UPDATE);
+                       m->add_attribute(m, HA_SYNC_IKE_ID, ike_sa->get_id(ike_sa));
+                       m->add_attribute(m, HA_SYNC_REMOTE_VIP, vip);
+                       this->socket->push(this->socket, m);
+                       m->destroy(m);
+               }
+       }
+       return TRUE;
+}
+
+/**
  * Implementation of ha_sync_ike_t.destroy.
  */
 static void destroy(private_ha_sync_ike_t *this)
@@ -223,18 +253,17 @@ static void destroy(private_ha_sync_ike_t *this)
 /**
  * See header
  */
-ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket,
-                                                                 ha_sync_cache_t *cache)
+ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket)
 {
        private_ha_sync_ike_t *this = malloc_thing(private_ha_sync_ike_t);
 
        memset(&this->public.listener, 0, sizeof(listener_t));
        this->public.listener.ike_keys = (bool(*)(listener_t*, ike_sa_t *ike_sa, diffie_hellman_t *dh,chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey))ike_keys;
        this->public.listener.ike_state_change = (bool(*)(listener_t*,ike_sa_t *ike_sa, ike_sa_state_t state))ike_state_change;
+       this->public.listener.message = (bool(*)(listener_t*, ike_sa_t *, message_t *,bool))message_hook;
        this->public.destroy = (void(*)(ha_sync_ike_t*))destroy;
 
        this->socket = socket;
-       this->cache = cache;
 
        return &this->public;
 }
index b47534a..0ffbbde 100644 (file)
@@ -24,7 +24,7 @@
 #define HA_SYNC_IKE_H_
 
 #include "ha_sync_socket.h"
-#include "ha_sync_cache.h"
+#include "ha_sync_segments.h"
 
 #include <daemon.h>
 
@@ -50,10 +50,8 @@ struct ha_sync_ike_t {
  * Create a ha_sync_ike instance.
  *
  * @param socket               socket to use for sending synchronization messages
- * @param cache                        synced and cached SAs
  * @return                             IKE listener
  */
-ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket,
-                                                                 ha_sync_cache_t *cache);
+ha_sync_ike_t *ha_sync_ike_create(ha_sync_socket_t *socket);
 
 #endif /* HA_SYNC_IKE_ @}*/
index 3cf0a10..314c20d 100644 (file)
@@ -211,7 +211,7 @@ static void add_attribute(private_ha_sync_message_t *this,
                {
                        u_int8_t val;
 
-                       val = (u_int8_t)va_arg(args, u_int32_t);
+                       val = va_arg(args, u_int);
                        check_buf(this, sizeof(val));
                        this->buf.ptr[this->buf.len] = val;
                        this->buf.len += sizeof(val);
@@ -228,7 +228,7 @@ static void add_attribute(private_ha_sync_message_t *this,
                {
                        u_int16_t val;
 
-                       val = (u_int16_t)va_arg(args, u_int32_t);
+                       val = va_arg(args, u_int);
                        check_buf(this, sizeof(val));
                        *(u_int16_t*)(this->buf.ptr + this->buf.len) = htons(val);
                        this->buf.len += sizeof(val);
@@ -239,10 +239,12 @@ static void add_attribute(private_ha_sync_message_t *this,
                case HA_SYNC_EXTENSIONS:
                case HA_SYNC_INBOUND_SPI:
                case HA_SYNC_OUTBOUND_SPI:
+               case HA_SYNC_INITIATE_MID:
+               case HA_SYNC_RESPOND_MID:
                {
                        u_int32_t val;
 
-                       val = va_arg(args, u_int32_t);
+                       val = va_arg(args, u_int);
                        check_buf(this, sizeof(val));
                        *(u_int32_t*)(this->buf.ptr + this->buf.len) = htonl(val);
                        this->buf.len += sizeof(val);
@@ -453,6 +455,8 @@ static bool attribute_enumerate(attribute_enumerator_t *this,
                case HA_SYNC_EXTENSIONS:
                case HA_SYNC_INBOUND_SPI:
                case HA_SYNC_OUTBOUND_SPI:
+               case HA_SYNC_INITIATE_MID:
+               case HA_SYNC_RESPOND_MID:
                {
                        if (this->buf.len < sizeof(u_int32_t))
                        {
index eec7b4f..8fe9610 100644 (file)
@@ -119,6 +119,10 @@ enum ha_sync_message_attribute_t {
        HA_SYNC_LOCAL_TS,
        /** traffic_selector_t*, remote traffic selector */
        HA_SYNC_REMOTE_TS,
+       /** u_int32_t, initiating message ID */
+       HA_SYNC_INITIATE_MID,
+       /** u_int32_t, responding message ID */
+       HA_SYNC_RESPOND_MID,
 };
 
 /**
index 2164a4b..ce80eb1 100644 (file)
@@ -20,7 +20,7 @@
 #include "ha_sync_child.h"
 #include "ha_sync_socket.h"
 #include "ha_sync_dispatcher.h"
-#include "ha_sync_cache.h"
+#include "ha_sync_segments.h"
 #include "ha_sync_ctl.h"
 
 #include <daemon.h>
@@ -59,9 +59,9 @@ struct private_ha_sync_plugin_t {
        ha_sync_dispatcher_t *dispatcher;
 
        /**
-        * Local cache of a nodes synced SAs
+        * Active/Passive segment management
         */
-       ha_sync_cache_t *cache;
+       ha_sync_segments_t *segments;
 
        /**
         * Segment control interface via FIFO
@@ -80,7 +80,7 @@ static void destroy(private_ha_sync_plugin_t *this)
        this->child->destroy(this->child);
        this->dispatcher->destroy(this->dispatcher);
        this->ctl->destroy(this->ctl);
-       this->cache->destroy(this->cache);
+       this->segments->destroy(this->segments);
        this->socket->destroy(this->socket);
        free(this);
 }
@@ -100,11 +100,11 @@ plugin_t *plugin_create()
                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);
+       this->segments = ha_sync_segments_create();
+       this->ctl = ha_sync_ctl_create(this->segments);
+       this->dispatcher = ha_sync_dispatcher_create(this->socket);
+       this->ike = ha_sync_ike_create(this->socket);
+       this->child = ha_sync_child_create(this->socket);
        charon->bus->add_listener(charon->bus, &this->ike->listener);
        charon->bus->add_listener(charon->bus, &this->child->listener);
 
diff --git a/src/charon/plugins/ha_sync/ha_sync_segments.c b/src/charon/plugins/ha_sync/ha_sync_segments.c
new file mode 100644 (file)
index 0000000..6f9985b
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * 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_segments.h"
+
+#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_segments_t private_ha_sync_segments_t;
+
+/**
+ * Private data of an ha_sync_segments_t object.
+ */
+struct private_ha_sync_segments_t {
+
+       /**
+        * Public ha_sync_segments_t interface.
+        */
+       ha_sync_segments_t public;
+
+       /**
+        * Init value for jhash
+        */
+       u_int initval;
+
+       /**
+        * Total number of ClusterIP segments
+        */
+       u_int segment_count;
+
+       /**
+        * mask of active segments
+        */
+       u_int16_t active;
+};
+
+/**
+ * Check if a host address is in the CLUSTERIP segment
+ */
+static bool in_segment(private_ha_sync_segments_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_segments_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_segments_t.activate
+ */
+static void activate(private_ha_sync_segments_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 = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
+               while (enumerator->enumerate(enumerator, &ike_sa))
+               {
+                       if (ike_sa->get_state(ike_sa) == IKE_PASSIVE &&
+                               in_segment(this, ike_sa->get_other_host(ike_sa), segment))
+                       {
+                               ike_sa->set_state(ike_sa, IKE_ESTABLISHED);
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               log_segments(this, TRUE, segment);
+       }
+}
+
+/**
+ * Implementation of ha_sync_segments_t.deactivate
+ */
+static void deactivate(private_ha_sync_segments_t *this, u_int segment)
+{
+       ike_sa_t *ike_sa;
+       enumerator_t *enumerator;
+       u_int16_t mask = 0x01 << (segment - 1);
+
+       if (segment > 0 && segment <= this->segment_count && (this->active & mask))
+       {
+               this->active &= ~mask;
+
+               enumerator = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
+               while (enumerator->enumerate(enumerator, &ike_sa))
+               {
+                       if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED &&
+                               in_segment(this, ike_sa->get_other_host(ike_sa), segment))
+                       {
+                               ike_sa->set_state(ike_sa, IKE_PASSIVE);
+                       }
+               }
+               enumerator->destroy(enumerator);
+
+               log_segments(this, FALSE, segment);
+       }
+}
+
+/**
+ * Implementation of ha_sync_segments_t.destroy.
+ */
+static void destroy(private_ha_sync_segments_t *this)
+{
+       free(this);
+}
+
+/**
+ * See header
+ */
+ha_sync_segments_t *ha_sync_segments_create()
+{
+       private_ha_sync_segments_t *this = malloc_thing(private_ha_sync_segments_t);
+       enumerator_t *enumerator;
+       u_int segment;
+       char *str;
+
+       this->public.activate = (void(*)(ha_sync_segments_t*, u_int segment))activate;
+       this->public.deactivate = (void(*)(ha_sync_segments_t*, u_int segment))deactivate;
+       this->public.destroy = (void(*)(ha_sync_segments_t*))destroy;
+
+       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_segments.h b/src/charon/plugins/ha_sync/ha_sync_segments.h
new file mode 100644 (file)
index 0000000..62908cf
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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_segments ha_sync_segments
+ * @{ @ingroup ha_sync
+ */
+
+#ifndef HA_SYNC_SEGMENTS_H_
+#define HA_SYNC_SEGMENTS_H_
+
+#include <daemon.h>
+
+typedef struct ha_sync_segments_t ha_sync_segments_t;
+
+/**
+ * Locally segmentsd HA state synced from other nodes.
+ */
+struct ha_sync_segments_t {
+
+       /**
+        * Activate a set of IKE_SAs identified by a segments.
+        *
+        * Activating means do a takeover of SAs as the responsible node has failed.
+        * This involves moving all SAs to the daemons IKE_SA manager and handle
+        * them actively now.
+        *
+        * @param segments      numerical segments to takeover
+        */
+       void (*activate)(ha_sync_segments_t *this, u_int segments);
+
+       /**
+        * Deactivate a set of IKE_SAs identified by a segments.
+        *
+        * @param segments      numerical segments to takeover
+        */
+       void (*deactivate)(ha_sync_segments_t *this, u_int segments);
+
+       /**
+        * Destroy a ha_sync_segments_t.
+        */
+       void (*destroy)(ha_sync_segments_t *this);
+};
+
+/**
+ * Create a ha_sync_segments instance.
+ */
+ha_sync_segments_t *ha_sync_segments_create();
+
+#endif /* HA_SYNC_SEGMENTS_ @}*/
index d70bed6..e6c6035 100644 (file)
@@ -322,7 +322,7 @@ struct child_sa_t {
 };
 
 /**
- * Constructor to create a new child_sa_t.
+ * Constructor to create a child SA negotiated with IKE.
  *
  * @param me                           own address
  * @param other                                remote address