Annotation of embedaddon/strongswan/src/libcharon/plugins/ha/ha_attribute.c, revision 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>