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, char *name
, identification_t
*id
,
177 int offset
= -1, byte
, bit
;
180 this->mutex
->lock(this->mutex
);
181 pool
= get_pool(this, name
);
184 for (byte
= 0; byte
< pool
->size
/ 8; byte
++)
186 if (pool
->mask
[byte
] != 0xFF)
188 for (bit
= 0; bit
< 8; bit
++)
190 if (!(pool
->mask
[byte
] & 1 << bit
) &&
191 responsible_for(this, bit
))
193 offset
= byte
* 8 + bit
;
194 pool
->mask
[byte
] |= 1 << bit
;
206 DBG1(DBG_CFG
, "no address left in HA pool '%s' belonging to"
207 "a responsible segment", name
);
210 this->mutex
->unlock(this->mutex
);
213 address
= offset2host(pool
, offset
);
214 DBG1(DBG_CFG
, "acquired address %H from HA pool '%s'", address
, name
);
220 METHOD(attribute_provider_t
, release_address
, bool,
221 private_ha_attribute_t
*this, char *name
, host_t
*address
,
222 identification_t
*id
)
228 this->mutex
->lock(this->mutex
);
229 pool
= get_pool(this, name
);
232 offset
= host2offset(pool
, address
);
233 if (offset
> 0 && offset
< pool
->size
)
235 pool
->mask
[offset
/ 8] &= ~(1 << (offset
% 8));
236 DBG1(DBG_CFG
, "released address %H to HA pool '%s'", address
, name
);
240 this->mutex
->unlock(this->mutex
);
244 METHOD(ha_attribute_t
, reserve
, void,
245 private_ha_attribute_t
*this, char *name
, host_t
*address
)
250 this->mutex
->lock(this->mutex
);
251 pool
= get_pool(this, name
);
254 offset
= host2offset(pool
, address
);
255 if (offset
> 0 && offset
< pool
->size
)
257 pool
->mask
[offset
/ 8] |= 1 << (offset
% 8);
258 DBG1(DBG_CFG
, "reserved address %H in HA pool '%s'", address
, name
);
261 this->mutex
->unlock(this->mutex
);
264 METHOD(ha_attribute_t
, destroy
, void,
265 private_ha_attribute_t
*this)
267 this->pools
->destroy_function(this->pools
, (void*)pool_destroy
);
268 this->mutex
->destroy(this->mutex
);
273 * Load the configured pools.
275 static void load_pools(private_ha_attribute_t
*this)
277 enumerator_t
*enumerator
;
278 char *name
, *net
, *bits
;
283 enumerator
= lib
->settings
->create_key_value_enumerator(lib
->settings
,
284 "charon.plugins.ha.pools");
285 while (enumerator
->enumerate(enumerator
, &name
, &net
))
288 bits
= strchr(net
, '/');
291 DBG1(DBG_CFG
, "invalid HA pool '%s' subnet, skipped", name
);
297 base
= host_create_from_string(net
, 0);
303 DBG1(DBG_CFG
, "invalid HA pool '%s', skipped", name
);
306 maxbits
= base
->get_family(base
) == AF_INET
? 32 : 128;
307 mask
= maxbits
- mask
;
311 DBG1(DBG_CFG
, "size of HA pool '%s' limited to /%d",
312 name
, maxbits
- mask
);
316 DBG1(DBG_CFG
, "HA pool '%s' too small, skipped", name
);
322 .name
= strdup(name
),
326 pool
->mask
= calloc(pool
->size
/ 8, 1);
327 /* do not use first/last address of pool */
328 pool
->mask
[0] |= 0x01;
329 pool
->mask
[pool
->size
/ 8 - 1] |= 0x80;
331 DBG1(DBG_CFG
, "loaded HA pool '%s' %H/%d (%d addresses)",
332 pool
->name
, pool
->base
, maxbits
- mask
, pool
->size
- 2);
333 this->pools
->insert_last(this->pools
, pool
);
335 enumerator
->destroy(enumerator
);
341 ha_attribute_t
*ha_attribute_create(ha_kernel_t
*kernel
, ha_segments_t
*segments
)
343 private_ha_attribute_t
*this;
348 .acquire_address
= _acquire_address
,
349 .release_address
= _release_address
,
350 .create_attribute_enumerator
= enumerator_create_empty
,
355 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
356 .pools
= linked_list_create(),
358 .segments
= segments
,
363 return &this->public;