summaryrefslogtreecommitdiff
path: root/src/libhydra/attributes
diff options
context:
space:
mode:
Diffstat (limited to 'src/libhydra/attributes')
-rw-r--r--src/libhydra/attributes/attribute_handler.h8
-rw-r--r--src/libhydra/attributes/attribute_manager.c79
-rw-r--r--src/libhydra/attributes/attribute_manager.h23
-rw-r--r--src/libhydra/attributes/attribute_provider.h19
-rw-r--r--src/libhydra/attributes/attributes.h2
-rw-r--r--src/libhydra/attributes/mem_pool.c364
-rw-r--r--src/libhydra/attributes/mem_pool.h44
7 files changed, 362 insertions, 177 deletions
diff --git a/src/libhydra/attributes/attribute_handler.h b/src/libhydra/attributes/attribute_handler.h
index d042f47ef..bc488f6cb 100644
--- a/src/libhydra/attributes/attribute_handler.h
+++ b/src/libhydra/attributes/attribute_handler.h
@@ -21,9 +21,9 @@
#ifndef ATTRIBUTE_HANDLER_H_
#define ATTRIBUTE_HANDLER_H_
-#include <chunk.h>
-#include <utils/host.h>
+#include <utils/chunk.h>
#include <utils/identification.h>
+#include <collections/linked_list.h>
#include "attributes.h"
@@ -62,11 +62,11 @@ struct attribute_handler_t {
* Enumerate attributes to request from a server.
*
* @param server server identity to request attributes from
- * @param vip virtual IP we are requesting, if any
+ * @param vips list of virtual IPs (host_t*) we are requesting
* @return enumerator (configuration_attribute_type_t, chunk_t)
*/
enumerator_t* (*create_attribute_enumerator)(attribute_handler_t *this,
- identification_t *server, host_t *vip);
+ identification_t *server, linked_list_t *vips);
};
#endif /** ATTRIBUTE_HANDLER_H_ @}*/
diff --git a/src/libhydra/attributes/attribute_manager.c b/src/libhydra/attributes/attribute_manager.c
index 95520531e..5fda8b426 100644
--- a/src/libhydra/attributes/attribute_manager.c
+++ b/src/libhydra/attributes/attribute_manager.c
@@ -15,8 +15,8 @@
#include "attribute_manager.h"
-#include <debug.h>
-#include <utils/linked_list.h>
+#include <utils/debug.h>
+#include <collections/linked_list.h>
#include <threading/rwlock.h>
typedef struct private_attribute_manager_t private_attribute_manager_t;
@@ -51,17 +51,17 @@ struct private_attribute_manager_t {
* Data to pass to enumerator filters
*/
typedef struct {
- /** attribute group pool */
- char *pool;
+ /** attribute group pools */
+ linked_list_t *pools;
/** server/peer identity */
identification_t *id;
- /** requesting/assigned virtual IP */
- host_t *vip;
+ /** requesting/assigned virtual IPs */
+ linked_list_t *vips;
} enum_data_t;
METHOD(attribute_manager_t, acquire_address, host_t*,
- private_attribute_manager_t *this, char *pool, identification_t *id,
- host_t *requested)
+ private_attribute_manager_t *this, linked_list_t *pools,
+ identification_t *id, host_t *requested)
{
enumerator_t *enumerator;
attribute_provider_t *current;
@@ -71,7 +71,7 @@ METHOD(attribute_manager_t, acquire_address, host_t*,
enumerator = this->providers->create_enumerator(this->providers);
while (enumerator->enumerate(enumerator, &current))
{
- host = current->acquire_address(current, pool, id, requested);
+ host = current->acquire_address(current, pools, id, requested);
if (host)
{
break;
@@ -80,15 +80,11 @@ METHOD(attribute_manager_t, acquire_address, host_t*,
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
- if (!host)
- {
- DBG1(DBG_CFG, "acquiring address from pool '%s' failed", pool);
- }
return host;
}
-METHOD(attribute_manager_t, release_address, void,
- private_attribute_manager_t *this, char *pool, host_t *address,
+METHOD(attribute_manager_t, release_address, bool,
+ private_attribute_manager_t *this, linked_list_t *pools, host_t *address,
identification_t *id)
{
enumerator_t *enumerator;
@@ -99,7 +95,7 @@ METHOD(attribute_manager_t, release_address, void,
enumerator = this->providers->create_enumerator(this->providers);
while (enumerator->enumerate(enumerator, &current))
{
- if (current->release_address(current, pool, address, id))
+ if (current->release_address(current, pools, address, id))
{
found = TRUE;
break;
@@ -108,10 +104,7 @@ METHOD(attribute_manager_t, release_address, void,
enumerator->destroy(enumerator);
this->lock->unlock(this->lock);
- if (!found)
- {
- DBG1(DBG_CFG, "releasing address to pool '%s' failed", pool);
- }
+ return found;
}
/**
@@ -120,19 +113,21 @@ METHOD(attribute_manager_t, release_address, void,
static enumerator_t *responder_enum_create(attribute_provider_t *provider,
enum_data_t *data)
{
- return provider->create_attribute_enumerator(provider, data->pool,
- data->id, data->vip);
+ return provider->create_attribute_enumerator(provider, data->pools,
+ data->id, data->vips);
}
METHOD(attribute_manager_t, create_responder_enumerator, enumerator_t*,
- private_attribute_manager_t *this, char *pool, identification_t *id,
- host_t *vip)
+ private_attribute_manager_t *this, linked_list_t *pools,
+ identification_t *id, linked_list_t *vips)
{
- enum_data_t *data = malloc_thing(enum_data_t);
+ enum_data_t *data;
- data->pool = pool;
- data->id = id;
- data->vip = vip;
+ INIT(data,
+ .pools = pools,
+ .id = id,
+ .vips = vips,
+ );
this->lock->read_lock(this->lock);
return enumerator_create_cleaner(
enumerator_create_nested(
@@ -238,8 +233,8 @@ typedef struct {
enumerator_t *inner;
/** server ID we want attributes for */
identification_t *id;
- /** virtual IP we are requesting along with attriubutes */
- host_t *vip;
+ /** virtual IPs we are requesting along with attriubutes */
+ linked_list_t *vips;
} initiator_enumerator_t;
/**
@@ -259,7 +254,7 @@ static bool initiator_enumerate(initiator_enumerator_t *this,
}
DESTROY_IF(this->inner);
this->inner = this->handler->create_attribute_enumerator(this->handler,
- this->id, this->vip);
+ this->id, this->vips);
}
/* inject the handler as additional attribute */
*handler = this->handler;
@@ -278,20 +273,22 @@ static void initiator_destroy(initiator_enumerator_t *this)
}
METHOD(attribute_manager_t, create_initiator_enumerator, enumerator_t*,
- private_attribute_manager_t *this, identification_t *id, host_t *vip)
+ private_attribute_manager_t *this, identification_t *id, linked_list_t *vips)
{
- initiator_enumerator_t *enumerator = malloc_thing(initiator_enumerator_t);
+ initiator_enumerator_t *enumerator;
this->lock->read_lock(this->lock);
- enumerator->public.enumerate = (void*)initiator_enumerate;
- enumerator->public.destroy = (void*)initiator_destroy;
- enumerator->this = this;
- enumerator->id = id;
- enumerator->vip = vip;
- enumerator->outer = this->handlers->create_enumerator(this->handlers);
- enumerator->inner = NULL;
- enumerator->handler = NULL;
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)initiator_enumerate,
+ .destroy = (void*)initiator_destroy,
+ },
+ .this = this,
+ .id = id,
+ .vips = vips,
+ .outer = this->handlers->create_enumerator(this->handlers),
+ );
return &enumerator->public;
}
diff --git a/src/libhydra/attributes/attribute_manager.h b/src/libhydra/attributes/attribute_manager.h
index 56afef7c6..99f41772c 100644
--- a/src/libhydra/attributes/attribute_manager.h
+++ b/src/libhydra/attributes/attribute_manager.h
@@ -39,35 +39,38 @@ struct attribute_manager_t {
/**
* Acquire a virtual IP address to assign to a peer.
*
- * @param pool pool name to acquire address from
+ * @param pools list of pool names (char*) to acquire from
* @param id peer identity to get address forua
* @param requested IP in configuration request
* @return allocated address, NULL to serve none
*/
host_t* (*acquire_address)(attribute_manager_t *this,
- char *pool, identification_t *id,
+ linked_list_t *pool, identification_t *id,
host_t *requested);
/**
* Release a previously acquired address.
*
- * @param pool pool name from which the address was acquired
+ * @param pools list of pool names (char*) to release to
* @param address address to release
* @param id peer identity to get address for
+ * @return TRUE if address released to pool
*/
- void (*release_address)(attribute_manager_t *this,
- char *pool, host_t *address, identification_t *id);
+ bool (*release_address)(attribute_manager_t *this,
+ linked_list_t *pools, host_t *address,
+ identification_t *id);
/**
* Create an enumerator over attributes to hand out to a peer.
*
- * @param pool pool name to get attributes from
+ * @param pool list of pools names (char*) to query attributes from
* @param id peer identity to hand out attributes to
- * @param vip virtual IP to assign to peer, if any
+ * @param vip list of virtual IPs (host_t*) to assign to peer
* @return enumerator (configuration_attribute_type_t, chunk_t)
*/
enumerator_t* (*create_responder_enumerator)(attribute_manager_t *this,
- char *pool, identification_t *id, host_t *vip);
+ linked_list_t *pool, identification_t *id,
+ linked_list_t *vips);
/**
* Register an attribute provider to the manager.
@@ -114,11 +117,11 @@ struct attribute_manager_t {
* Create an enumerator over attributes to request from server.
*
* @param id server identity to hand out attributes to
- * @param vip virtual IP going to request, if any
+ * @param vip list of virtual IPs (host_t*) going to request
* @return enumerator (attribute_handler_t, ca_type_t, chunk_t)
*/
enumerator_t* (*create_initiator_enumerator)(attribute_manager_t *this,
- identification_t *id, host_t *vip);
+ identification_t *id, linked_list_t *vips);
/**
* Register an attribute handler to the manager.
diff --git a/src/libhydra/attributes/attribute_provider.h b/src/libhydra/attributes/attribute_provider.h
index e4b4e13f3..adfd4a516 100644
--- a/src/libhydra/attributes/attribute_provider.h
+++ b/src/libhydra/attributes/attribute_provider.h
@@ -21,8 +21,9 @@
#ifndef ATTRIBUTE_PROVIDER_H_
#define ATTRIBUTE_PROVIDER_H_
-#include <utils/host.h>
+#include <networking/host.h>
#include <utils/identification.h>
+#include <collections/linked_list.h>
typedef struct attribute_provider_t attribute_provider_t;
@@ -34,35 +35,37 @@ struct attribute_provider_t {
/**
* Acquire a virtual IP address to assign to a peer.
*
- * @param pool name of the pool to acquire address from
+ * @param pools list of pool names (char*) to acquire from
* @param id peer ID
* @param requested IP in configuration request
* @return allocated address, NULL to serve none
*/
host_t* (*acquire_address)(attribute_provider_t *this,
- char *pool, identification_t *id,
+ linked_list_t *pools, identification_t *id,
host_t *requested);
/**
* Release a previously acquired address.
*
- * @param pool name of the pool this address was acquired from
+ * @param pools list of pool names (char*) to release to
* @param address address to release
* @param id peer ID
* @return TRUE if the address has been released by the provider
*/
bool (*release_address)(attribute_provider_t *this,
- char *pool, host_t *address, identification_t *id);
+ linked_list_t *pools, host_t *address,
+ identification_t *id);
/**
* Create an enumerator over attributes to hand out to a peer.
*
- * @param pool pool name to get attributes from
+ * @param pool list of pools names (char*) to query attributes from
* @param id peer ID
- * @param vip virtual IP to assign to peer, if any
+ * @param vip list of virtual IPs (host_t*) to assign to peer
* @return enumerator (configuration_attribute_type_t, chunk_t)
*/
enumerator_t* (*create_attribute_enumerator)(attribute_provider_t *this,
- char *pool, identification_t *id, host_t *vip);
+ linked_list_t *pools, identification_t *id,
+ linked_list_t *vips);
};
#endif /** ATTRIBUTE_PROVIDER_H_ @}*/
diff --git a/src/libhydra/attributes/attributes.h b/src/libhydra/attributes/attributes.h
index 8ff774b64..c3c37cfc4 100644
--- a/src/libhydra/attributes/attributes.h
+++ b/src/libhydra/attributes/attributes.h
@@ -24,7 +24,7 @@
typedef enum configuration_attribute_type_t configuration_attribute_type_t;
-#include <enum.h>
+#include <utils/enum.h>
/**
* Type of the attribute, as in IKEv2 RFC 3.15.1 or IKEv1 ModeConfig.
diff --git a/src/libhydra/attributes/mem_pool.c b/src/libhydra/attributes/mem_pool.c
index 8af97dc78..77567ce48 100644
--- a/src/libhydra/attributes/mem_pool.c
+++ b/src/libhydra/attributes/mem_pool.c
@@ -16,12 +16,14 @@
#include "mem_pool.h"
-#include <debug.h>
-#include <utils/hashtable.h>
-#include <utils/linked_list.h>
+#include <library.h>
+#include <hydra.h>
+#include <utils/debug.h>
+#include <collections/hashtable.h>
+#include <collections/array.h>
#include <threading/mutex.h>
-#define POOL_LIMIT (sizeof(uintptr_t)*8)
+#define POOL_LIMIT (sizeof(u_int)*8 - 1)
typedef struct private_mem_pool_t private_mem_pool_t;
@@ -63,6 +65,11 @@ struct private_mem_pool_t {
* lock to safely access the pool
*/
mutex_t *mutex;
+
+ /**
+ * Do we reassign online leases to the same identity, if requested?
+ */
+ bool reassign_online;
};
/**
@@ -71,13 +78,28 @@ struct private_mem_pool_t {
typedef struct {
/* identitiy reference */
identification_t *id;
- /* list of online leases, as offset */
- linked_list_t *online;
- /* list of offline leases, as offset */
- linked_list_t *offline;
+ /* array of online leases, as u_int offset */
+ array_t *online;
+ /* array of offline leases, as u_int offset */
+ array_t *offline;
} entry_t;
/**
+ * Create a new entry
+ */
+static entry_t* entry_create(identification_t *id)
+{
+ entry_t *entry;
+
+ INIT(entry,
+ .id = id->clone(id),
+ .online = array_create(sizeof(u_int), 0),
+ .offline = array_create(sizeof(u_int), 0),
+ );
+ return entry;
+}
+
+/**
* hashtable hash function for identities
*/
static u_int id_hash(identification_t *id)
@@ -162,6 +184,12 @@ METHOD(mem_pool_t, get_name, const char*,
return this->name;
}
+METHOD(mem_pool_t, get_base, host_t*,
+ private_mem_pool_t *this)
+{
+ return this->base;
+}
+
METHOD(mem_pool_t, get_size, u_int,
private_mem_pool_t *this)
{
@@ -179,7 +207,7 @@ METHOD(mem_pool_t, get_online, u_int,
enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
- count += entry->online->get_count(entry->online);
+ count += array_count(entry->online);
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
@@ -198,7 +226,7 @@ METHOD(mem_pool_t, get_offline, u_int,
enumerator = this->leases->create_enumerator(this->leases);
while (enumerator->enumerate(enumerator, NULL, &entry))
{
- count += entry->offline->get_count(entry->offline);
+ count += array_count(entry->offline);
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
@@ -206,99 +234,154 @@ METHOD(mem_pool_t, get_offline, u_int,
return count;
}
-METHOD(mem_pool_t, acquire_address, host_t*,
- private_mem_pool_t *this, identification_t *id, host_t *requested)
+/**
+ * Get an existing lease for id
+ */
+static int get_existing(private_mem_pool_t *this, identification_t *id,
+ host_t *requested)
{
- uintptr_t offset = 0, current;
enumerator_t *enumerator;
- entry_t *entry, *old;
+ u_int *current;
+ entry_t *entry;
+ int offset = 0;
- /* if the pool is empty (e.g. in the %config case) we simply return the
- * requested address */
- if (this->size == 0)
+ entry = this->leases->get(this->leases, id);
+ if (!entry)
{
- return requested->clone(requested);
+ return 0;
}
- if (!requested->is_anyaddr(requested) &&
- requested->get_family(requested) !=
- this->base->get_family(this->base))
+ /* check for a valid offline lease, refresh */
+ enumerator = array_create_enumerator(entry->offline);
+ if (enumerator->enumerate(enumerator, &current))
{
- DBG1(DBG_CFG, "IP pool address family mismatch");
- return NULL;
+ offset = *current;
+ array_insert(entry->online, ARRAY_TAIL, current);
+ array_remove_at(entry->offline, enumerator);
}
-
- this->mutex->lock(this->mutex);
- while (TRUE)
+ enumerator->destroy(enumerator);
+ if (offset)
{
- entry = this->leases->get(this->leases, id);
- if (entry)
+ DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
+ return offset;
+ }
+ if (!this->reassign_online)
+ {
+ return 0;
+ }
+ /* check for a valid online lease to reassign */
+ enumerator = array_create_enumerator(entry->online);
+ while (enumerator->enumerate(enumerator, &current))
+ {
+ if (*current == host2offset(this, requested))
{
- /* check for a valid offline lease, refresh */
- enumerator = entry->offline->create_enumerator(entry->offline);
- if (enumerator->enumerate(enumerator, &current))
- {
- entry->offline->remove_at(entry->offline, enumerator);
- entry->online->insert_last(entry->online, (void*)current);
- offset = current;
- }
- enumerator->destroy(enumerator);
- if (offset)
- {
- DBG1(DBG_CFG, "reassigning offline lease to '%Y'", id);
- break;
- }
- /* check for a valid online lease to reassign */
- enumerator = entry->online->create_enumerator(entry->online);
- while (enumerator->enumerate(enumerator, &current))
- {
- if (current == host2offset(this, requested))
- {
- offset = current;
- break;
- }
- }
- enumerator->destroy(enumerator);
- if (offset)
- {
- DBG1(DBG_CFG, "reassigning online lease to '%Y'", id);
- break;
- }
+ offset = *current;
+ /* add an additional "online" entry */
+ array_insert(entry->online, ARRAY_TAIL, current);
+ break;
}
- else
+ }
+ enumerator->destroy(enumerator);
+ if (offset)
+ {
+ DBG1(DBG_CFG, "reassigning online lease to '%Y'", id);
+ }
+ return offset;
+}
+
+/**
+ * Get a new lease for id
+ */
+static int get_new(private_mem_pool_t *this, identification_t *id)
+{
+ entry_t *entry;
+ u_int offset = 0;
+
+ if (this->unused < this->size)
+ {
+ entry = this->leases->get(this->leases, id);
+ if (!entry)
{
- INIT(entry,
- .id = id->clone(id),
- .online = linked_list_create(),
- .offline = linked_list_create(),
- );
+ entry = entry_create(id);
this->leases->put(this->leases, entry->id, entry);
}
- if (this->unused < this->size)
+ /* assigning offset, starting by 1 */
+ offset = ++this->unused;
+ array_insert(entry->online, ARRAY_TAIL, &offset);
+ DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
+ }
+ return offset;
+}
+
+/**
+ * Get a reassigned lease for id in case the pool is full
+ */
+static int get_reassigned(private_mem_pool_t *this, identification_t *id)
+{
+ enumerator_t *enumerator;
+ entry_t *entry;
+ u_int current, offset = 0;
+
+ enumerator = this->leases->create_enumerator(this->leases);
+ while (enumerator->enumerate(enumerator, NULL, &entry))
+ {
+ if (array_remove(entry->offline, ARRAY_HEAD, &current))
{
- /* assigning offset, starting by 1 */
- offset = ++this->unused;
- entry->online->insert_last(entry->online, (void*)offset);
- DBG1(DBG_CFG, "assigning new lease to '%Y'", id);
+ offset = current;
+ DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
+ " to '%Y'", entry->id, id);
break;
}
+ }
+ enumerator->destroy(enumerator);
- /* no more addresses, replace the first found offline lease */
- enumerator = this->leases->create_enumerator(this->leases);
- while (enumerator->enumerate(enumerator, NULL, &old))
- {
- if (old->offline->remove_first(old->offline,
- (void**)&current) == SUCCESS)
+ if (offset)
+ {
+ entry = entry_create(id);
+ array_insert(entry->online, ARRAY_TAIL, &offset);
+ this->leases->put(this->leases, entry->id, entry);
+ }
+ return offset;
+}
+
+METHOD(mem_pool_t, acquire_address, host_t*,
+ private_mem_pool_t *this, identification_t *id, host_t *requested,
+ mem_pool_op_t operation)
+{
+ int offset = 0;
+
+ /* 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);
+ }
+
+ if (requested->get_family(requested) !=
+ this->base->get_family(this->base))
+ {
+ return NULL;
+ }
+
+ this->mutex->lock(this->mutex);
+ switch (operation)
+ {
+ case MEM_POOL_EXISTING:
+ offset = get_existing(this, id, requested);
+ break;
+ case MEM_POOL_NEW:
+ offset = get_new(this, id);
+ break;
+ case MEM_POOL_REASSIGN:
+ offset = get_reassigned(this, id);
+ if (!offset)
{
- offset = current;
- entry->online->insert_last(entry->online, (void*)offset);
- DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
- " to '%Y'", old->id, id);
- break;
+ DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
+ this->name);
}
- }
- enumerator->destroy(enumerator);
- break;
+ break;
+ default:
+ break;
}
this->mutex->unlock(this->mutex);
@@ -306,20 +389,16 @@ METHOD(mem_pool_t, acquire_address, host_t*,
{
return offset2host(this, offset);
}
- else
- {
- DBG1(DBG_CFG, "pool '%s' is full, unable to assign address",
- this->name);
- }
return NULL;
}
METHOD(mem_pool_t, release_address, bool,
private_mem_pool_t *this, host_t *address, identification_t *id)
{
- bool found = FALSE;
+ enumerator_t *enumerator;
+ bool found = FALSE, more = FALSE;
entry_t *entry;
- uintptr_t offset;
+ u_int offset, *current;
if (this->size != 0)
{
@@ -328,11 +407,31 @@ METHOD(mem_pool_t, release_address, bool,
if (entry)
{
offset = host2offset(this, address);
- if (entry->online->remove(entry->online, (void*)offset, NULL) > 0)
+
+ enumerator = array_create_enumerator(entry->online);
+ while (enumerator->enumerate(enumerator, &current))
{
+ if (*current == offset)
+ {
+ if (!found)
+ { /* remove the first entry only */
+ array_remove_at(entry->online, enumerator);
+ found = TRUE;
+ }
+ else
+ { /* but check for more entries */
+ more = TRUE;
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ if (found && !more)
+ {
+ /* no tunnels are online anymore for this lease, make offline */
+ array_insert(entry->offline, ARRAY_TAIL, &offset);
DBG1(DBG_CFG, "lease %H by '%Y' went offline", address, id);
- entry->offline->insert_last(entry->offline, (void*)offset);
- found = TRUE;
}
}
this->mutex->unlock(this->mutex);
@@ -363,7 +462,7 @@ typedef struct {
METHOD(enumerator_t, lease_enumerate, bool,
lease_enumerator_t *this, identification_t **id, host_t **addr, bool *online)
{
- uintptr_t offset;
+ u_int *offset;
DESTROY_IF(this->addr);
this->addr = NULL;
@@ -372,17 +471,17 @@ METHOD(enumerator_t, lease_enumerate, bool,
{
if (this->entry)
{
- if (this->online->enumerate(this->online, (void**)&offset))
+ if (this->online->enumerate(this->online, &offset))
{
*id = this->entry->id;
- *addr = this->addr = offset2host(this->pool, offset);
+ *addr = this->addr = offset2host(this->pool, *offset);
*online = TRUE;
return TRUE;
}
- if (this->offline->enumerate(this->offline, (void**)&offset))
+ if (this->offline->enumerate(this->offline, &offset))
{
*id = this->entry->id;
- *addr = this->addr = offset2host(this->pool, offset);
+ *addr = this->addr = offset2host(this->pool, *offset);
*online = FALSE;
return TRUE;
}
@@ -394,10 +493,8 @@ METHOD(enumerator_t, lease_enumerate, bool,
{
return FALSE;
}
- this->online = this->entry->online->create_enumerator(
- this->entry->online);
- this->offline = this->entry->offline->create_enumerator(
- this->entry->offline);
+ this->online = array_create_enumerator(this->entry->online);
+ this->offline = array_create_enumerator(this->entry->offline);
}
}
@@ -439,8 +536,8 @@ METHOD(mem_pool_t, destroy, void,
while (enumerator->enumerate(enumerator, NULL, &entry))
{
entry->id->destroy(entry->id);
- entry->online->destroy(entry->online);
- entry->offline->destroy(entry->offline);
+ array_destroy(entry->online);
+ array_destroy(entry->offline);
free(entry);
}
enumerator->destroy(enumerator);
@@ -453,16 +550,16 @@ METHOD(mem_pool_t, destroy, void,
}
/**
- * Described in header
+ * Generic constructor
*/
-mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
+static private_mem_pool_t *create_generic(char *name)
{
private_mem_pool_t *this;
- int addr_bits;
INIT(this,
.public = {
.get_name = _get_name,
+ .get_base = _get_base,
.get_size = _get_size,
.get_online = _get_online,
.get_offline = _get_offline,
@@ -475,11 +572,26 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
.leases = hashtable_create((hashtable_hash_t)id_hash,
(hashtable_equals_t)id_equals, 16),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .reassign_online = lib->settings->get_bool(lib->settings,
+ "%s.mem-pool.reassign_online", FALSE, hydra->daemon),
);
+ return this;
+}
+
+/**
+ * Described in header
+ */
+mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
+{
+ private_mem_pool_t *this;
+ int addr_bits;
+
+ this = create_generic(name);
if (base)
{
addr_bits = base->get_family(base) == AF_INET ? 32 : 128;
+ bits = max(0, min(bits, base->get_family(base) == AF_INET ? 32 : 128));
/* net bits -> host bits */
bits = addr_bits - bits;
if (bits > POOL_LIMIT)
@@ -488,12 +600,12 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
DBG1(DBG_CFG, "virtual IP pool too large, limiting to %H/%d",
base, addr_bits - bits);
}
- this->size = 1 << (bits);
+ this->size = 1 << bits;
if (this->size > 2)
{ /* do not use first and last addresses of a block */
this->unused++;
- this->size--;
+ this->size -= 2;
}
this->base = base->clone(base);
}
@@ -501,3 +613,37 @@ mem_pool_t *mem_pool_create(char *name, host_t *base, int bits)
return &this->public;
}
+/**
+ * Described in header
+ */
+mem_pool_t *mem_pool_create_range(char *name, host_t *from, host_t *to)
+{
+ private_mem_pool_t *this;
+ chunk_t fromaddr, toaddr;
+ u_int32_t diff;
+
+ fromaddr = from->get_address(from);
+ toaddr = to->get_address(to);
+
+ if (from->get_family(from) != to->get_family(to) ||
+ fromaddr.len != toaddr.len || fromaddr.len < sizeof(diff) ||
+ memcmp(fromaddr.ptr, toaddr.ptr, toaddr.len) > 0)
+ {
+ DBG1(DBG_CFG, "invalid IP address range: %H-%H", from, to);
+ return NULL;
+ }
+ if (fromaddr.len > sizeof(diff) &&
+ !chunk_equals(chunk_create(fromaddr.ptr, fromaddr.len - sizeof(diff)),
+ chunk_create(toaddr.ptr, toaddr.len - sizeof(diff))))
+ {
+ DBG1(DBG_CFG, "IP address range too large: %H-%H", from, to);
+ return NULL;
+ }
+ this = create_generic(name);
+ this->base = from->clone(from);
+ diff = untoh32(toaddr.ptr + toaddr.len - sizeof(diff)) -
+ untoh32(fromaddr.ptr + fromaddr.len - sizeof(diff));
+ this->size = diff + 1;
+
+ return &this->public;
+}
diff --git a/src/libhydra/attributes/mem_pool.h b/src/libhydra/attributes/mem_pool.h
index bb963de93..7347bb547 100644
--- a/src/libhydra/attributes/mem_pool.h
+++ b/src/libhydra/attributes/mem_pool.h
@@ -22,11 +22,24 @@
#define MEM_POOL_H
typedef struct mem_pool_t mem_pool_t;
+typedef enum mem_pool_op_t mem_pool_op_t;
-#include <utils/host.h>
+#include <networking/host.h>
#include <utils/identification.h>
/**
+ * In-memory IP pool acquire operation.
+ */
+enum mem_pool_op_t {
+ /** Check for an exsiting lease */
+ MEM_POOL_EXISTING,
+ /** Get a new lease */
+ MEM_POOL_NEW,
+ /** Replace an existing offline lease of another ID */
+ MEM_POOL_REASSIGN,
+};
+
+/**
* An in-memory IP address pool.
*/
struct mem_pool_t {
@@ -39,6 +52,13 @@ struct mem_pool_t {
const char* (*get_name)(mem_pool_t *this);
/**
+ * Get the base (first) address of this pool.
+ *
+ * @return base address, internal host
+ */
+ host_t* (*get_base)(mem_pool_t *this);
+
+ /**
* Get the size (i.e. number of addresses) of this pool.
*
* @return the size of this pool
@@ -62,12 +82,18 @@ struct mem_pool_t {
/**
* Acquire an address for the given id from this pool.
*
+ * This call is usually invoked several times: The first time to find an
+ * existing lease (MEM_POOL_EXISTING), if none found a second time to
+ * acquire a new lease (MEM_POOL_NEW), and if the pool is full once again
+ * to assign an existing offline lease (MEM_POOL_REASSIGN).
+ *
* @param id the id to acquire an address for
* @param requested acquire this address, if possible
+ * @param operation acquire operation to perform, see above
* @return the acquired address
*/
host_t* (*acquire_address)(mem_pool_t *this, identification_t *id,
- host_t *requested);
+ host_t *requested, mem_pool_op_t operation);
/**
* Release a previously acquired address.
@@ -102,9 +128,19 @@ struct mem_pool_t {
*
* @param name name of this pool
* @param base base address of this pool, NULL to create an empty pool
- * @param bits net mask
+ * @param bits number of non-network bits in base, as in CIDR notation
+ * @return memory pool instance
*/
mem_pool_t *mem_pool_create(char *name, host_t *base, int bits);
-#endif /** MEM_POOL_H_ @} */
+/**
+ * Create an in-memory IP address from a range.
+ *
+ * @param name name of this pool
+ * @param from start of ranged pool
+ * @param to end of ranged pool
+ * @return memory pool instance, NULL if range invalid
+ */
+mem_pool_t *mem_pool_create_range(char *name, host_t *from, host_t *to);
+#endif /** MEM_POOL_H_ @} */