Check for an existing lease in all stroke pools before creating a new one
authorMartin Willi <martin@revosec.ch>
Tue, 11 Sep 2012 09:33:42 +0000 (11:33 +0200)
committerMartin Willi <martin@revosec.ch>
Tue, 11 Sep 2012 14:18:28 +0000 (16:18 +0200)
src/libcharon/plugins/stroke/stroke_attribute.c
src/libhydra/attributes/mem_pool.c
src/libhydra/attributes/mem_pool.h

index e0c8360..85fb94e 100644 (file)
@@ -89,35 +89,59 @@ static mem_pool_t *find_pool(private_stroke_attribute_t *this, char *name)
        return found;
 }
 
-METHOD(attribute_provider_t, acquire_address, host_t*,
-       private_stroke_attribute_t *this, linked_list_t *pools, identification_t *id,
-       host_t *requested)
+/**
+ * Find an existing or not yet existing lease
+ */
+static host_t *find_addr(private_stroke_attribute_t *this, linked_list_t *pools,
+                                                identification_t *id, host_t *requested,
+                                                mem_pool_op_t operation)
 {
+       host_t *addr = NULL;
        enumerator_t *enumerator;
        mem_pool_t *pool;
-       host_t *addr = NULL;
        char *name;
 
        enumerator = pools->create_enumerator(pools);
-       this->lock->read_lock(this->lock);
        while (enumerator->enumerate(enumerator, &name))
        {
                pool = find_pool(this, name);
                if (pool)
                {
-                       addr = pool->acquire_address(pool, id, requested);
+                       addr = pool->acquire_address(pool, id, requested, operation);
                        if (addr)
                        {
                                break;
                        }
                }
        }
-       this->lock->unlock(this->lock);
        enumerator->destroy(enumerator);
 
        return addr;
 }
 
+METHOD(attribute_provider_t, acquire_address, host_t*,
+       private_stroke_attribute_t *this, linked_list_t *pools, identification_t *id,
+       host_t *requested)
+{
+       host_t *addr;
+
+       this->lock->read_lock(this->lock);
+
+       addr = find_addr(this, pools, id, requested, MEM_POOL_EXISTING);
+       if (!addr)
+       {
+               addr = find_addr(this, pools, id, requested, MEM_POOL_NEW);
+               if (!addr)
+               {
+                       addr = find_addr(this, pools, id, requested, MEM_POOL_REASSIGN);
+               }
+       }
+
+       this->lock->unlock(this->lock);
+
+       return addr;
+}
+
 METHOD(attribute_provider_t, release_address, bool,
        private_stroke_attribute_t *this, linked_list_t *pools, host_t *address,
        identification_t *id)
index 39159bf..1c42031 100644 (file)
@@ -212,12 +212,123 @@ 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)
+{
+       enumerator_t *enumerator;
+       uintptr_t current;
+       entry_t *entry;
+       int offset = 0;
+
+       entry = this->leases->get(this->leases, id);
+       if (!entry)
+       {
+               return 0;
+       }
+
+       /* 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);
+               return offset;
+       }
+
+       /* 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);
+       }
+       return offset;
+}
+
+/**
+ * Get a new lease for id
+ */
+static int get_new(private_mem_pool_t *this, identification_t *id)
+{
+       entry_t *entry;
+       int offset = 0;
+
+       if (this->unused < this->size)
+       {
+               INIT(entry,
+                       .id = id->clone(id),
+                       .online = linked_list_create(),
+                       .offline = linked_list_create(),
+               );
+               this->leases->put(this->leases, entry->id, entry);
+
+               /* 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);
+       }
+       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)
 {
-       uintptr_t offset = 0, current;
        enumerator_t *enumerator;
-       entry_t *entry, *old;
+       entry_t *entry;
+       uintptr_t current;
+       int offset = 0;
+
+       enumerator = this->leases->create_enumerator(this->leases);
+       while (enumerator->enumerate(enumerator, NULL, &entry))
+       {
+               if (entry->offline->remove_first(entry->offline,
+                                                                                (void**)&current) == SUCCESS)
+               {
+                       offset = current;
+                       DBG1(DBG_CFG, "reassigning existing offline lease by '%Y'"
+                                " to '%Y'", entry->id, id);
+                       break;
+               }
+       }
+       enumerator->destroy(enumerator);
+
+       if (offset)
+       {
+               INIT(entry,
+                       .id = id->clone(id),
+                       .online = linked_list_create(),
+                       .offline = linked_list_create(),
+               );
+               entry->online->insert_last(entry->online, (void*)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 */
@@ -233,76 +344,24 @@ METHOD(mem_pool_t, acquire_address, host_t*,
        }
 
        this->mutex->lock(this->mutex);
-       while (TRUE)
+       switch (operation)
        {
-               entry = this->leases->get(this->leases, id);
-               if (entry)
-               {
-                       /* 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;
-                       }
-               }
-               else
-               {
-                       INIT(entry,
-                               .id = id->clone(id),
-                               .online = linked_list_create(),
-                               .offline = linked_list_create(),
-                       );
-                       this->leases->put(this->leases, entry->id, entry);
-               }
-               if (this->unused < this->size)
-               {
-                       /* 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);
+               case MEM_POOL_EXISTING:
+                       offset = get_existing(this, id, requested);
                        break;
-               }
-
-               /* 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)
+               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);
 
@@ -310,11 +369,6 @@ 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;
 }
 
index 7b7e58a..fa4e648 100644 (file)
 #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 <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 {
@@ -69,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 existing      TRUE to look for an existing lease, FALSE for a new one
         * @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.