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>