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>