diff options
Diffstat (limited to 'src/libhydra/attributes')
-rw-r--r-- | src/libhydra/attributes/attribute_handler.h | 8 | ||||
-rw-r--r-- | src/libhydra/attributes/attribute_manager.c | 79 | ||||
-rw-r--r-- | src/libhydra/attributes/attribute_manager.h | 23 | ||||
-rw-r--r-- | src/libhydra/attributes/attribute_provider.h | 19 | ||||
-rw-r--r-- | src/libhydra/attributes/attributes.h | 2 | ||||
-rw-r--r-- | src/libhydra/attributes/mem_pool.c | 364 | ||||
-rw-r--r-- | src/libhydra/attributes/mem_pool.h | 44 |
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, ¤t)) { - 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, ¤t)) { - 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, ¤t)) { - 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, ¤t)) + { + if (*current == host2offset(this, requested)) { - /* check for a valid offline lease, refresh */ - enumerator = entry->offline->create_enumerator(entry->offline); - if (enumerator->enumerate(enumerator, ¤t)) - { - 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, ¤t)) - { - 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, ¤t)) { - /* 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**)¤t) == 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, ¤t)) { + 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_ @} */ |