Return to ha_attribute.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libcharon / plugins / ha |
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: }