#include "stroke_attribute.h"
#include <daemon.h>
+#include <attributes/mem_pool.h>
#include <utils/linked_list.h>
-#include <utils/hashtable.h>
#include <threading/mutex.h>
-#define POOL_LIMIT (sizeof(uintptr_t)*8)
-
typedef struct private_stroke_attribute_t private_stroke_attribute_t;
/**
stroke_attribute_t public;
/**
- * list of pools, contains pool_t
+ * list of pools, contains mem_pool_t
*/
linked_list_t *pools;
mutex_t *mutex;
};
-typedef struct {
- /** name of the pool */
- char *name;
- /** base address of the pool */
- host_t *base;
- /** size of the pool */
- int size;
- /** next unused address */
- int unused;
- /** hashtable [identity => offset], for online leases */
- hashtable_t *online;
- /** hashtable [identity => offset], for offline leases */
- hashtable_t *offline;
- /** hashtable [identity => identity], handles identity references */
- hashtable_t *ids;
-} pool_t;
-
-/**
- * hashtable hash function for identities
- */
-static u_int id_hash(identification_t *id)
-{
- return chunk_hash(id->get_encoding(id));
-}
-
-/**
- * hashtable equals function for identities
- */
-static bool id_equals(identification_t *a, identification_t *b)
-{
- return a->equals(a, b);
-}
-
-/**
- * destroy a pool_t
- */
-static void pool_destroy(pool_t *this)
-{
- enumerator_t *enumerator;
- identification_t *id;
-
- enumerator = this->ids->create_enumerator(this->ids);
- while (enumerator->enumerate(enumerator, &id, NULL))
- {
- id->destroy(id);
- }
- enumerator->destroy(enumerator);
- this->ids->destroy(this->ids);
- this->online->destroy(this->online);
- this->offline->destroy(this->offline);
- DESTROY_IF(this->base);
- free(this->name);
- free(this);
-}
-
/**
* find a pool by name
*/
-static pool_t *find_pool(private_stroke_attribute_t *this, char *name)
+static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
{
enumerator_t *enumerator;
- pool_t *current, *found = NULL;
+ mem_pool_t *current, *found = NULL;
enumerator = this->pools->create_enumerator(this->pools);
while (enumerator->enumerate(enumerator, ¤t))
{
- if (streq(name, current->name))
+ if (streq(name, current->get_name(current)))
{
found = current;
break;
}
/**
- * convert an pool offset to an address
- */
-host_t* offset2host(pool_t *pool, int offset)
-{
- chunk_t addr;
- host_t *host;
- u_int32_t *pos;
-
- offset--;
- if (offset > pool->size)
- {
- return NULL;
- }
-
- addr = chunk_clone(pool->base->get_address(pool->base));
- if (pool->base->get_family(pool->base) == AF_INET6)
- {
- pos = (u_int32_t*)(addr.ptr + 12);
- }
- else
- {
- pos = (u_int32_t*)addr.ptr;
- }
- *pos = htonl(offset + ntohl(*pos));
- host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
- free(addr.ptr);
- return host;
-}
-
-/**
- * convert a host to a pool offset
- */
-int host2offset(pool_t *pool, host_t *addr)
-{
- chunk_t host, base;
- u_int32_t hosti, basei;
-
- if (addr->get_family(addr) != pool->base->get_family(pool->base))
- {
- return -1;
- }
- host = addr->get_address(addr);
- base = pool->base->get_address(pool->base);
- if (addr->get_family(addr) == AF_INET6)
- {
- /* only look at last /32 block */
- if (!memeq(host.ptr, base.ptr, 12))
- {
- return -1;
- }
- host = chunk_skip(host, 12);
- base = chunk_skip(base, 12);
- }
- hosti = ntohl(*(u_int32_t*)(host.ptr));
- basei = ntohl(*(u_int32_t*)(base.ptr));
- if (hosti > basei + pool->size)
- {
- return -1;
- }
- return hosti - basei + 1;
-}
-
-/**
* Implementation of attribute_provider_t.acquire_address
*/
static host_t* acquire_address(private_stroke_attribute_t *this,
char *name, identification_t *id,
host_t *requested)
{
- pool_t *pool;
- uintptr_t offset = 0;
- enumerator_t *enumerator;
- identification_t *old_id;
-
+ mem_pool_t *pool;
+ host_t *addr = NULL;
this->mutex->lock(this->mutex);
pool = find_pool(this, name);
- while (pool)
+ if (pool)
{
- /* handle %config case by mirroring requested address */
- if (pool->size == 0)
- {
- this->mutex->unlock(this->mutex);
- return requested->clone(requested);
- }
-
- if (!requested->is_anyaddr(requested) &&
- requested->get_family(requested) !=
- pool->base->get_family(pool->base))
- {
- DBG1(DBG_CFG, "IP pool address family mismatch");
- break;
- }
-
- /* check for a valid offline lease, refresh */
- offset = (uintptr_t)pool->offline->remove(pool->offline, id);
- if (offset)
- {
- id = pool->ids->get(pool->ids, id);
- if (id)
- {
- DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
- pool->online->put(pool->online, id, (void*)offset);
- break;
- }
- }
-
- /* check for a valid online lease, reassign */
- offset = (uintptr_t)pool->online->get(pool->online, id);
- if (offset && offset == host2offset(pool, requested))
- {
- DBG1(DBG_CFG, "reassigning online lease to '%Y'", id);
- break;
- }
-
- if (pool->unused < pool->size)
- {
- /* assigning offset, starting by 1. Handling 0 in hashtable
- * is difficult. */
- offset = ++pool->unused;
- id = id->clone(id);
- pool->ids->put(pool->ids, id, id);
- pool->online->put(pool->online, id, (void*)offset);
- DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
- break;
- }
- /* no more addresses, replace the first found offline lease */
- enumerator = pool->offline->create_enumerator(pool->offline);
- if (enumerator->enumerate(enumerator, &old_id, &offset))
- {
- offset = (uintptr_t)pool->offline->remove(pool->offline, old_id);
- if (offset)
- {
- /* destroy reference to old ID */
- old_id = pool->ids->remove(pool->ids, old_id);
- DBG1(DBG_CFG, "reassigning existing offline lease by '%Y' to '%Y'",
- old_id, id);
- if (old_id)
- {
- old_id->destroy(old_id);
- }
- id = id->clone(id);
- pool->ids->put(pool->ids, id, id);
- pool->online->put(pool->online, id, (void*)offset);
- enumerator->destroy(enumerator);
- break;
- }
- }
- enumerator->destroy(enumerator);
-
- DBG1(DBG_CFG, "pool '%s' is full, unable to assign address", name);
- break;
+ addr = pool->acquire_address(pool, id, requested);
}
this->mutex->unlock(this->mutex);
- if (offset)
- {
- return offset2host(pool, offset);
- }
- return NULL;
+ return addr;
}
/**
static bool release_address(private_stroke_attribute_t *this,
char *name, host_t *address, identification_t *id)
{
- pool_t *pool;
+ mem_pool_t *pool;
bool found = FALSE;
- uintptr_t offset;
-
this->mutex->lock(this->mutex);
pool = find_pool(this, name);
if (pool)
{
- if (pool->size != 0)
- {
- offset = (uintptr_t)pool->online->remove(pool->online, id);
- if (offset)
- {
- id = pool->ids->get(pool->ids, id);
- if (id)
- {
- DBG1(DBG_CFG, "lease %H by '%Y' went offline", address, id);
- pool->offline->put(pool->offline, id, (void*)offset);
- found = TRUE;
- }
- }
- }
+ found = pool->release_address(pool, address, id);
}
this->mutex->unlock(this->mutex);
return found;
{
if (msg->add_conn.other.sourceip_mask)
{
- pool_t *pool;
-
- pool = malloc_thing(pool_t);
- pool->base = NULL;
- pool->size = 0;
- pool->unused = 0;
- pool->name = strdup(msg->add_conn.name);
- pool->online = hashtable_create((hashtable_hash_t)id_hash,
- (hashtable_equals_t)id_equals, 16);
- pool->offline = hashtable_create((hashtable_hash_t)id_hash,
- (hashtable_equals_t)id_equals, 16);
- pool->ids = hashtable_create((hashtable_hash_t)id_hash,
- (hashtable_equals_t)id_equals, 16);
+ mem_pool_t *pool;
+ host_t *base = NULL;
+ u_int32_t bits = 0;
/* if %config, add an empty pool, otherwise */
if (msg->add_conn.other.sourceip)
{
- u_int32_t bits;
- int family;
-
DBG1(DBG_CFG, "adding virtual IP address pool '%s': %s/%d",
msg->add_conn.name, msg->add_conn.other.sourceip,
msg->add_conn.other.sourceip_mask);
-
- pool->base = host_create_from_string(msg->add_conn.other.sourceip, 0);
- if (!pool->base)
+ base = host_create_from_string(msg->add_conn.other.sourceip, 0);
+ if (!base)
{
- pool_destroy(pool);
DBG1(DBG_CFG, "virtual IP address invalid, discarded");
return;
}
- family = pool->base->get_family(pool->base);
- bits = (family == AF_INET ? 32 : 128) - msg->add_conn.other.sourceip_mask;
- if (bits > POOL_LIMIT)
- {
- bits = POOL_LIMIT;
- DBG1(DBG_CFG, "virtual IP pool to large, limiting to %s/%d",
- msg->add_conn.other.sourceip,
- (family == AF_INET ? 32 : 128) - bits);
- }
- pool->size = 1 << (bits);
-
- if (pool->size > 2)
- { /* do not use first and last addresses of a block */
- pool->unused++;
- pool->size--;
- }
+ bits = msg->add_conn.other.sourceip_mask;
}
+ pool = mem_pool_create(msg->add_conn.name, base, bits);
+ DESTROY_IF(base);
+
this->mutex->lock(this->mutex);
this->pools->insert_last(this->pools, pool);
this->mutex->unlock(this->mutex);
static void del_pool(private_stroke_attribute_t *this, stroke_msg_t *msg)
{
enumerator_t *enumerator;
- pool_t *pool;
+ mem_pool_t *pool;
this->mutex->lock(this->mutex);
enumerator = this->pools->create_enumerator(this->pools);
while (enumerator->enumerate(enumerator, &pool))
{
- if (streq(msg->del_conn.name, pool->name))
+ if (streq(msg->del_conn.name, pool->get_name(pool)))
{
this->pools->remove_at(this->pools, enumerator);
- pool_destroy(pool);
+ pool->destroy(pool);
break;
}
}
/**
* Pool enumerator filter function, converts pool_t to name, size, ...
*/
-static bool pool_filter(void *mutex, pool_t **poolp, char **name,
+static bool pool_filter(void *mutex, mem_pool_t **poolp, const char **name,
void *d1, u_int *size, void *d2, u_int *online,
void *d3, u_int *offline)
{
- pool_t *pool = *poolp;
-
- *name = pool->name;
- *size = pool->size;
- *online = pool->online->get_count(pool->online);
- *offline = pool->offline->get_count(pool->offline);
+ mem_pool_t *pool = *poolp;
+ *name = pool->get_name(pool);
+ *size = pool->get_size(pool);
+ *online = pool->get_online(pool);
+ *offline = pool->get_offline(pool);
return TRUE;
}
}
/**
- * lease enumerator
- */
-typedef struct {
- /** implemented enumerator interface */
- enumerator_t public;
- /** inner hash-table enumerator */
- enumerator_t *inner;
- /** enumerated pool */
- pool_t *pool;
- /** mutex to unlock on destruction */
- mutex_t *mutex;
- /** currently enumerated lease address */
- host_t *current;
-} lease_enumerator_t;
-
-/**
- * Implementation of lease_enumerator_t.enumerate
- */
-static bool lease_enumerate(lease_enumerator_t *this, identification_t **id_out,
- host_t **addr_out, bool *online)
-{
- identification_t *id;
- uintptr_t offset;
-
- DESTROY_IF(this->current);
- this->current = NULL;
-
- if (this->inner->enumerate(this->inner, &id, NULL))
- {
- offset = (uintptr_t)this->pool->online->get(this->pool->online, id);
- if (offset)
- {
- *id_out = id;
- *addr_out = this->current = offset2host(this->pool, offset);
- *online = TRUE;
- return TRUE;
- }
- offset = (uintptr_t)this->pool->offline->get(this->pool->offline, id);
- if (offset)
- {
- *id_out = id;
- *addr_out = this->current = offset2host(this->pool, offset);
- *online = FALSE;
- return TRUE;
- }
- }
- return FALSE;
-}
-
-/**
- * Implementation of lease_enumerator_t.destroy
- */
-static void lease_enumerator_destroy(lease_enumerator_t *this)
-{
- DESTROY_IF(this->current);
- this->inner->destroy(this->inner);
- this->mutex->unlock(this->mutex);
- free(this);
-}
-
-/**
* Implementation of stroke_attribute_t.create_lease_enumerator
*/
static enumerator_t* create_lease_enumerator(private_stroke_attribute_t *this,
- char *pool)
+ char *name)
{
- lease_enumerator_t *enumerator;
-
+ mem_pool_t *pool;
this->mutex->lock(this->mutex);
- enumerator = malloc_thing(lease_enumerator_t);
- enumerator->pool = find_pool(this, pool);
- if (!enumerator->pool)
+ pool = find_pool(this, name);
+ if (!pool)
{
this->mutex->unlock(this->mutex);
- free(enumerator);
return NULL;
}
- enumerator->public.enumerate = (void*)lease_enumerate;
- enumerator->public.destroy = (void*)lease_enumerator_destroy;
- enumerator->inner = enumerator->pool->ids->create_enumerator(enumerator->pool->ids);
- enumerator->mutex = this->mutex;
- enumerator->current = NULL;
- return &enumerator->public;
+ return enumerator_create_cleaner(pool->create_lease_enumerator(pool),
+ (void*)this->mutex->unlock, this->mutex);
}
/**
static void destroy(private_stroke_attribute_t *this)
{
this->mutex->destroy(this->mutex);
- this->pools->destroy_function(this->pools, (void*)pool_destroy);
+ this->pools->destroy_offset(this->pools, offsetof(mem_pool_t, destroy));
free(this);
}
attribute_provider_t provider;
/**
- * Add a virtual IP address.
+ * Add a virtual IP address pool.
*
* @param msg stroke message
- * @param end end of stroke message that contains virtual IP.
*/
void (*add_pool)(stroke_attribute_t *this, stroke_msg_t *msg);
/**
- * Remove a virtual IP address.
+ * Remove a virtual IP address pool.
*
* @param msg stroke message
*/
* identification_t *id, host_t *address, bool online
*
* @param pool name of the pool to enumerate
- * @return enumerator, NULL if pool not found
+ * @return enumerator, NULL if pool not found
*/
enumerator_t* (*create_lease_enumerator)(stroke_attribute_t *this,
char *pool);
+
/**
* Destroy a stroke_attribute instance.
*/
hydra.c hydra.h \
attributes/attributes.c attributes/attributes.h \
attributes/attribute_provider.h attributes/attribute_handler.h \
-attributes/attribute_manager.c attributes/attribute_manager.h
+attributes/attribute_manager.c attributes/attribute_manager.h \
+attributes/mem_pool.c attributes/mem_pool.h
libhydra_la_LIBADD =
--- /dev/null
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * 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.
+ */
+
+#include "mem_pool.h"
+
+#include <debug.h>
+#include <utils/hashtable.h>
+
+#define POOL_LIMIT (sizeof(uintptr_t)*8)
+
+typedef struct private_mem_pool_t private_mem_pool_t;
+
+/**
+ * private data of mem_pool_t
+ */
+struct private_mem_pool_t {
+ /**
+ * public interface
+ */
+ mem_pool_t public;
+
+ /**
+ * name of the pool
+ */
+ char *name;
+
+ /**
+ * base address of the pool
+ */
+ host_t *base;
+
+ /**
+ * size of the pool
+ */
+ u_int size;
+
+ /**
+ * next unused address
+ */
+ u_int unused;
+
+ /**
+ * hashtable [identity => offset], for online leases
+ */
+ hashtable_t *online;
+
+ /**
+ * hashtable [identity => offset], for offline leases
+ */
+ hashtable_t *offline;
+
+ /**
+ * hashtable [identity => identity], handles identity references
+ */
+ hashtable_t *ids;
+};
+
+/**
+ * hashtable hash function for identities
+ */
+static u_int id_hash(identification_t *id)
+{
+ return chunk_hash(id->get_encoding(id));
+}
+
+/**
+ * hashtable equals function for identities
+ */
+static bool id_equals(identification_t *a, identification_t *b)
+{
+ return a->equals(a, b);
+}
+
+/**
+ * convert a pool offset to an address
+ */
+static host_t* offset2host(private_mem_pool_t *pool, int offset)
+{
+ chunk_t addr;
+ host_t *host;
+ u_int32_t *pos;
+
+ offset--;
+ if (offset > pool->size)
+ {
+ return NULL;
+ }
+
+ addr = chunk_clone(pool->base->get_address(pool->base));
+ if (pool->base->get_family(pool->base) == AF_INET6)
+ {
+ pos = (u_int32_t*)(addr.ptr + 12);
+ }
+ else
+ {
+ pos = (u_int32_t*)addr.ptr;
+ }
+ *pos = htonl(offset + ntohl(*pos));
+ host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
+ free(addr.ptr);
+ return host;
+}
+
+/**
+ * convert a host to a pool offset
+ */
+static int host2offset(private_mem_pool_t *pool, host_t *addr)
+{
+ chunk_t host, base;
+ u_int32_t hosti, basei;
+
+ if (addr->get_family(addr) != pool->base->get_family(pool->base))
+ {
+ return -1;
+ }
+ host = addr->get_address(addr);
+ base = pool->base->get_address(pool->base);
+ if (addr->get_family(addr) == AF_INET6)
+ {
+ /* only look at last /32 block */
+ if (!memeq(host.ptr, base.ptr, 12))
+ {
+ return -1;
+ }
+ host = chunk_skip(host, 12);
+ base = chunk_skip(base, 12);
+ }
+ hosti = ntohl(*(u_int32_t*)(host.ptr));
+ basei = ntohl(*(u_int32_t*)(base.ptr));
+ if (hosti > basei + pool->size)
+ {
+ return -1;
+ }
+ return hosti - basei + 1;
+}
+
+METHOD(mem_pool_t, get_name, const char*,
+ private_mem_pool_t *this)
+{
+ return this->name;
+}
+
+METHOD(mem_pool_t, get_size, u_int,
+ private_mem_pool_t *this)
+{
+ return this->size;
+}
+
+METHOD(mem_pool_t, get_online, u_int,
+ private_mem_pool_t *this)
+{
+ return this->online->get_count(this->online);
+}
+
+METHOD(mem_pool_t, get_offline, u_int,
+ private_mem_pool_t *this)
+{
+ return this->offline->get_count(this->offline);
+}
+
+METHOD(mem_pool_t, acquire_address, host_t*,
+ private_mem_pool_t *this, identification_t *id, host_t *requested)
+{
+ uintptr_t offset = 0;
+ enumerator_t *enumerator;
+ identification_t *old_id;
+
+ /* if the pool is empty (e.g. in the %config case) we simply return the
+ * requested address */
+ if (this->size == 0)
+ {
+ return requested->clone(requested);
+ }
+
+ while (TRUE)
+ {
+ if (!requested->is_anyaddr(requested) &&
+ requested->get_family(requested) !=
+ this->base->get_family(this->base))
+ {
+ DBG1("IP pool address family mismatch");
+ break;
+ }
+
+ /* check for a valid offline lease, refresh */
+ offset = (uintptr_t)this->offline->remove(this->offline, id);
+ if (offset)
+ {
+ id = this->ids->get(this->ids, id);
+ if (id)
+ {
+ DBG1("reassigning offline lease to '%Y'", id);
+ this->online->put(this->online, id, (void*)offset);
+ break;
+ }
+ }
+
+ /* check for a valid online lease, reassign */
+ offset = (uintptr_t)this->online->get(this->online, id);
+ if (offset && offset == host2offset(this, requested))
+ {
+ DBG1("reassigning online lease to '%Y'", id);
+ break;
+ }
+
+ if (this->unused < this->size)
+ {
+ /* assigning offset, starting by 1. Handling 0 in hashtable
+ * is difficult. */
+ offset = ++this->unused;
+ id = id->clone(id);
+ this->ids->put(this->ids, id, id);
+ this->online->put(this->online, id, (void*)offset);
+ DBG1("assigning new lease to '%Y'", id);
+ break;
+ }
+
+ /* no more addresses, replace the first found offline lease */
+ enumerator = this->offline->create_enumerator(this->offline);
+ if (enumerator->enumerate(enumerator, &old_id, &offset))
+ {
+ offset = (uintptr_t)this->offline->remove(this->offline, old_id);
+ if (offset)
+ {
+ /* destroy reference to old ID */
+ old_id = this->ids->remove(this->ids, old_id);
+ DBG1("reassigning existing offline lease by '%Y' to '%Y'",
+ old_id, id);
+ if (old_id)
+ {
+ old_id->destroy(old_id);
+ }
+ id = id->clone(id);
+ this->ids->put(this->ids, id, id);
+ this->online->put(this->online, id, (void*)offset);
+ enumerator->destroy(enumerator);
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ DBG1("pool '%s' is full, unable to assign address", this->name);
+ break;
+ }
+
+ if (offset)
+ {
+ return offset2host(this, offset);
+ }
+ return NULL;
+}
+
+METHOD(mem_pool_t, release_address, bool,
+ private_mem_pool_t *this, host_t *address, identification_t *id)
+{
+ uintptr_t offset;
+ if (this->size != 0)
+ {
+ offset = (uintptr_t)this->online->remove(this->online, id);
+ if (offset)
+ {
+ id = this->ids->get(this->ids, id);
+ if (id)
+ {
+ DBG1("lease %H by '%Y' went offline", address, id);
+ this->offline->put(this->offline, id, (void*)offset);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ * lease enumerator
+ */
+typedef struct {
+ /** implemented enumerator interface */
+ enumerator_t public;
+ /** inner hash-table enumerator */
+ enumerator_t *inner;
+ /** enumerated pool */
+ private_mem_pool_t *pool;
+ /** currently enumerated lease address */
+ host_t *current;
+} lease_enumerator_t;
+
+METHOD(enumerator_t, lease_enumerate, bool,
+ lease_enumerator_t *this, identification_t **id_out, host_t **addr_out,
+ bool *online)
+{
+ identification_t *id;
+ uintptr_t offset;
+
+ DESTROY_IF(this->current);
+ this->current = NULL;
+
+ if (this->inner->enumerate(this->inner, &id, NULL))
+ {
+ offset = (uintptr_t)this->pool->online->get(this->pool->online, id);
+ if (offset)
+ {
+ *id_out = id;
+ *addr_out = this->current = offset2host(this->pool, offset);
+ *online = TRUE;
+ return TRUE;
+ }
+ offset = (uintptr_t)this->pool->offline->get(this->pool->offline, id);
+ if (offset)
+ {
+ *id_out = id;
+ *addr_out = this->current = offset2host(this->pool, offset);
+ *online = FALSE;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+METHOD(enumerator_t, lease_enumerator_destroy, void,
+ lease_enumerator_t *this)
+{
+ DESTROY_IF(this->current);
+ this->inner->destroy(this->inner);
+ free(this);
+}
+
+METHOD(mem_pool_t, create_lease_enumerator, enumerator_t*,
+ private_mem_pool_t *this)
+{
+ lease_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_lease_enumerate,
+ .destroy = (void*)_lease_enumerator_destroy,
+ },
+ .pool = this,
+ .inner = this->ids->create_enumerator(this->ids),
+ );
+
+ return &enumerator->public;
+}
+
+METHOD(mem_pool_t, destroy, void,
+ private_mem_pool_t *this)
+{
+ enumerator_t *enumerator;
+ identification_t *id;
+
+ enumerator = this->ids->create_enumerator(this->ids);
+ while (enumerator->enumerate(enumerator, &id, NULL))
+ {
+ id->destroy(id);
+ }
+ enumerator->destroy(enumerator);
+
+ this->ids->destroy(this->ids);
+ this->online->destroy(this->online);
+ this->offline->destroy(this->offline);
+ DESTROY_IF(this->base);
+ free(this->name);
+ free(this);
+}
+
+/**
+ * Described in header
+ */
+mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
+{
+ private_mem_pool_t *this;
+
+ INIT(this,
+ .public = {
+ .get_name = _get_name,
+ .get_size = _get_size,
+ .get_online = _get_online,
+ .get_offline = _get_offline,
+ .acquire_address = _acquire_address,
+ .release_address = _release_address,
+ .create_lease_enumerator = _create_lease_enumerator,
+ .destroy = _destroy,
+ },
+ .name = strdup(name),
+ .online = hashtable_create((hashtable_hash_t)id_hash,
+ (hashtable_equals_t)id_equals, 16),
+ .offline = hashtable_create((hashtable_hash_t)id_hash,
+ (hashtable_equals_t)id_equals, 16),
+ .ids = hashtable_create((hashtable_hash_t)id_hash,
+ (hashtable_equals_t)id_equals, 16),
+ );
+
+ if (base)
+ {
+ int addr_bits = base->get_family(base) == AF_INET ? 32 : 128;
+ /* net bits -> host bits */
+ bits = addr_bits - bits;
+ if (bits > POOL_LIMIT)
+ {
+ bits = POOL_LIMIT;
+ DBG1("virtual IP pool too large, limiting to %H/%d",
+ base, addr_bits - bits);
+ }
+ this->size = 1 << (bits);
+
+ if (this->size > 2)
+ { /* do not use first and last addresses of a block */
+ this->unused++;
+ this->size--;
+ }
+ this->base = base->clone(base);
+ }
+
+ return &this->public;
+}
+
--- /dev/null
+/*
+ * Copyright (C) 2010 Tobias Brunner
+ * 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.
+ */
+
+/**
+ * @defgroup mem_pool mem_pool
+ * @{ @ingroup attributes
+ */
+
+#ifndef MEM_POOL_H
+#define MEM_POOL_H
+
+typedef struct mem_pool_t mem_pool_t;
+
+#include <utils/host.h>
+#include <utils/identification.h>
+
+/**
+ * An in-memory IP address pool.
+ *
+ * @note the implementation is not thread-safe.
+ */
+struct mem_pool_t {
+
+ /**
+ * Get the name of this pool.
+ *
+ * @return the name of this pool
+ */
+ const char* (*get_name)(mem_pool_t *this);
+
+ /**
+ * Get the size (i.e. number of addresses) of this pool.
+ *
+ * @return the size of this pool
+ */
+ u_int (*get_size)(mem_pool_t *this);
+
+ /**
+ * Get the number of online leases.
+ *
+ * @return the number of offline leases
+ */
+ u_int (*get_online)(mem_pool_t *this);
+
+ /**
+ * Get the number of offline leases.
+ *
+ * @return the number of online leases
+ */
+ u_int (*get_offline)(mem_pool_t *this);
+
+ /**
+ * Acquire an address for the given id from this pool.
+ *
+ * @param id the id to acquire an address for
+ * @param requested acquire this address, if possible
+ * @return the acquired address
+ */
+ host_t* (*acquire_address)(mem_pool_t *this, identification_t *id,
+ host_t *requested);
+
+ /**
+ * Release a previously acquired address.
+ *
+ * @param address the address to release
+ * @param id the id the address was assigned to
+ * @return TRUE, if the lease was found
+ */
+ bool (*release_address)(mem_pool_t *this, host_t *address,
+ identification_t *id);
+
+ /**
+ * Create an enumerator over the leases of this pool.
+ *
+ * Enumerator enumerates over
+ * identification_t *id, host_t *address, bool online
+ *
+ * @return enumerator
+ */
+ enumerator_t* (*create_lease_enumerator)(mem_pool_t *this);
+
+ /**
+ * Destroy a mem_pool_t instance.
+ */
+ void (*destroy)(mem_pool_t *this);
+};
+
+/**
+ * Create an in-memory IP address pool.
+ *
+ * An empty pool just returns the requested address.
+ *
+ * @param name name of this pool
+ * @param base base address of this pool, NULL to create an empty pool
+ * @param bits net mask
+ */
+mem_pool_t *mem_pool_create(char *name, host_t *base, int bits);
+
+#endif /** MEM_POOL_H_ @} */
+