Changeset 4681

Show
Ignore:
Timestamp:
11/20/08 14:30:23 (2 months ago)
Author:
tobias
Message:

optimized ike_sa_manager for concurrent access (default behavior is still as before, needs configuration in strongswan.conf).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/src/charon/sa/ike_sa_manager.c

    r4579 r4681  
    2828#include <crypto/hashers/hasher.h> 
    2929 
     30/* the default size of the hash table (MUST be a power of 2) */ 
     31#define DEFAULT_HASHTABLE_SIZE 1 
     32 
     33/* the maximum size of the hash table (MUST be a power of 2) */ 
     34#define MAX_HASHTABLE_SIZE (1 << 30) 
     35 
     36/* the default number of segments (MUST be a power of 2) */ 
     37#define DEFAULT_SEGMENT_COUNT 1 
     38 
    3039typedef struct entry_t entry_t; 
    3140 
     
    6170     
    6271    /** 
    63      * Identifiaction of an IKE_SA (SPIs). 
     72     * Identification of an IKE_SA (SPIs). 
    6473     */ 
    6574    ike_sa_id_t *ike_sa_id; 
     
    142151} 
    143152 
     153/** 
     154 * Function that matches entry_t objects by initiator SPI and the hash of the 
     155 * IKE_SA_INIT message. 
     156 */ 
     157static bool entry_match_by_hash(entry_t *entry, ike_sa_id_t *id, chunk_t *hash) 
     158{ 
     159    return id->get_responder_spi(id) == 0 && 
     160        id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id) && 
     161        id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id) && 
     162        chunk_equals(*hash, entry->init_hash); 
     163} 
     164 
     165/** 
     166 * Function that matches entry_t objects by ike_sa_id_t. 
     167 */ 
     168static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id) 
     169{ 
     170    if (id->equals(id, entry->ike_sa_id)) 
     171    { 
     172        return TRUE; 
     173    }    
     174    if (entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0 && 
     175        id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id) && 
     176        id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id)) 
     177    { 
     178        /* this is TRUE for IKE_SAs that we initiated but have not yet received a response */ 
     179        return TRUE; 
     180    } 
     181    return FALSE; 
     182} 
     183 
     184/** 
     185 * Function that matches entry_t objects by ike_sa_t pointers. 
     186 */ 
     187static bool entry_match_by_sa(entry_t *entry, ike_sa_t *ike_sa) 
     188{ 
     189    return entry->ike_sa == ike_sa; 
     190} 
     191 
     192/** 
     193 * Hash function for ike_sa_id_t objects. 
     194 */ 
     195static u_int ike_sa_id_hash(ike_sa_id_t *ike_sa_id) 
     196{ 
     197    /* we always use initiator spi as key */ 
     198    return ike_sa_id->get_initiator_spi(ike_sa_id); 
     199} 
     200 
     201typedef struct segment_t segment_t; 
     202 
     203/** 
     204 * Struct to manage segments of the hash table. 
     205 */ 
     206struct segment_t { 
     207    /* mutex to access a segment exclusively */ 
     208    mutex_t *mutex; 
     209     
     210    /* the number of items in this segment */ 
     211    u_int count; 
     212}; 
    144213 
    145214typedef struct private_ike_sa_manager_t private_ike_sa_manager_t; 
     
    155224     
    156225     /** 
    157       * Lock for exclusivly accessing the manager
     226      * Hash table with entries for the ike_sa_t objects
    158227      */ 
    159      mutex_t *mutex
    160  
     228     linked_list_t **ike_sa_table
     229      
    161230     /** 
    162       * Linked list with entries for the ike_sa_t objects
     231      * The size of the hash table
    163232      */ 
    164      linked_list_t *ike_sa_list; 
     233     u_int table_size; 
     234      
     235     /** 
     236      * Mask to map the hashes to table rows. 
     237      */ 
     238     u_int table_mask; 
     239      
     240     /** 
     241      * Segments of the hash table. 
     242      */ 
     243     segment_t *segments; 
     244      
     245     /** 
     246      * The number of segments. 
     247      */ 
     248     u_int segment_count; 
     249      
     250     /** 
     251      * Mask to map a table row to a segment. 
     252      */ 
     253     u_int segment_mask; 
    165254      
    166255     /** 
     
    180269}; 
    181270 
    182 /** 
    183  * Implementation of private_ike_sa_manager_t.get_entry_by_id. 
     271 
     272/** 
     273 * Acquire a lock to access the segment of the table row with the given index. 
     274 * It also works with the segment index directly. 
     275 */ 
     276static void lock_single_segment(private_ike_sa_manager_t *this, u_int index) 
     277
     278    mutex_t *lock = this->segments[index & this->segment_mask].mutex; 
     279    lock->lock(lock); 
     280
     281 
     282/** 
     283 * Release the lock required to access the segment of the table row with the given index. 
     284 * It also works with the segment index directly. 
     285 */ 
     286static void unlock_single_segment(private_ike_sa_manager_t *this, u_int index) 
     287
     288    mutex_t *lock = this->segments[index & this->segment_mask].mutex; 
     289    lock->unlock(lock); 
     290
     291 
     292/** 
     293 * Lock all segments 
     294 */ 
     295static void lock_all_segments(private_ike_sa_manager_t *this) 
     296
     297    u_int i; 
     298    for (i = 0; i < this->segment_count; ++i) 
     299    { 
     300        this->segments[i].mutex->lock(this->segments[i].mutex); 
     301    } 
     302
     303 
     304/** 
     305 * Unlock all segments 
     306 */ 
     307static void unlock_all_segments(private_ike_sa_manager_t *this) 
     308
     309    u_int i; 
     310    for (i = 0; i < this->segment_count; ++i) 
     311    { 
     312        this->segments[i].mutex->unlock(this->segments[i].mutex); 
     313    } 
     314
     315 
     316typedef struct private_enumerator_t private_enumerator_t; 
     317 
     318/** 
     319 * hash table enumerator implementation 
     320 */ 
     321struct private_enumerator_t { 
     322 
     323    /** 
     324     * implements enumerator interface 
     325     */ 
     326    enumerator_t enumerator; 
     327     
     328    /** 
     329     * associated ike_sa_manager_t 
     330     */ 
     331    private_ike_sa_manager_t *manager; 
     332     
     333    /** 
     334     * current segment index 
     335     */ 
     336    u_int segment; 
     337     
     338    /** 
     339     * current table row index 
     340     */ 
     341    u_int row; 
     342     
     343    /** 
     344     * enumerator for the current table row 
     345     */ 
     346    enumerator_t *current; 
     347}; 
     348 
     349/** 
     350 * Implementation of private_enumerator_t.enumerator.enumerate. 
     351 */ 
     352static bool enumerate(private_enumerator_t *this, entry_t **entry, u_int *segment) 
     353
     354    while (this->segment < this->manager->segment_count) 
     355    { 
     356        while (this->row < this->manager->table_size) 
     357        { 
     358            if (this->current) 
     359            { 
     360                entry_t *item; 
     361                if (this->current->enumerate(this->current, (void**)&item)) 
     362                { 
     363                    *entry = item; 
     364                    *segment = this->segment; 
     365                    return TRUE; 
     366                } 
     367                this->current->destroy(this->current); 
     368                this->current = NULL; 
     369                unlock_single_segment(this->manager, this->segment); 
     370            } 
     371            else 
     372            { 
     373                linked_list_t *list; 
     374                lock_single_segment(this->manager, this->segment); 
     375                if ((list = this->manager->ike_sa_table[this->row]) != NULL && 
     376                     list->get_count(list)) 
     377                { 
     378                    this->current = list->create_enumerator(list); 
     379                    continue; 
     380                } 
     381                unlock_single_segment(this->manager, this->segment); 
     382            } 
     383            this->row += this->manager->segment_count; 
     384        } 
     385        this->segment++; 
     386        this->row = this->segment; 
     387    } 
     388    return FALSE; 
     389
     390 
     391/** 
     392 * Implementation of private_enumerator_t.enumerator.destroy. 
     393 */ 
     394static void enumerator_destroy(private_enumerator_t *this) 
     395
     396    if (this->current) 
     397    { 
     398        this->current->destroy(this->current); 
     399        unlock_single_segment(this->manager, this->segment); 
     400    } 
     401    free(this); 
     402
     403 
     404/** 
     405 * Creates an enumerator to enumerate the entries in the hash table. 
     406 */ 
     407static enumerator_t* create_table_enumerator(private_ike_sa_manager_t *this) 
     408
     409    private_enumerator_t *enumerator = malloc_thing(private_enumerator_t); 
     410     
     411    enumerator->enumerator.enumerate = (void*)enumerate; 
     412    enumerator->enumerator.destroy = (void*)enumerator_destroy; 
     413    enumerator->manager = this; 
     414    enumerator->segment = 0; 
     415    enumerator->row = 0; 
     416    enumerator->current = NULL; 
     417     
     418    return &enumerator->enumerator; 
     419
     420 
     421/** 
     422 * Put an entry into the hash table. 
     423 * Note: The caller has to unlock the returned segment. 
     424 */ 
     425static u_int put_entry(private_ike_sa_manager_t *this, entry_t *entry) 
     426
     427    linked_list_t *list; 
     428    u_int row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; 
     429    u_int segment = row & this->segment_mask; 
     430     
     431    lock_single_segment(this, segment); 
     432    if ((list = this->ike_sa_table[row]) == NULL) 
     433    { 
     434        list = this->ike_sa_table[row] = linked_list_create(); 
     435    } 
     436    list->insert_last(list, entry); 
     437    this->segments[segment].count++; 
     438    return segment; 
     439
     440 
     441/** 
     442 * Remove an entry from the hash table. 
     443 * Note: The caller MUST have a lock on the segment of this entry. 
     444 */ 
     445static void remove_entry(private_ike_sa_manager_t *this, entry_t *entry) 
     446
     447    linked_list_t *list; 
     448    u_int row = ike_sa_id_hash(entry->ike_sa_id) & this->table_mask; 
     449    u_int segment = row & this->segment_mask; 
     450     
     451    if ((list = this->ike_sa_table[row]) != NULL) 
     452    { 
     453        entry_t *current; 
     454        enumerator_t *enumerator = list->create_enumerator(list); 
     455        while (enumerator->enumerate(enumerator, &current)) 
     456        { 
     457            if (current == entry) 
     458            { 
     459                list->remove_at(list, enumerator); 
     460                this->segments[segment].count--; 
     461                break; 
     462            } 
     463        } 
     464        enumerator->destroy(enumerator); 
     465    } 
     466
     467 
     468/** 
     469 * Remove the entry at the current enumerator position. 
     470 */ 
     471static void remove_entry_at(private_enumerator_t *this) 
     472
     473    if (this->current) 
     474    { 
     475        linked_list_t *list = this->manager->ike_sa_table[this->row]; 
     476        list->remove_at(list, this->current); 
     477        this->manager->segments[this->segment].count--; 
     478    } 
     479
     480 
     481/** 
     482 * Find an entry using the provided match function to compare the entries for 
     483 * equality. 
     484 */ 
     485static status_t get_entry_by_match_function(private_ike_sa_manager_t *this, 
     486                    ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment, 
     487                    linked_list_match_t match, void *p1, void *p2) 
     488
     489    entry_t *current; 
     490    linked_list_t *list; 
     491    u_int row = ike_sa_id_hash(ike_sa_id) & this->table_mask; 
     492    u_int seg = row & this->segment_mask; 
     493     
     494    lock_single_segment(this, seg); 
     495    if ((list = this->ike_sa_table[row]) != NULL) 
     496    { 
     497        if (list->find_first(list, match, (void**)&current, p1, p2) == SUCCESS) 
     498        { 
     499            *entry = current; 
     500            *segment = seg; 
     501            /* the locked segment has to be unlocked by the caller */ 
     502            return SUCCESS; 
     503        } 
     504    } 
     505    unlock_single_segment(this, seg); 
     506    return NOT_FOUND; 
     507
     508 
     509/** 
     510 * Find an entry by ike_sa_id_t. 
     511 * Note: On SUCCESS, the caller has to unlock the segment. 
    184512 */ 
    185513static status_t get_entry_by_id(private_ike_sa_manager_t *this, 
    186                                 ike_sa_id_t *ike_sa_id, entry_t **entry) 
    187 
    188     enumerator_t *enumerator; 
    189     entry_t *current; 
    190     status_t status; 
    191      
    192     /* create enumerator over list of ike_sa's */ 
    193     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    194  
    195     /* default status */ 
    196     status = NOT_FOUND; 
    197      
    198     while (enumerator->enumerate(enumerator, &current)) 
    199     { 
    200         if (current->ike_sa_id->equals(current->ike_sa_id, ike_sa_id)) 
    201         { 
    202             DBG2(DBG_MGR,  "found entry by both SPIs"); 
    203             *entry = current; 
    204             status = SUCCESS; 
    205             break; 
    206         } 
    207         if (ike_sa_id->get_responder_spi(ike_sa_id) == 0 || 
    208             current->ike_sa_id->get_responder_spi(current->ike_sa_id) == 0) 
    209         { 
    210             /* seems to be a half ready ike_sa */ 
    211             if ((current->ike_sa_id->get_initiator_spi(current->ike_sa_id) == 
    212                           ike_sa_id->get_initiator_spi(ike_sa_id)) && 
    213                 (current->ike_sa_id->is_initiator(ike_sa_id) == 
    214                           ike_sa_id->is_initiator(current->ike_sa_id))) 
    215             { 
    216                 DBG2(DBG_MGR, "found entry by initiator SPI"); 
    217                 *entry = current; 
    218                 status = SUCCESS; 
    219                 break; 
    220             } 
    221         } 
    222     } 
    223      
    224     enumerator->destroy(enumerator); 
    225     return status; 
    226 
    227  
    228 /** 
    229  * Implementation of private_ike_sa_manager_t.get_entry_by_sa. 
     514                        ike_sa_id_t *ike_sa_id, entry_t **entry, u_int *segment) 
     515
     516    return get_entry_by_match_function(this, ike_sa_id, entry, segment,  
     517                (linked_list_match_t)entry_match_by_id, ike_sa_id, NULL); 
     518
     519 
     520/** 
     521 * Find an entry by initiator SPI and IKE_SA_INIT hash. 
     522 * Note: On SUCCESS, the caller has to unlock the segment. 
     523 */ 
     524static status_t get_entry_by_hash(private_ike_sa_manager_t *this, 
     525            ike_sa_id_t *ike_sa_id, chunk_t hash, entry_t **entry, u_int *segment) 
     526
     527    return get_entry_by_match_function(this, ike_sa_id, entry, segment, 
     528                (linked_list_match_t)entry_match_by_hash, ike_sa_id, &hash); 
     529
     530 
     531/** 
     532 * Find an entry by IKE_SA pointer. 
     533 * Note: On SUCCESS, the caller has to unlock the segment. 
    230534 */ 
    231535static status_t get_entry_by_sa(private_ike_sa_manager_t *this, 
    232                                 ike_sa_t *ike_sa, entry_t **entry) 
    233 
    234     enumerator_t *enumerator; 
    235     entry_t *current; 
    236     status_t status; 
    237      
    238     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    239      
    240     /* default status */ 
    241     status = NOT_FOUND; 
    242      
    243     while (enumerator->enumerate(enumerator, &current)) 
    244     { 
    245         /* only pointers are compared */ 
    246         if (current->ike_sa == ike_sa) 
    247         { 
    248             DBG2(DBG_MGR, "found entry by pointer"); 
    249             *entry = current; 
    250             status = SUCCESS; 
    251             break; 
    252         } 
    253     } 
    254     enumerator->destroy(enumerator); 
    255      
    256     return status; 
    257 
    258  
    259 /** 
    260  * Implementation of private_ike_sa_manager_s.delete_entry. 
    261  */ 
    262 static status_t delete_entry(private_ike_sa_manager_t *this, entry_t *entry) 
    263 
    264     enumerator_t *enumerator; 
    265     entry_t *current; 
    266     status_t status; 
    267      
    268     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    269  
    270     status = NOT_FOUND; 
    271      
    272     while (enumerator->enumerate(enumerator, &current)) 
    273     { 
    274         if (current == entry) 
    275         { 
    276             /* mark it, so now new threads can get this entry */ 
    277             entry->driveout_new_threads = TRUE; 
    278             /* wait until all workers have done their work */ 
    279             while (entry->waiting_threads) 
    280             { 
    281                 /* wake up all */ 
    282                 entry->condvar->broadcast(entry->condvar); 
    283                 /* they will wake us again when their work is done */ 
    284                 entry->condvar->wait(entry->condvar, this->mutex); 
    285             } 
    286              
    287             DBG2(DBG_MGR,  "found entry by pointer, deleting it"); 
    288             this->ike_sa_list->remove_at(this->ike_sa_list, enumerator); 
    289             entry_destroy(entry); 
    290             status = SUCCESS; 
    291             break; 
    292         } 
    293     } 
    294     enumerator->destroy(enumerator); 
    295     return status; 
     536            ike_sa_id_t *ike_sa_id, ike_sa_t *ike_sa, entry_t **entry, u_int *segment) 
     537
     538    return get_entry_by_match_function(this, ike_sa_id, entry, segment, 
     539                (linked_list_match_t)entry_match_by_sa, ike_sa, NULL); 
    296540} 
    297541 
    298542/** 
    299543 * Wait until no other thread is using an IKE_SA, return FALSE if entry not 
    300  * acquireable 
    301  */ 
    302 static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry) 
     544 * acquirable. 
     545 */ 
     546static bool wait_for_entry(private_ike_sa_manager_t *this, entry_t *entry, 
     547                           u_int segment) 
    303548{ 
    304549    if (entry->driveout_new_threads) 
     
    312557         * we register us as waiting. */ 
    313558        entry->waiting_threads++; 
    314         entry->condvar->wait(entry->condvar, this->mutex); 
     559        entry->condvar->wait(entry->condvar, this->segments[segment].mutex); 
    315560        entry->waiting_threads--; 
    316561    } 
     
    343588    ike_sa_t *ike_sa = NULL; 
    344589    entry_t *entry; 
    345      
    346     DBG2(DBG_MGR, "checkout IKE_SA, %d IKE_SAs in manager", 
    347          this->ike_sa_list->get_count(this->ike_sa_list)); 
    348      
    349     this->mutex->lock(this->mutex); 
    350     if (get_entry_by_id(this, ike_sa_id, &entry) == SUCCESS) 
    351     { 
    352         if (wait_for_entry(this, entry)) 
     590    u_int segment; 
     591     
     592    DBG2(DBG_MGR, "checkout IKE_SA"); 
     593     
     594    if (get_entry_by_id(this, ike_sa_id, &entry, &segment) == SUCCESS) 
     595    { 
     596        if (wait_for_entry(this, entry, segment)) 
    353597        { 
    354598            DBG2(DBG_MGR, "IKE_SA successfully checked out"); 
     
    356600            ike_sa = entry->ike_sa; 
    357601        } 
    358     } 
    359     this->mutex->unlock(this->mutex); 
     602       unlock_single_segment(this, segment); 
     603    } 
    360604    charon->bus->set_sa(charon->bus, ike_sa); 
    361605    return ike_sa; 
     
    369613    entry_t *entry; 
    370614    ike_sa_id_t *id; 
     615    u_int segment; 
    371616     
    372617    if (initiator) 
     
    380625    entry = entry_create(id); 
    381626    id->destroy(id); 
    382     this->mutex->lock(this->mutex);     
    383     this->ike_sa_list->insert_last(this->ike_sa_list, entry); 
     627     
     628    segment = put_entry(this, entry);  
    384629    entry->checked_out = TRUE; 
    385     this->mutex->unlock(this->mutex);   
    386     DBG2(DBG_MGR, "created IKE_SA, %d IKE_SAs in manager", 
    387         this->ike_sa_list->get_count(this->ike_sa_list)); 
     630    unlock_single_segment(this, segment); 
     631     
     632    DBG2(DBG_MGR, "created IKE_SA"); 
    388633    return entry->ike_sa; 
    389634} 
     
    395640                                     message_t *message) 
    396641{ 
     642    u_int segment; 
    397643    entry_t *entry; 
    398644    ike_sa_t *ike_sa = NULL; 
     
    401647    id->switch_initiator(id); 
    402648     
    403     DBG2(DBG_MGR, "checkout IKE_SA by message, %d IKE_SAs in manager", 
    404          this->ike_sa_list->get_count(this->ike_sa_list)); 
     649    DBG2(DBG_MGR, "checkout IKE_SA by message"); 
    405650     
    406651    if (message->get_request(message) && 
     
    408653    { 
    409654        /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */ 
    410         enumerator_t *enumerator; 
    411655        chunk_t data, hash; 
    412          
     656            
    413657        data = message->get_packet_data(message); 
    414658        this->hasher->allocate_hash(this->hasher, data, &hash); 
    415659        chunk_free(&data); 
    416660         
    417         this->mutex->lock(this->mutex); 
    418         enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    419         while (enumerator->enumerate(enumerator, &entry)) 
    420         { 
    421             if (chunk_equals(hash, entry->init_hash)) 
    422             { 
    423                 if (entry->message_id == 0) 
    424                 { 
    425                     enumerator->destroy(enumerator); 
    426                     this->mutex->unlock(this->mutex); 
    427                     chunk_free(&hash); 
    428                     id->destroy(id); 
    429                     DBG1(DBG_MGR, "ignoring IKE_SA_INIT, already processing"); 
    430                     return NULL; 
    431                 } 
    432                 else if (wait_for_entry(this, entry)) 
    433                 { 
    434                     DBG2(DBG_MGR, "IKE_SA checked out by hash"); 
    435                     entry->checked_out = TRUE; 
    436                     entry->message_id = message->get_message_id(message); 
    437                     ike_sa = entry->ike_sa; 
    438                 } 
    439                 break; 
    440             } 
    441         } 
    442         enumerator->destroy(enumerator); 
    443         this->mutex->unlock(this->mutex); 
     661        if (get_entry_by_hash(this, id, hash, &entry, &segment) == SUCCESS) 
     662        { 
     663            if (entry->message_id == 0) 
     664            { 
     665                unlock_single_segment(this, segment); 
     666                chunk_free(&hash); 
     667                id->destroy(id); 
     668                DBG1(DBG_MGR, "ignoring IKE_SA_INIT, already processing"); 
     669                return NULL; 
     670            } 
     671            else if (wait_for_entry(this, entry, segment)) 
     672            { 
     673                DBG2(DBG_MGR, "IKE_SA checked out by hash"); 
     674                entry->checked_out = TRUE; 
     675                entry->message_id = message->get_message_id(message); 
     676                ike_sa = entry->ike_sa; 
     677            } 
     678            unlock_single_segment(this, segment); 
     679        } 
    444680         
    445681        if (ike_sa == NULL) 
     
    452688                entry = entry_create(id); 
    453689                 
    454                 this->mutex->lock(this->mutex); 
    455                 this->ike_sa_list->insert_last(this->ike_sa_list, entry); 
     690                segment = put_entry(this, entry); 
    456691                entry->checked_out = TRUE; 
    457                 entry->message_id = message->get_message_id(message); 
    458                 this->mutex->unlock(this->mutex); 
     692                unlock_single_segment(this, segment); 
     693                 
     694                entry->message_id = message->get_message_id(message);                
    459695                entry->init_hash = hash; 
    460696                ike_sa = entry->ike_sa; 
     697                 
     698                DBG2(DBG_MGR, "created IKE_SA"); 
    461699            } 
    462700            else 
     
    475713    } 
    476714     
    477     this->mutex->lock(this->mutex); 
    478     if (get_entry_by_id(this, id, &entry) == SUCCESS) 
     715    if (get_entry_by_id(this, id, &entry, &segment) == SUCCESS) 
    479716    { 
    480717        /* only check out if we are not processing this request */ 
     
    485722                 entry->message_id); 
    486723        } 
    487         else if (wait_for_entry(this, entry)) 
     724        else if (wait_for_entry(this, entry, segment)) 
    488725        { 
    489726            ike_sa_id_t *ike_id = entry->ike_sa->get_id(entry->ike_sa); 
     
    497734            ike_sa = entry->ike_sa; 
    498735        } 
    499     } 
    500     this->mutex->unlock(this->mutex); 
     736       unlock_single_segment(this, segment); 
     737    } 
    501738    id->destroy(id); 
    502739    charon->bus->set_sa(charon->bus, ike_sa); 
     
    516753    host_t *my_host, *other_host; 
    517754    ike_cfg_t *ike_cfg; 
     755    u_int segment; 
    518756     
    519757    ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); 
     
    523761    other_host = host_create_from_dns(ike_cfg->get_other_addr(ike_cfg), 0, 0); 
    524762     
    525     this->mutex->lock(this->mutex); 
    526      
    527763    if (my_host && other_host && this->reuse_ikesa) 
    528764    { 
    529         enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    530         while (enumerator->enumerate(enumerator, &entry)) 
     765        enumerator = create_table_enumerator(this); 
     766        while (enumerator->enumerate(enumerator, &entry, &segment)) 
    531767        { 
    532768            identification_t *found_my_id, *found_other_id; 
    533769            host_t *found_my_host, *found_other_host; 
    534770         
    535             if (!wait_for_entry(this, entry)) 
     771            if (!wait_for_entry(this, entry, segment)) 
    536772            { 
    537773                continue; 
     
    540776            if (entry->ike_sa->get_state(entry->ike_sa) == IKE_DELETING) 
    541777            { 
    542                 /* skip IKE_SA which are not useable */ 
     778                /* skip IKE_SAs which are not usable */ 
    543779                continue; 
    544780            } 
     
    586822    if (!ike_sa) 
    587823    { 
    588         u_int64_t initiator_spi; 
    589824        entry_t *new_entry; 
    590825        ike_sa_id_t *new_ike_sa_id; 
    591826         
    592         initiator_spi = get_next_spi(this); 
    593         new_ike_sa_id = ike_sa_id_create(0, 0, TRUE); 
    594         new_ike_sa_id->set_initiator_spi(new_ike_sa_id, initiator_spi); 
     827        new_ike_sa_id = ike_sa_id_create(get_next_spi(this), 0, TRUE); 
    595828         
    596829        /* create entry */ 
    597830        new_entry = entry_create(new_ike_sa_id); 
    598         DBG2(DBG_MGR, "created IKE_SA"); 
    599831        new_ike_sa_id->destroy(new_ike_sa_id); 
    600832         
    601         this->ike_sa_list->insert_last(this->ike_sa_list, new_entry); 
     833        segment = put_entry(this, new_entry); 
    602834         
    603835        /* check ike_sa out */ 
     
    605837        new_entry->checked_out = TRUE; 
    606838        ike_sa = new_entry->ike_sa; 
    607     } 
    608     this->mutex->unlock(this->mutex); 
     839       unlock_single_segment(this, segment); 
     840    } 
    609841    charon->bus->set_sa(charon->bus, ike_sa); 
    610842    return ike_sa; 
     
    622854    ike_sa_t *ike_sa = NULL; 
    623855    child_sa_t *child_sa; 
    624      
    625     this->mutex->lock(this->mutex); 
    626      
    627     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    628     while (enumerator->enumerate(enumerator, &entry)) 
    629     { 
    630         if (wait_for_entry(this, entry)) 
     856    u_int segment; 
     857     
     858    enumerator = create_table_enumerator(this); 
     859    while (enumerator->enumerate(enumerator, &entry, &segment)) 
     860    { 
     861        if (wait_for_entry(this, entry, segment)) 
    631862        { 
    632863            /* look for a child with such a reqid ... */ 
     
    660891    } 
    661892    enumerator->destroy(enumerator); 
    662     this->mutex->unlock(this->mutex); 
    663893     
    664894    charon->bus->set_sa(charon->bus, ike_sa); 
     
    677907    ike_sa_t *ike_sa = NULL; 
    678908    child_sa_t *child_sa; 
    679      
    680     this->mutex->lock(this->mutex); 
    681      
    682     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    683     while (enumerator->enumerate(enumerator, &entry)) 
    684     { 
    685         if (wait_for_entry(this, entry)) 
     909    u_int segment; 
     910     
     911    enumerator = create_table_enumerator(this); 
     912    while (enumerator->enumerate(enumerator, &entry, &segment)) 
     913    { 
     914        if (wait_for_entry(this, entry, segment)) 
    686915        { 
    687916            /* look for a child with such a policy name ... */ 
     
    715944    } 
    716945    enumerator->destroy(enumerator); 
    717     this->mutex->unlock(this->mutex); 
    718946     
    719947    charon->bus->set_sa(charon->bus, ike_sa); 
     
    731959    ike_sa_t *duplicate = NULL; 
    732960    identification_t *me, *other; 
     961    u_int segment; 
    733962     
    734963    me = ike_sa->get_my_id(ike_sa); 
    735964    other = ike_sa->get_other_id(ike_sa); 
    736965     
    737     this->mutex->lock(this->mutex); 
    738     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    739     while (enumerator->enumerate(enumerator, &entry)) 
     966    enumerator = create_table_enumerator(this); 
     967    while (enumerator->enumerate(enumerator, &entry, &segment)) 
    740968    { 
    741969        if (entry->ike_sa == ike_sa) 
     
    749977             * checkout_duplicate here, as the identities in entry would not 
    750978             * have been set yet. Otherwise we would risk a deadlock. */ 
    751             if (wait_for_entry(this, entry)) 
     979            if (wait_for_entry(this, entry, segment)) 
    752980            { 
    753981                duplicate = entry->ike_sa; 
     
    758986    } 
    759987    enumerator->destroy(enumerator); 
    760     this->mutex->unlock(this->mutex); 
    761988    return duplicate; 
    762989} 
    763990 
    764991/** 
    765  * enumerator cleanup function 
    766  */ 
    767 static void enumerator_unlock(private_ike_sa_manager_t *this) 
    768 { 
    769     this->mutex->unlock(this->mutex); 
    770 } 
    771  
    772 /** 
    773992 * enumerator filter function  
    774993 */ 
    775994static bool enumerator_filter(private_ike_sa_manager_t *this, 
    776                               entry_t **in, ike_sa_t **out
    777 { 
    778     if (wait_for_entry(this, *in)) 
     995                              entry_t **in, ike_sa_t **out, u_int *segment
     996{ 
     997    if (wait_for_entry(this, *in, *segment)) 
    779998    { 
    780999        *out = (*in)->ike_sa; 
     
    7851004 
    7861005/** 
    787  * Implementation of ike_sa_manager_t.create_iterator. 
     1006 * Implementation of ike_sa_manager_t.create_enumerator. 
    7881007 */ 
    7891008static enumerator_t *create_enumerator(private_ike_sa_manager_t* this) 
    7901009{ 
    791     this->mutex->lock(this->mutex); 
    7921010    return enumerator_create_filter( 
    793                         this->ike_sa_list->create_enumerator(this->ike_sa_list), 
    794                         (void*)enumerator_filter, this, (void*)enumerator_unlock); 
     1011                        create_table_enumerator(this), 
     1012                        (void*)enumerator_filter, this, NULL); 
    7951013} 
    7961014 
     
    8021020    /* to check the SA back in, we look for the pointer of the ike_sa 
    8031021     * in all entries. 
    804      * We can't search by SPI's since the MAY have changed (e.g. on reception 
    805      * of a IKE_SA_INIT response). Updating of the SPI MAY be necessary... 
     1022     * The lookup is done by initiator SPI, so even if the SPI has changed (e.g. 
     1023     * on reception of a IKE_SA_INIT response) the lookup will work but 
     1024     * updating of the SPI MAY be necessary... 
    8061025     */ 
    8071026    status_t retval; 
     
    8101029    host_t *other; 
    8111030    identification_t *my_id, *other_id; 
     1031    u_int segment; 
    8121032     
    8131033    ike_sa_id = ike_sa->get_id(ike_sa); 
     
    8151035    DBG2(DBG_MGR, "checkin IKE_SA"); 
    8161036     
    817     this->mutex->lock(this->mutex); 
    818  
    8191037    /* look for the entry */ 
    820     if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) 
     1038    if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS) 
    8211039    { 
    8221040        /* ike_sa_id must be updated */ 
     
    8321050            entry->other = other->clone(other); 
    8331051        } 
    834         /* apply identities for diplicate test */ 
     1052        /* apply identities for duplicate test */ 
    8351053        my_id = ike_sa->get_my_id(ike_sa); 
    8361054        other_id = ike_sa->get_other_id(ike_sa); 
     
    8501068        entry->condvar->signal(entry->condvar); 
    8511069        retval = SUCCESS; 
     1070        unlock_single_segment(this, segment); 
    8521071    } 
    8531072    else 
     
    8581077    } 
    8591078     
    860     DBG2(DBG_MGR, "%d IKE_SAs in manager now", 
    861          this->ike_sa_list->get_count(this->ike_sa_list)); 
    862     this->mutex->unlock(this->mutex); 
    863      
    8641079    charon->bus->set_sa(charon->bus, NULL); 
    8651080    return retval; 
     
    8721087static status_t checkin_and_destroy(private_ike_sa_manager_t *this, ike_sa_t *ike_sa) 
    8731088{ 
    874     /* deletion is a bit complex, we must garant that no thread is waiting for 
     1089    /* deletion is a bit complex, we must ensure that no thread is waiting for 
    8751090     * this SA. 
    876      * We take this SA from the list, and start signaling while threads 
     1091     * We take this SA from the table, and start signaling while threads 
    8771092     * are in the condvar. 
    8781093     */ 
     
    8801095    status_t retval; 
    8811096    ike_sa_id_t *ike_sa_id; 
     1097    u_int segment; 
    8821098     
    8831099    ike_sa_id = ike_sa->get_id(ike_sa); 
     1100     
    8841101    DBG2(DBG_MGR, "checkin and destroy IKE_SA"); 
    8851102 
    886     this->mutex->lock(this->mutex); 
    887  
    888     if (get_entry_by_sa(this, ike_sa, &entry) == SUCCESS) 
     1103    if (get_entry_by_sa(this, ike_sa_id, ike_sa, &entry, &segment) == SUCCESS) 
    8891104    { 
    8901105        /* drive out waiting threads, as we are in hurry */ 
    8911106        entry->driveout_waiting_threads = TRUE; 
    892          
    893         delete_entry(this, entry); 
     1107        /* mark it, so no new threads can get this entry */ 
     1108        entry->driveout_new_threads = TRUE; 
     1109        /* wait until all workers have done their work */ 
     1110        while (entry->waiting_threads) 
     1111        { 
     1112            /* wake up all */ 
     1113            entry->condvar->broadcast(entry->condvar); 
     1114            /* they will wake us again when their work is done */ 
     1115            entry->condvar->wait(entry->condvar, this->segments[segment].mutex); 
     1116        } 
     1117     
     1118        remove_entry(this, entry); 
     1119        entry_destroy(entry); 
     1120        unlock_single_segment(this, segment); 
    8941121         
    8951122        DBG2(DBG_MGR, "check-in and destroy of IKE_SA successful"); 
     
    9021129    } 
    9031130    charon->bus->set_sa(charon->bus, NULL); 
    904      
    905     this->mutex->unlock(this->mutex); 
    9061131    return retval; 
    9071132} 
     
    9161141    int count = 0; 
    9171142 
    918     this->mutex->lock(this->mutex); 
    919     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
     1143    enumerator = create_table_enumerator(this); 
    9201144    while (enumerator->enumerate(enumerator, &entry)) 
    9211145    { 
     
    9401164    enumerator->destroy(enumerator); 
    9411165     
    942     this->mutex->unlock(this->mutex); 
    9431166    return count; 
    9441167} 
     
    9521175    enumerator_t *enumerator; 
    9531176    entry_t *entry; 
    954      
    955     this->mutex->lock(this->mutex); 
     1177    u_int segment; 
     1178     
     1179    lock_all_segments(this); 
    9561180    DBG2(DBG_MGR, "going to destroy IKE_SA manager and all managed IKE_SA's"); 
    9571181    /* Step 1: drive out all waiting threads  */ 
    9581182    DBG2(DBG_MGR, "set driveout flags for all stored IKE_SA's"); 
    959     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    960     while (enumerator->enumerate(enumerator, &entry)) 
     1183    enumerator = create_table_enumerator(this); 
     1184    while (enumerator->enumerate(enumerator, &entry, &segment)) 
    9611185    { 
    9621186        /* do not accept new threads, drive out waiting threads */ 
     
    9671191    DBG2(DBG_MGR, "wait for all threads to leave IKE_SA's"); 
    9681192    /* Step 2: wait until all are gone */ 
    969     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    970     while (enumerator->enumerate(enumerator, &entry)) 
     1193    enumerator = create_table_enumerator(this); 
     1194    while (enumerator->enumerate(enumerator, &entry, &segment)) 
    9711195    { 
    9721196        while (entry->waiting_threads) 
     
    9751199            entry->condvar->broadcast(entry->condvar); 
    9761200            /* go sleeping until they are gone */ 
    977             entry->condvar->wait(entry->condvar, this->mutex); 
     1201            entry->condvar->wait(entry->condvar, this->segments[segment].mutex); 
    9781202        } 
    9791203    } 
     
    9811205    DBG2(DBG_MGR, "delete all IKE_SA's"); 
    9821206    /* Step 3: initiate deletion of all IKE_SAs */ 
    983     enumerator = this->ike_sa_list->create_enumerator(this->ike_sa_list); 
    984     while (enumerator->enumerate(enumerator, &entry)) 
     1207    enumerator = create_table_enumerator(this); 
     1208    while (enumerator->enumerate(enumerator, &entry, &segment)) 
    9851209    { 
    9861210        charon->bus->set_sa(charon->bus, entry->ike_sa); 
     
    9911215    DBG2(DBG_MGR, "destroy all entries"); 
    9921216    /* Step 4: destroy all entries */ 
    993     while (this->ike_sa_list->remove_last(this->ike_sa_list, 
    994                                          (void**)&entry) == SUCCESS
     1217    enumerator = create_table_enumerator(this); 
     1218    while (enumerator->enumerate(enumerator, &entry, &segment)
    9951219    { 
    9961220        charon->bus->set_sa(charon->bus, entry->ike_sa); 
     1221        remove_entry_at((private_enumerator_t*)enumerator); 
    9971222        entry_destroy(entry); 
    9981223    } 
     1224    enumerator->destroy(enumerator); 
    9991225    charon->bus->set_sa(charon->bus, NULL); 
    1000     this->mutex->unlock(this->mutex); 
     1226    unlock_all_segments(this); 
    10011227} 
    10021228 
     
    10061232static void destroy(private_ike_sa_manager_t *this) 
    10071233{ 
    1008     this->ike_sa_list->destroy(this->ike_sa_list); 
     1234    u_int i; 
     1235    for (i = 0; i < this->table_size; ++i) 
     1236    { 
     1237        linked_list_t *list; 
     1238        if ((list = this->ike_sa_table[i]) != NULL) 
     1239        { 
     1240            list->destroy(list); 
     1241        } 
     1242    } 
     1243    free(this->ike_sa_table); 
     1244    for (i = 0; i < this->segment_count; ++i) 
     1245    { 
     1