Pass the full list of pools to acquire_address, enumerate in providers

If the provider has access to the full pool list, it can enumerate
them twice, for example to search for existing leases first, and
only search for new leases in a second step.

Fixes lease enumeration in attr-sql using multiple pools.
This commit is contained in:
Martin Willi
2012-09-11 16:18:28 +02:00
parent dc7b79d8a5
commit 594c58e111
10 changed files with 109 additions and 73 deletions
+20 -8
View File
@@ -81,18 +81,29 @@ static uintptr_t hash_transaction(dhcp_transaction_t *transaction)
} }
METHOD(attribute_provider_t, acquire_address, host_t*, METHOD(attribute_provider_t, acquire_address, host_t*,
private_dhcp_provider_t *this, char *pool, private_dhcp_provider_t *this, linked_list_t *pools,
identification_t *id, host_t *requested) identification_t *id, host_t *requested)
{ {
if (streq(pool, "dhcp") && requested->get_family(requested) == AF_INET) dhcp_transaction_t *transaction, *old;
{ enumerator_t *enumerator;
dhcp_transaction_t *transaction, *old; char *pool;
host_t *vip; host_t *vip = NULL;
if (requested->get_family(requested) != AF_INET)
{
return NULL;
}
enumerator = pools->create_enumerator(pools);
while (enumerator->enumerate(enumerator, &pool))
{
if (!streq(pool, "dhcp"))
{
continue;
}
transaction = this->socket->enroll(this->socket, id); transaction = this->socket->enroll(this->socket, id);
if (!transaction) if (!transaction)
{ {
return NULL; continue;
} }
vip = transaction->get_address(transaction); vip = transaction->get_address(transaction);
vip = vip->clone(vip); vip = vip->clone(vip);
@@ -101,9 +112,10 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
(void*)hash_transaction(transaction), transaction); (void*)hash_transaction(transaction), transaction);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
DESTROY_IF(old); DESTROY_IF(old);
return vip; break;
} }
return NULL; enumerator->destroy(enumerator);
return vip;
} }
METHOD(attribute_provider_t, release_address, bool, METHOD(attribute_provider_t, release_address, bool,
+13 -5
View File
@@ -170,22 +170,28 @@ static bool responsible_for(private_ha_attribute_t *this, int bit)
} }
METHOD(attribute_provider_t, acquire_address, host_t*, METHOD(attribute_provider_t, acquire_address, host_t*,
private_ha_attribute_t *this, char *name, identification_t *id, private_ha_attribute_t *this, linked_list_t *pools, identification_t *id,
host_t *requested) host_t *requested)
{ {
enumerator_t *enumerator;
pool_t *pool; pool_t *pool;
int offset = -1, byte, bit; int offset = -1, byte, bit;
host_t *address; host_t *address;
char *name;
enumerator = pools->create_enumerator(pools);
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
pool = get_pool(this, name); while (enumerator->enumerate(enumerator, &name))
if (pool)
{ {
pool = get_pool(this, name);
if (!pool)
{
continue;
}
if (pool->base->get_family(pool->base) != if (pool->base->get_family(pool->base) !=
requested->get_family(requested)) requested->get_family(requested))
{ {
this->mutex->unlock(this->mutex); continue;
return NULL;
} }
for (byte = 0; byte < pool->size / 8; byte++) for (byte = 0; byte < pool->size / 8; byte++)
{ {
@@ -214,6 +220,8 @@ METHOD(attribute_provider_t, acquire_address, host_t*,
} }
} }
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
enumerator->destroy(enumerator);
if (offset != -1) if (offset != -1)
{ {
address = offset2host(pool, offset); address = offset2host(pool, offset);
@@ -90,19 +90,31 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
} }
METHOD(attribute_provider_t, acquire_address, host_t*, METHOD(attribute_provider_t, acquire_address, host_t*,
private_stroke_attribute_t *this, char *name, identification_t *id, private_stroke_attribute_t *this, linked_list_t *pools, identification_t *id,
host_t *requested) host_t *requested)
{ {
enumerator_t *enumerator;
mem_pool_t *pool; mem_pool_t *pool;
host_t *addr = NULL; host_t *addr = NULL;
char *name;
enumerator = pools->create_enumerator(pools);
this->lock->read_lock(this->lock); this->lock->read_lock(this->lock);
pool = find_pool(this, name); while (enumerator->enumerate(enumerator, &name))
if (pool)
{ {
addr = pool->acquire_address(pool, id, requested); pool = find_pool(this, name);
if (pool)
{
addr = pool->acquire_address(pool, id, requested);
if (addr)
{
break;
}
}
} }
this->lock->unlock(this->lock); this->lock->unlock(this->lock);
enumerator->destroy(enumerator);
return addr; return addr;
} }
@@ -27,6 +27,7 @@ static void* testing(void *thread)
int i; int i;
host_t *addr[ALLOCS]; host_t *addr[ALLOCS];
identification_t *id[ALLOCS]; identification_t *id[ALLOCS];
linked_list_t *pools;
/* prepare identities */ /* prepare identities */
for (i = 0; i < ALLOCS; i++) for (i = 0; i < ALLOCS; i++)
@@ -37,17 +38,23 @@ static void* testing(void *thread)
id[i] = identification_create_from_string(buf); id[i] = identification_create_from_string(buf);
} }
pools = linked_list_create();
pools->insert_last(pools, "test");
/* allocate addresses */ /* allocate addresses */
for (i = 0; i < ALLOCS; i++) for (i = 0; i < ALLOCS; i++)
{ {
addr[i] = hydra->attributes->acquire_address(hydra->attributes, addr[i] = hydra->attributes->acquire_address(hydra->attributes,
"test", id[i], NULL); pools, id[i], NULL);
if (!addr[i]) if (!addr[i])
{ {
pools->destroy(pools);
return (void*)FALSE; return (void*)FALSE;
} }
} }
pools->destroy(pools);
/* release addresses */ /* release addresses */
for (i = 0; i < ALLOCS; i++) for (i = 0; i < ALLOCS; i++)
{ {
+6 -20
View File
@@ -330,29 +330,23 @@ METHOD(task_t, build_r, status_t,
id = this->ike_sa->get_other_eap_id(this->ike_sa); id = this->ike_sa->get_other_eap_id(this->ike_sa);
config = this->ike_sa->get_peer_cfg(this->ike_sa); config = this->ike_sa->get_peer_cfg(this->ike_sa);
vips = linked_list_create(); vips = linked_list_create();
pools = linked_list_create(); pools = linked_list_create_from_enumerator(
config->create_pool_enumerator(config));
this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE); this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
enumerator = this->vips->create_enumerator(this->vips); enumerator = this->vips->create_enumerator(this->vips);
while (enumerator->enumerate(enumerator, &requested)) while (enumerator->enumerate(enumerator, &requested))
{ {
enumerator_t *poolenum;
char *pool;
host_t *found = NULL; host_t *found = NULL;
/* query all pools until we get an address */ /* query all pools until we get an address */
DBG1(DBG_IKE, "peer requested virtual IP %H", requested); DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
poolenum = config->create_pool_enumerator(config); found = hydra->attributes->acquire_address(hydra->attributes,
while (poolenum->enumerate(poolenum, &pool)) pools, id, requested);
if (found)
{ {
found = hydra->attributes->acquire_address(hydra->attributes,
pool, id, requested);
if (!found)
{
continue;
}
DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id); DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found); this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
if (!cp) if (!cp)
@@ -360,17 +354,9 @@ METHOD(task_t, build_r, status_t,
cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY);
} }
cp->add_attribute(cp, build_vip(found)); cp->add_attribute(cp, build_vip(found));
/* use pool to request other attributes */
if (pools->find_first(pools, NULL, (void**)&pool) == NOT_FOUND)
{
pools->insert_last(pools, pool);
}
vips->insert_last(vips, found); vips->insert_last(vips, found);
break;
} }
poolenum->destroy(poolenum); else
if (!found)
{ {
DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'", DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
requested, id); requested, id);
+6 -20
View File
@@ -342,29 +342,23 @@ METHOD(task_t, build_r, status_t,
id = this->ike_sa->get_other_eap_id(this->ike_sa); id = this->ike_sa->get_other_eap_id(this->ike_sa);
config = this->ike_sa->get_peer_cfg(this->ike_sa); config = this->ike_sa->get_peer_cfg(this->ike_sa);
vips = linked_list_create(); vips = linked_list_create();
pools = linked_list_create(); pools = linked_list_create_from_enumerator(
config->create_pool_enumerator(config));
this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE); this->ike_sa->clear_virtual_ips(this->ike_sa, FALSE);
enumerator = this->vips->create_enumerator(this->vips); enumerator = this->vips->create_enumerator(this->vips);
while (enumerator->enumerate(enumerator, &requested)) while (enumerator->enumerate(enumerator, &requested))
{ {
enumerator_t *poolenum;
char *pool;
host_t *found = NULL; host_t *found = NULL;
/* query all pools until we get an address */ /* query all pools until we get an address */
DBG1(DBG_IKE, "peer requested virtual IP %H", requested); DBG1(DBG_IKE, "peer requested virtual IP %H", requested);
poolenum = config->create_pool_enumerator(config); found = hydra->attributes->acquire_address(hydra->attributes,
while (poolenum->enumerate(poolenum, &pool)) pools, id, requested);
if (found)
{ {
found = hydra->attributes->acquire_address(hydra->attributes,
pool, id, requested);
if (!found)
{
continue;
}
DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id); DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", found, id);
this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found); this->ike_sa->add_virtual_ip(this->ike_sa, FALSE, found);
if (!cp) if (!cp)
@@ -372,17 +366,9 @@ METHOD(task_t, build_r, status_t,
cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY); cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY);
} }
cp->add_attribute(cp, build_vip(found)); cp->add_attribute(cp, build_vip(found));
/* use pool to request other attributes */
if (pools->find_first(pools, NULL, (void**)&pool) == NOT_FOUND)
{
pools->insert_last(pools, pool);
}
vips->insert_last(vips, found); vips->insert_last(vips, found);
break;
} }
poolenum->destroy(poolenum); else
if (!found)
{ {
DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'", DBG1(DBG_IKE, "no virtual IP found for %H requested by '%Y'",
requested, id); requested, id);
+3 -3
View File
@@ -60,8 +60,8 @@ typedef struct {
} enum_data_t; } enum_data_t;
METHOD(attribute_manager_t, acquire_address, host_t*, METHOD(attribute_manager_t, acquire_address, host_t*,
private_attribute_manager_t *this, char *pool, identification_t *id, private_attribute_manager_t *this, linked_list_t *pools,
host_t *requested) identification_t *id, host_t *requested)
{ {
enumerator_t *enumerator; enumerator_t *enumerator;
attribute_provider_t *current; attribute_provider_t *current;
@@ -71,7 +71,7 @@ METHOD(attribute_manager_t, acquire_address, host_t*,
enumerator = this->providers->create_enumerator(this->providers); enumerator = this->providers->create_enumerator(this->providers);
while (enumerator->enumerate(enumerator, &current)) while (enumerator->enumerate(enumerator, &current))
{ {
host = current->acquire_address(current, pool, id, requested); host = current->acquire_address(current, pools, id, requested);
if (host) if (host)
{ {
break; break;
+2 -2
View File
@@ -39,13 +39,13 @@ struct attribute_manager_t {
/** /**
* Acquire a virtual IP address to assign to a peer. * 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 id peer identity to get address forua
* @param requested IP in configuration request * @param requested IP in configuration request
* @return allocated address, NULL to serve none * @return allocated address, NULL to serve none
*/ */
host_t* (*acquire_address)(attribute_manager_t *this, host_t* (*acquire_address)(attribute_manager_t *this,
char *pool, identification_t *id, linked_list_t *pool, identification_t *id,
host_t *requested); host_t *requested);
/** /**
+2 -2
View File
@@ -35,13 +35,13 @@ struct attribute_provider_t {
/** /**
* Acquire a virtual IP address to assign to a peer. * 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 id peer ID
* @param requested IP in configuration request * @param requested IP in configuration request
* @return allocated address, NULL to serve none * @return allocated address, NULL to serve none
*/ */
host_t* (*acquire_address)(attribute_provider_t *this, host_t* (*acquire_address)(attribute_provider_t *this,
char *pool, identification_t *id, linked_list_t *pools, identification_t *id,
host_t *requested); host_t *requested);
/** /**
* Release a previously acquired address. * Release a previously acquired address.
+33 -8
View File
@@ -233,26 +233,51 @@ static host_t* get_lease(private_sql_attribute_t *this, char *name,
} }
METHOD(attribute_provider_t, acquire_address, host_t*, METHOD(attribute_provider_t, acquire_address, host_t*,
private_sql_attribute_t *this, char *name, identification_t *id, private_sql_attribute_t *this, linked_list_t *pools, identification_t *id,
host_t *requested) host_t *requested)
{ {
enumerator_t *enumerator;
host_t *address = NULL; host_t *address = NULL;
u_int identity, pool, timeout; u_int identity, pool, timeout;
char *name;
identity = get_identity(this, id); identity = get_identity(this, id);
if (identity) if (identity)
{ {
pool = get_pool(this, name, &timeout); /* check for an existing lease in all pools */
if (pool) enumerator = pools->create_enumerator(pools);
while (enumerator->enumerate(enumerator, &name))
{ {
/* check for an existing lease */ pool = get_pool(this, name, &timeout);
address = check_lease(this, name, pool, identity); if (pool)
if (address == NULL)
{ {
/* get an unallocated address or expired lease */ address = check_lease(this, name, pool, identity);
address = get_lease(this, name, pool, timeout, identity); if (address)
{
break;
}
} }
} }
enumerator->destroy(enumerator);
if (!address)
{
/* get an unallocated address or expired lease */
enumerator = pools->create_enumerator(pools);
while (enumerator->enumerate(enumerator, &name))
{
pool = get_pool(this, name, &timeout);
if (pool)
{
address = get_lease(this, name, pool, timeout, identity);
if (address)
{
break;
}
}
}
enumerator->destroy(enumerator);
}
} }
return address; return address;
} }