HA kernel interface can mangle netfilter rules, currently with iptables invocation

This commit is contained in:
Martin Willi
2010-04-07 13:55:14 +02:00
committed by Martin Willi
parent dbc91f7c84
commit 4e248733a8
4 changed files with 183 additions and 29 deletions
+150 -4
View File
@@ -19,6 +19,12 @@ typedef u_int32_t u32;
typedef u_int8_t u8; typedef u_int8_t u8;
#include <linux/jhash.h> #include <linux/jhash.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef struct private_ha_sync_kernel_t private_ha_sync_kernel_t; typedef struct private_ha_sync_kernel_t private_ha_sync_kernel_t;
@@ -43,15 +49,16 @@ struct private_ha_sync_kernel_t {
u_int segment_count; u_int segment_count;
/** /**
* mask of active segments * List of virtual addresses, as host_t*
*/ */
segment_mask_t active; linked_list_t *virtuals;
}; };
/** /**
* Implementation of ha_sync_kernel_t.in_segment * Implementation of ha_sync_kernel_t.in_segment
*/ */
static bool in_segment(private_ha_sync_kernel_t *this, host_t *host, u_int segment) static bool in_segment(private_ha_sync_kernel_t *this,
host_t *host, u_int segment)
{ {
if (host->get_family(host) == AF_INET) if (host->get_family(host) == AF_INET)
{ {
@@ -68,12 +75,140 @@ static bool in_segment(private_ha_sync_kernel_t *this, host_t *host, u_int segme
} }
return FALSE; return FALSE;
} }
/**
* Activate/Deactivate a segment
*/
static void activate_deactivate(private_ha_sync_kernel_t *this,
u_int segment, char op)
{
enumerator_t *enumerator;
host_t *host;
char cmd[8], file[256];
int fd;
enumerator = this->virtuals->create_enumerator(this->virtuals);
while (enumerator->enumerate(enumerator, &host))
{
snprintf(file, sizeof(file), "/proc/net/ipt_CLUSTERIP/%H", host);
snprintf(cmd, sizeof(cmd), "%c%d\n", op, segment);
fd = open(file, O_WRONLY);
if (fd == -1)
{
DBG1(DBG_CFG, "opening CLUSTERIP file '%s' failed: %s",
file, strerror(errno));
continue;
}
if (write(fd, cmd, strlen(cmd) == -1))
{
DBG1(DBG_CFG, "writing to CLUSTERIP file '%s' failed: %s",
file, strerror(errno));
}
close(fd);
}
enumerator->destroy(enumerator);
}
/**
* Implementation of ha_sync_kernel_t.activate
*/
static void activate(private_ha_sync_kernel_t *this, u_int segment)
{
activate_deactivate(this, segment, '+');
}
/**
* Implementation of ha_sync_kernel_t.deactivate
*/
static void deactivate(private_ha_sync_kernel_t *this, u_int segment)
{
activate_deactivate(this, segment, '-');
}
/**
* Mangle IPtable rules for virtual addresses
*/
static bool mangle_rules(private_ha_sync_kernel_t *this, bool add,
segment_mask_t active)
{
enumerator_t *enumerator;
host_t *host;
u_char i, mac = 0x20;
char *iface, buf[256];
enumerator = this->virtuals->create_enumerator(this->virtuals);
while (enumerator->enumerate(enumerator, &host))
{
iface = charon->kernel_interface->get_interface(
charon->kernel_interface, host);
if (!iface)
{
DBG1(DBG_CFG, "cluster address %H not installed, ignored", host);
this->virtuals->remove_at(this->virtuals, enumerator);
host->destroy(host);
continue;
}
/* iptables insists of a local node specification. We add '1' but drop
* it afterwards. */
snprintf(buf, sizeof(buf),
"/sbin/iptables -%c INPUT -i %s -d %H -j CLUSTERIP --new "
"--hashmode sourceip --clustermac 01:00:5e:00:00:%2x "
"--total-nodes %d --local-node 1",
add ? 'A' : 'D', iface, host, mac++, this->segment_count);
free(iface);
if (system(buf) != 0)
{
DBG1(DBG_CFG, "installing CLUSTERIP rule '%s' failed", buf);
}
}
enumerator->destroy(enumerator);
if (add)
{
deactivate(this, 1);
for (i = 0; i < SEGMENTS_MAX; i++)
{
if (active & SEGMENTS_BIT(i))
{
activate(this, i);
}
}
}
return TRUE;
}
/**
* Parse the list of virtual cluster addresses
*/
static void parse_virtuals(private_ha_sync_kernel_t *this, char *virtual)
{
enumerator_t *enumerator;
host_t *host;
enumerator = enumerator_create_token(virtual, ",", " ");
while (enumerator->enumerate(enumerator, &virtual))
{
host = host_create_from_string(virtual, 0);
if (host)
{
this->virtuals->insert_last(this->virtuals, host);
}
else
{
DBG1(DBG_CFG, "virtual cluster address '%s' invalid, ignored",
virtual);
}
}
enumerator->destroy(enumerator);
}
/** /**
* Implementation of ha_sync_kernel_t.destroy. * Implementation of ha_sync_kernel_t.destroy.
*/ */
static void destroy(private_ha_sync_kernel_t *this) static void destroy(private_ha_sync_kernel_t *this)
{ {
mangle_rules(this, FALSE, 0);
this->virtuals->destroy_offset(this->virtuals, offsetof(host_t, destroy));
free(this); free(this);
} }
@@ -81,15 +216,26 @@ static void destroy(private_ha_sync_kernel_t *this)
* See header * See header
*/ */
ha_sync_kernel_t *ha_sync_kernel_create(u_int count, segment_mask_t active, ha_sync_kernel_t *ha_sync_kernel_create(u_int count, segment_mask_t active,
char *external, char *internal) char *virtuals)
{ {
private_ha_sync_kernel_t *this = malloc_thing(private_ha_sync_kernel_t); private_ha_sync_kernel_t *this = malloc_thing(private_ha_sync_kernel_t);
this->public.in_segment = (bool(*)(ha_sync_kernel_t*, host_t *host, u_int segment))in_segment; this->public.in_segment = (bool(*)(ha_sync_kernel_t*, host_t *host, u_int segment))in_segment;
this->public.activate = (void(*)(ha_sync_kernel_t*, u_int segment))activate;
this->public.deactivate = (void(*)(ha_sync_kernel_t*, u_int segment))deactivate;
this->public.destroy = (void(*)(ha_sync_kernel_t*))destroy; this->public.destroy = (void(*)(ha_sync_kernel_t*))destroy;
this->initval = 0; this->initval = 0;
this->segment_count = count; this->segment_count = count;
this->virtuals = linked_list_create();
parse_virtuals(this, virtuals);
if (!mangle_rules(this, TRUE, active))
{
destroy(this);
return NULL;
}
return &this->public; return &this->public;
} }
+16 -3
View File
@@ -39,6 +39,20 @@ struct ha_sync_kernel_t {
*/ */
bool (*in_segment)(ha_sync_kernel_t *this, host_t *host, u_int segment); bool (*in_segment)(ha_sync_kernel_t *this, host_t *host, u_int segment);
/**
* Activate a segment at kernel level for all cluster addresses.
*
* @param segment segment to activate
*/
void (*activate)(ha_sync_kernel_t *this, u_int segment);
/**
* Deactivate a segment at kernel level for all cluster addresses.
*
* @param segment segment to deactivate
*/
void (*deactivate)(ha_sync_kernel_t *this, u_int segment);
/** /**
* Destroy a ha_sync_kernel_t. * Destroy a ha_sync_kernel_t.
*/ */
@@ -50,10 +64,9 @@ struct ha_sync_kernel_t {
* *
* @param count total number of segments to use * @param count total number of segments to use
* @param active bitmask of initially active segments * @param active bitmask of initially active segments
* @param external external virtual IP the cluster acts as * @param virtuals comma separated list of virtual cluster addresses
* @param internal internal virtual IP the cluster uses
*/ */
ha_sync_kernel_t *ha_sync_kernel_create(u_int count, segment_mask_t active, ha_sync_kernel_t *ha_sync_kernel_create(u_int count, segment_mask_t active,
char *external, char *internal); char *virtuals);
#endif /* HA_SYNC_KERNEL_ @}*/ #endif /* HA_SYNC_KERNEL_ @}*/
+4 -11
View File
@@ -125,7 +125,7 @@ static segment_mask_t parse_active(char *active)
plugin_t *plugin_create() plugin_t *plugin_create()
{ {
private_ha_sync_plugin_t *this; private_ha_sync_plugin_t *this;
char *local, *remote, *secret, *external, *internal; char *local, *remote, *secret, *virtuals;
segment_mask_t active; segment_mask_t active;
u_int count; u_int count;
bool fifo; bool fifo;
@@ -134,10 +134,8 @@ plugin_t *plugin_create()
"charon.plugins.ha_sync.local", NULL); "charon.plugins.ha_sync.local", NULL);
remote = lib->settings->get_str(lib->settings, remote = lib->settings->get_str(lib->settings,
"charon.plugins.ha_sync.remote", NULL); "charon.plugins.ha_sync.remote", NULL);
external = lib->settings->get_str(lib->settings, virtuals = lib->settings->get_str(lib->settings,
"charon.plugins.ha_sync.external", NULL); "charon.plugins.ha_sync.virtuals", "");
internal = lib->settings->get_str(lib->settings,
"charon.plugins.ha_sync.internal", NULL);
secret = lib->settings->get_str(lib->settings, secret = lib->settings->get_str(lib->settings,
"charon.plugins.ha_sync.secret", NULL); "charon.plugins.ha_sync.secret", NULL);
fifo = lib->settings->get_bool(lib->settings, fifo = lib->settings->get_bool(lib->settings,
@@ -151,11 +149,6 @@ plugin_t *plugin_create()
DBG1(DBG_CFG, "HA sync config misses local/remote address"); DBG1(DBG_CFG, "HA sync config misses local/remote address");
return NULL; return NULL;
} }
if (!external || !internal)
{
DBG1(DBG_CFG, "HA sync config misses external/internal virtual address");
return NULL;
}
this = malloc_thing(private_ha_sync_plugin_t); this = malloc_thing(private_ha_sync_plugin_t);
@@ -169,7 +162,7 @@ plugin_t *plugin_create()
free(this); free(this);
return NULL; return NULL;
} }
this->kernel = ha_sync_kernel_create(count, active, external, internal); this->kernel = ha_sync_kernel_create(count, active, virtuals);
if (!this->kernel) if (!this->kernel)
{ {
this->socket->destroy(this->socket); this->socket->destroy(this->socket);
+13 -11
View File
@@ -107,17 +107,6 @@ static void enable_disable(private_ha_sync_segments_t *this, u_int segment,
{ /* or segment_count times for all segments */ { /* or segment_count times for all segments */
limit = this->segment_count; limit = this->segment_count;
} }
for (i = segment; i < limit; i++)
{
if (enable)
{
this->active |= SEGMENTS_BIT(i);
}
else
{
this->active &= ~SEGMENTS_BIT(i);
}
}
enumerator = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager); enumerator = charon->ike_sa_manager->create_enumerator(charon->ike_sa_manager);
while (enumerator->enumerate(enumerator, &ike_sa)) while (enumerator->enumerate(enumerator, &ike_sa))
{ {
@@ -134,6 +123,19 @@ static void enable_disable(private_ha_sync_segments_t *this, u_int segment,
} }
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
for (i = segment; i < limit; i++)
{
if (enable)
{
this->active |= SEGMENTS_BIT(i);
this->kernel->activate(this->kernel, i);
}
else
{
this->active &= ~SEGMENTS_BIT(i);
this->kernel->deactivate(this->kernel, i);
}
}
log_segments(this, enable, segment); log_segments(this, enable, segment);
} }