Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_attribute.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2010 Martin Willi
                      3:  * Copyright (C) 2010 revosec AG
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: 
                     16: #include "ha_attribute.h"
                     17: 
                     18: #include <collections/linked_list.h>
                     19: #include <threading/mutex.h>
                     20: 
                     21: typedef struct private_ha_attribute_t private_ha_attribute_t;
                     22: 
                     23: /**
                     24:  * Private data of an ha_attribute_t object.
                     25:  */
                     26: struct private_ha_attribute_t {
                     27: 
                     28:        /**
                     29:         * Public ha_attribute_t interface.
                     30:         */
                     31:        ha_attribute_t public;
                     32: 
                     33:        /**
                     34:         * List of pools, pool_t
                     35:         */
                     36:        linked_list_t *pools;
                     37: 
                     38:        /**
                     39:         * Mutex to lock mask
                     40:         */
                     41:        mutex_t *mutex;
                     42: 
                     43:        /**
                     44:         * Kernel helper
                     45:         */
                     46:        ha_kernel_t *kernel;
                     47: 
                     48:        /**
                     49:         * Segment responsibility
                     50:         */
                     51:        ha_segments_t *segments;
                     52: };
                     53: 
                     54: /**
                     55:  * In-memory pool.
                     56:  */
                     57: typedef struct {
                     58:        /** name of the pool */
                     59:        char *name;
                     60:        /** base address of pool */
                     61:        host_t *base;
                     62:        /** total number of addresses in this pool */
                     63:        int size;
                     64:        /** bitmask for address usage */
                     65:        u_char *mask;
                     66: } pool_t;
                     67: 
                     68: /**
                     69:  * Clean up a pool entry
                     70:  */
                     71: static void pool_destroy(pool_t *pool)
                     72: {
                     73:        pool->base->destroy(pool->base);
                     74:        free(pool->name);
                     75:        free(pool->mask);
                     76:        free(pool);
                     77: }
                     78: 
                     79: /**
                     80:  * convert a pool offset to an address
                     81:  */
                     82: static host_t* offset2host(pool_t *pool, int offset)
                     83: {
                     84:        chunk_t addr;
                     85:        host_t *host;
                     86:        uint32_t *pos;
                     87: 
                     88:        if (offset > pool->size)
                     89:        {
                     90:                return NULL;
                     91:        }
                     92: 
                     93:        addr = chunk_clone(pool->base->get_address(pool->base));
                     94:        if (pool->base->get_family(pool->base) == AF_INET6)
                     95:        {
                     96:                pos = (uint32_t*)(addr.ptr + 12);
                     97:        }
                     98:        else
                     99:        {
                    100:                pos = (uint32_t*)addr.ptr;
                    101:        }
                    102:        *pos = htonl(offset + ntohl(*pos));
                    103:        host = host_create_from_chunk(pool->base->get_family(pool->base), addr, 0);
                    104:        free(addr.ptr);
                    105:        return host;
                    106: }
                    107: 
                    108: /**
                    109:  * convert a host to a pool offset
                    110:  */
                    111: static int host2offset(pool_t *pool, host_t *addr)
                    112: {
                    113:        chunk_t host, base;
                    114:        uint32_t hosti, basei;
                    115: 
                    116:        if (addr->get_family(addr) != pool->base->get_family(pool->base))
                    117:        {
                    118:                return -1;
                    119:        }
                    120:        host = addr->get_address(addr);
                    121:        base = pool->base->get_address(pool->base);
                    122:        if (addr->get_family(addr) == AF_INET6)
                    123:        {
                    124:                /* only look at last /32 block */
                    125:                if (!memeq(host.ptr, base.ptr, 12))
                    126:                {
                    127:                        return -1;
                    128:                }
                    129:                host = chunk_skip(host, 12);
                    130:                base = chunk_skip(base, 12);
                    131:        }
                    132:        hosti = ntohl(*(uint32_t*)(host.ptr));
                    133:        basei = ntohl(*(uint32_t*)(base.ptr));
                    134:        if (hosti > basei + pool->size)
                    135:        {
                    136:                return -1;
                    137:        }
                    138:        return hosti - basei;
                    139: }
                    140: 
                    141: /**
                    142:  * Find a pool by its name
                    143:  */
                    144: static pool_t* get_pool(private_ha_attribute_t *this, char *name)
                    145: {
                    146:        enumerator_t *enumerator;
                    147:        pool_t *pool, *found = NULL;
                    148: 
                    149:        enumerator = this->pools->create_enumerator(this->pools);
                    150:        while (enumerator->enumerate(enumerator, &pool))
                    151:        {
                    152:                if (streq(name, pool->name))
                    153:                {
                    154:                        found = pool;
                    155:                }
                    156:        }
                    157:        enumerator->destroy(enumerator);
                    158:        return found;
                    159: }
                    160: 
                    161: /**
                    162:  * Check if we are responsible for an offset
                    163:  */
                    164: static bool responsible_for(private_ha_attribute_t *this, int offset)
                    165: {
                    166:        u_int segment;
                    167: 
                    168:        segment = offset % this->segments->count(this->segments) + 1;
                    169:        return this->segments->is_active(this->segments, segment);
                    170: }
                    171: 
                    172: METHOD(attribute_provider_t, acquire_address, host_t*,
                    173:        private_ha_attribute_t *this, linked_list_t *pools, ike_sa_t *ike_sa,
                    174:        host_t *requested)
                    175: {
                    176:        enumerator_t *enumerator;
                    177:        pool_t *pool = NULL;
                    178:        int offset = -1, tmp_offset, byte, bit;
                    179:        host_t *address;
                    180:        char *name;
                    181: 
                    182:        enumerator = pools->create_enumerator(pools);
                    183:        this->mutex->lock(this->mutex);
                    184:        while (enumerator->enumerate(enumerator, &name))
                    185:        {
                    186:                pool = get_pool(this, name);
                    187:                if (!pool)
                    188:                {
                    189:                        continue;
                    190:                }
                    191:                if (pool->base->get_family(pool->base) !=
                    192:                        requested->get_family(requested))
                    193:                {
                    194:                        continue;
                    195:                }
                    196:                for (byte = 0; byte < pool->size / 8; byte++)
                    197:                {
                    198:                        if (pool->mask[byte] != 0xFF)
                    199:                        {
                    200:                                for (bit = 0; bit < 8; bit++)
                    201:                                {
                    202:                                        tmp_offset = byte * 8 + bit;
                    203:                                        if (!(pool->mask[byte] & 1 << bit) &&
                    204:                                                responsible_for(this, tmp_offset))
                    205:                                        {
                    206:                                                offset = tmp_offset;
                    207:                                                pool->mask[byte] |= 1 << bit;
                    208:                                                break;
                    209:                                        }
                    210:                                }
                    211:                        }
                    212:                        if (offset != -1)
                    213:                        {
                    214:                                break;
                    215:                        }
                    216:                }
                    217:                if (offset == -1)
                    218:                {
                    219:                        DBG1(DBG_CFG, "no address belonging to a responsible segment left "
                    220:                                 "in HA pool '%s'", name);
                    221:                }
                    222:                else
                    223:                {
                    224:                        break;
                    225:                }
                    226:        }
                    227:        this->mutex->unlock(this->mutex);
                    228:        enumerator->destroy(enumerator);
                    229: 
                    230:        if (offset != -1)
                    231:        {
                    232:                address = offset2host(pool, offset);
                    233:                DBG1(DBG_CFG, "acquired address %H from HA pool '%s'", address, name);
                    234:                return address;
                    235:        }
                    236:        return NULL;
                    237: }
                    238: 
                    239: METHOD(attribute_provider_t, release_address, bool,
                    240:        private_ha_attribute_t *this, linked_list_t *pools, host_t *address,
                    241:        ike_sa_t *ike_sa)
                    242: {
                    243:        enumerator_t *enumerator;
                    244:        pool_t *pool;
                    245:        int offset;
                    246:        char *name;
                    247:        bool found = FALSE;
                    248: 
                    249:        enumerator = pools->create_enumerator(pools);
                    250:        this->mutex->lock(this->mutex);
                    251:        while (enumerator->enumerate(enumerator, &name))
                    252:        {
                    253:                pool = get_pool(this, name);
                    254:                if (!pool)
                    255:                {
                    256:                        continue;
                    257:                }
                    258:                if (pool->base->get_family(pool->base) != address->get_family(address))
                    259:                {
                    260:                        continue;
                    261:                }
                    262:                offset = host2offset(pool, address);
                    263:                if (offset > 0 && offset < pool->size)
                    264:                {
                    265:                        pool->mask[offset / 8] &= ~(1 << (offset % 8));
                    266:                        DBG1(DBG_CFG, "released address %H to HA pool '%s'", address, name);
                    267:                        found = TRUE;
                    268:                        break;
                    269:                }
                    270:        }
                    271:        this->mutex->unlock(this->mutex);
                    272:        enumerator->destroy(enumerator);
                    273: 
                    274:        return found;
                    275: }
                    276: 
                    277: METHOD(ha_attribute_t, reserve, void,
                    278:        private_ha_attribute_t *this, char *name, host_t *address)
                    279: {
                    280:        pool_t *pool;
                    281:        int offset;
                    282: 
                    283:        this->mutex->lock(this->mutex);
                    284:        pool = get_pool(this, name);
                    285:        if (pool)
                    286:        {
                    287:                offset = host2offset(pool, address);
                    288:                if (offset > 0 && offset < pool->size)
                    289:                {
                    290:                        pool->mask[offset / 8] |= 1 << (offset % 8);
                    291:                        DBG1(DBG_CFG, "reserved address %H in HA pool '%s'", address, name);
                    292:                }
                    293:        }
                    294:        this->mutex->unlock(this->mutex);
                    295: }
                    296: 
                    297: METHOD(ha_attribute_t, destroy, void,
                    298:        private_ha_attribute_t *this)
                    299: {
                    300:        this->pools->destroy_function(this->pools, (void*)pool_destroy);
                    301:        this->mutex->destroy(this->mutex);
                    302:        free(this);
                    303: }
                    304: 
                    305: /**
                    306:  * Load the configured pools.
                    307:  */
                    308: static void load_pools(private_ha_attribute_t *this)
                    309: {
                    310:        enumerator_t *enumerator;
                    311:        char *name, *net, *bits;
                    312:        host_t *base;
                    313:        int mask, maxbits;
                    314:        pool_t *pool;
                    315: 
                    316:        enumerator = lib->settings->create_key_value_enumerator(lib->settings,
                    317:                                                                                                "%s.plugins.ha.pools", lib->ns);
                    318:        while (enumerator->enumerate(enumerator, &name, &net))
                    319:        {
                    320:                net = strdup(net);
                    321:                bits = strchr(net, '/');
                    322:                if (!bits)
                    323:                {
                    324:                        DBG1(DBG_CFG, "invalid HA pool '%s' subnet, skipped", name);
                    325:                        free(net);
                    326:                        continue;
                    327:                }
                    328:                *bits++ = '\0';
                    329: 
                    330:                base = host_create_from_string(net, 0);
                    331:                mask = atoi(bits);
                    332:                free(net);
                    333:                if (!base || !mask)
                    334:                {
                    335:                        DESTROY_IF(base);
                    336:                        DBG1(DBG_CFG, "invalid HA pool '%s', skipped", name);
                    337:                        continue;
                    338:                }
                    339:                maxbits = base->get_family(base) == AF_INET ? 32 : 128;
                    340:                mask = maxbits - mask;
                    341:                if (mask > 24)
                    342:                {
                    343:                        mask = 24;
                    344:                        DBG1(DBG_CFG, "size of HA pool '%s' limited to /%d",
                    345:                                 name, maxbits - mask);
                    346:                }
                    347:                if (mask < 3)
                    348:                {
                    349:                        DBG1(DBG_CFG, "HA pool '%s' too small, skipped", name);
                    350:                        base->destroy(base);
                    351:                        continue;
                    352:                }
                    353: 
                    354:                INIT(pool,
                    355:                        .name = strdup(name),
                    356:                        .base = base,
                    357:                        .size = (1 << mask),
                    358:                );
                    359:                pool->mask = calloc(pool->size / 8, 1);
                    360:                /* do not use first/last address of pool */
                    361:                pool->mask[0] |= 0x01;
                    362:                pool->mask[pool->size / 8 - 1] |= 0x80;
                    363: 
                    364:                DBG1(DBG_CFG, "loaded HA pool '%s' %H/%d (%d addresses)",
                    365:                         pool->name, pool->base, maxbits - mask, pool->size - 2);
                    366:                this->pools->insert_last(this->pools, pool);
                    367:        }
                    368:        enumerator->destroy(enumerator);
                    369: }
                    370: 
                    371: /**
                    372:  * See header
                    373:  */
                    374: ha_attribute_t *ha_attribute_create(ha_kernel_t *kernel, ha_segments_t *segments)
                    375: {
                    376:        private_ha_attribute_t *this;
                    377: 
                    378:        INIT(this,
                    379:                .public = {
                    380:                        .provider = {
                    381:                                .acquire_address = _acquire_address,
                    382:                                .release_address = _release_address,
                    383:                                .create_attribute_enumerator = enumerator_create_empty,
                    384:                        },
                    385:                        .reserve = _reserve,
                    386:                        .destroy = _destroy,
                    387:                },
                    388:                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                    389:                .pools = linked_list_create(),
                    390:                .kernel = kernel,
                    391:                .segments = segments,
                    392:        );
                    393: 
                    394:        load_pools(this);
                    395: 
                    396:        return &this->public;
                    397: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>