2 * Copyright (C) 2010 Martin Willi
3 * Copyright (C) 2010 revosec AG
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>.
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
16 #include "ha_attribute.h"
18 #include <utils/linked_list.h>
19 #include <threading/mutex.h>
21 typedef struct private_ha_attribute_t private_ha_attribute_t
;
24 * Private data of an ha_attribute_t object.
26 struct private_ha_attribute_t
{
29 * Public ha_attribute_t interface.
31 ha_attribute_t
public;
34 * List of pools, pool_t
49 * Segment responsibility
51 ha_segments_t
*segments
;
58 /** name of the pool */
60 /** base address of pool */
62 /** total number of addresses in this pool */
64 /** bitmask for address usage */
69 * Clean up a pool entry
71 static void pool_destroy(pool_t
*pool
)
73 pool
->base
->destroy(pool
->base
);
80 * convert a pool offset to an address
82 static host_t
* offset2host(pool_t
*pool
, int offset
)
88 if (offset
> pool
->size
)
93 addr
= chunk_clone(pool
->base
->get_address(pool
->base
));
94 if (pool
->base
->get_family(pool
->base
) == AF_INET6
)
96 pos
= (u_int32_t
*)(addr
.ptr
+ 12);
100 pos
= (u_int32_t
*)addr
.ptr
;
102 *pos
= htonl(offset
+ ntohl(*pos
));
103 host
= host_create_from_chunk(pool
->base
->get_family(pool
->base
), addr
, 0);
109 * convert a host to a pool offset
111 static int host2offset(pool_t
*pool
, host_t
*addr
)
114 u_int32_t hosti
, basei
;
116 if (addr
->get_family(addr
) != pool
->base
->get_family(pool
->base
))
120 host
= addr
->get_address(addr
);
121 base
= pool
->base
->get_address(pool
->base
);
122 if (addr
->get_family(addr
) == AF_INET6
)
124 /* only look at last /32 block */
125 if (!memeq(host
.ptr
, base
.ptr
, 12))
129 host
= chunk_skip(host
, 12);
130 base
= chunk_skip(base
, 12);
132 hosti
= ntohl(*(u_int32_t
*)(host
.ptr
));
133 basei
= ntohl(*(u_int32_t
*)(base
.ptr
));
134 if (hosti
> basei
+ pool
->size
)
138 return hosti
- basei
;
142 * Find a pool by its name
144 static pool_t
* get_pool(private_ha_attribute_t
*this, char *name
)
146 enumerator_t
*enumerator
;
147 pool_t
*pool
, *found
= NULL
;
149 enumerator
= this->pools
->create_enumerator(this->pools
);
150 while (enumerator
->enumerate(enumerator
, &pool
))
152 if (streq(name
, pool
->name
))
157 enumerator
->destroy(enumerator
);
162 * Check if we are responsible for a bit in our bitmask
164 static bool responsible_for(private_ha_attribute_t
*this, int bit
)
168 segment
= this->kernel
->get_segment_int(this->kernel
, bit
);
169 return this->segments
->is_active(this->segments
, segment
);
172 METHOD(attribute_provider_t
, acquire_address
, host_t
*,
173 private_ha_attribute_t
*this, linked_list_t
*pools
, identification_t
*id
,
176 enumerator_t
*enumerator
;
178 int offset
= -1, byte
, bit
;
182 enumerator
= pools
->create_enumerator(pools
);
183 this->mutex
->lock(this->mutex
);
184 while (enumerator
->enumerate(enumerator
, &name
))
186 pool
= get_pool(this, name
);
191 if (pool
->base
->get_family(pool
->base
) !=
192 requested
->get_family(requested
))
196 for (byte
= 0; byte
< pool
->size
/ 8; byte
++)
198 if (pool
->mask
[byte
] != 0xFF)
200 for (bit
= 0; bit
< 8; bit
++)
202 if (!(pool
->mask
[byte
] & 1 << bit
) &&
203 responsible_for(this, bit
))
205 offset
= byte
* 8 + bit
;
206 pool
->mask
[byte
] |= 1 << bit
;
218 DBG1(DBG_CFG
, "no address left in HA pool '%s' belonging to"
219 "a responsible segment", name
);
222 this->mutex
->unlock(this->mutex
);
223 enumerator
->destroy(enumerator
);
227 address
= offset2host(pool
, offset
);
228 DBG1(DBG_CFG
, "acquired address %H from HA pool '%s'", address
, name
);
234 METHOD(attribute_provider_t
, release_address
, bool,
235 private_ha_attribute_t
*this, char *name
, host_t
*address
,
236 identification_t
*id
)
242 this->mutex
->lock(this->mutex
);
243 pool
= get_pool(this, name
);
246 offset
= host2offset(pool
, address
);
247 if (offset
> 0 && offset
< pool
->size
)
249 pool
->mask
[offset
/ 8] &= ~(1 << (offset
% 8));
250 DBG1(DBG_CFG
, "released address %H to HA pool '%s'", address
, name
);
254 this->mutex
->unlock(this->mutex
);
258 METHOD(ha_attribute_t
, reserve
, void,
259 private_ha_attribute_t
*this, char *name
, host_t
*address
)
264 this->mutex
->lock(this->mutex
);
265 pool
= get_pool(this, name
);
268 offset
= host2offset(pool
, address
);
269 if (offset
> 0 && offset
< pool
->size
)
271 pool
->mask
[offset
/ 8] |= 1 << (offset
% 8);
272 DBG1(DBG_CFG
, "reserved address %H in HA pool '%s'", address
, name
);
275 this->mutex
->unlock(this->mutex
);
278 METHOD(ha_attribute_t
, destroy
, void,
279 private_ha_attribute_t
*this)
281 this->pools
->destroy_function(this->pools
, (void*)pool_destroy
);
282 this->mutex
->destroy(this->mutex
);
287 * Load the configured pools.
289 static void load_pools(private_ha_attribute_t
*this)
291 enumerator_t
*enumerator
;
292 char *name
, *net
, *bits
;
297 enumerator
= lib
->settings
->create_key_value_enumerator(lib
->settings
,
298 "%s.plugins.ha.pools", charon
->name
);
299 while (enumerator
->enumerate(enumerator
, &name
, &net
))
302 bits
= strchr(net
, '/');
305 DBG1(DBG_CFG
, "invalid HA pool '%s' subnet, skipped", name
);
311 base
= host_create_from_string(net
, 0);
317 DBG1(DBG_CFG
, "invalid HA pool '%s', skipped", name
);
320 maxbits
= base
->get_family(base
) == AF_INET ?
32 : 128;
321 mask
= maxbits
- mask
;
325 DBG1(DBG_CFG
, "size of HA pool '%s' limited to /%d",
326 name
, maxbits
- mask
);
330 DBG1(DBG_CFG
, "HA pool '%s' too small, skipped", name
);
336 .name
= strdup(name
),
340 pool
->mask
= calloc(pool
->size
/ 8, 1);
341 /* do not use first/last address of pool */
342 pool
->mask
[0] |= 0x01;
343 pool
->mask
[pool
->size
/ 8 - 1] |= 0x80;
345 DBG1(DBG_CFG
, "loaded HA pool '%s' %H/%d (%d addresses)",
346 pool
->name
, pool
->base
, maxbits
- mask
, pool
->size
- 2);
347 this->pools
->insert_last(this->pools
, pool
);
349 enumerator
->destroy(enumerator
);
355 ha_attribute_t
*ha_attribute_create(ha_kernel_t
*kernel
, ha_segments_t
*segments
)
357 private_ha_attribute_t
*this;
362 .acquire_address
= _acquire_address
,
363 .release_address
= _release_address
,
364 .create_attribute_enumerator
= enumerator_create_empty
,
369 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
370 .pools
= linked_list_create(),
372 .segments
= segments
,
377 return &this->public;