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
18 #include <utils/hashtable.h>
19 #include <utils/linked_list.h>
20 #include <threading/mutex.h>
21 #include <processing/jobs/callback_job.h>
23 typedef struct private_ha_cache_t private_ha_cache_t
;
26 * Private data of an ha_cache_t object.
28 struct private_ha_cache_t
{
31 * Public ha_cache_t interface.
36 * Kernel helper functions
41 * Socket to send sync messages over
46 * Total number of segments
51 * cached entries (ike_sa_t, entry_t)
62 * Hashtable hash function
64 static u_int
hash(void *key
)
66 return (uintptr_t)key
;
70 * Hashtable equals function
72 static bool equals(void *a
, void *b
)
78 * Cache entry for an IKE_SA
81 /* segment this entry is associate to */
85 /* list of updates UPDATE message */
86 linked_list_t
*updates
;
87 /* last initiator mid */
89 /* last responder mid */
94 * Create a entry with an add message
96 static entry_t
*entry_create(ha_message_t
*add
)
102 .updates
= linked_list_create(),
110 static void entry_destroy(entry_t
*entry
)
112 entry
->updates
->destroy_offset(entry
->updates
,
113 offsetof(ha_message_t
, destroy
));
114 entry
->add
->destroy(entry
->add
);
115 DESTROY_IF(entry
->midi
);
116 DESTROY_IF(entry
->midr
);
120 METHOD(ha_cache_t
, cache
, void,
121 private_ha_cache_t
*this, ike_sa_t
*ike_sa
, ha_message_t
*message
)
125 this->mutex
->lock(this->mutex
);
126 switch (message
->get_type(message
))
129 entry
= entry_create(message
);
130 entry
= this->cache
->put(this->cache
, ike_sa
, entry
);
133 entry_destroy(entry
);
137 entry
= this->cache
->get(this->cache
, ike_sa
);
140 entry
->segment
= this->kernel
->get_segment(this->kernel
,
141 ike_sa
->get_other_host(ike_sa
));
142 entry
->updates
->insert_last(entry
->updates
, message
);
145 message
->destroy(message
);
147 case HA_IKE_MID_INITIATOR
:
148 entry
= this->cache
->get(this->cache
, ike_sa
);
151 DESTROY_IF(entry
->midi
);
152 entry
->midi
= message
;
155 message
->destroy(message
);
157 case HA_IKE_MID_RESPONDER
:
158 entry
= this->cache
->get(this->cache
, ike_sa
);
161 DESTROY_IF(entry
->midr
);
162 entry
->midr
= message
;
165 message
->destroy(message
);
168 entry
= this->cache
->remove(this->cache
, ike_sa
);
171 entry_destroy(entry
);
173 message
->destroy(message
);
176 message
->destroy(message
);
179 this->mutex
->unlock(this->mutex
);
182 METHOD(ha_cache_t
, delete_
, void,
183 private_ha_cache_t
*this, ike_sa_t
*ike_sa
)
187 entry
= this->cache
->remove(this->cache
, ike_sa
);
190 entry_destroy(entry
);
195 * Rekey all children of an IKE_SA
197 static status_t
rekey_children(ike_sa_t
*ike_sa
)
199 iterator_t
*iterator
;
200 child_sa_t
*child_sa
;
201 status_t status
= SUCCESS
;
203 iterator
= ike_sa
->create_child_sa_iterator(ike_sa
);
204 while (iterator
->iterate(iterator
, (void**)&child_sa
))
206 DBG1(DBG_CFG
, "resyncing CHILD_SA");
207 status
= ike_sa
->rekey_child_sa(ike_sa
, child_sa
->get_protocol(child_sa
),
208 child_sa
->get_spi(child_sa
, TRUE
));
209 if (status
== DESTROY_ME
)
214 iterator
->destroy(iterator
);
219 * Trigger rekeying of CHILD_SA in segment
221 static void rekey_segment(private_ha_cache_t
*this, u_int segment
)
224 enumerator_t
*enumerator
;
228 list
= linked_list_create();
230 enumerator
= charon
->ike_sa_manager
->create_enumerator(
231 charon
->ike_sa_manager
, TRUE
);
232 while (enumerator
->enumerate(enumerator
, &ike_sa
))
234 if (ike_sa
->get_state(ike_sa
) == IKE_ESTABLISHED
&&
235 this->kernel
->get_segment(this->kernel
,
236 ike_sa
->get_other_host(ike_sa
)) == segment
)
238 id
= ike_sa
->get_id(ike_sa
);
239 list
->insert_last(list
, id
->clone(id
));
242 enumerator
->destroy(enumerator
);
244 while (list
->remove_last(list
, (void**)&id
) == SUCCESS
)
246 ike_sa
= charon
->ike_sa_manager
->checkout(charon
->ike_sa_manager
, id
);
249 if (rekey_children(ike_sa
) != DESTROY_ME
)
251 charon
->ike_sa_manager
->checkin(
252 charon
->ike_sa_manager
, ike_sa
);
256 charon
->ike_sa_manager
->checkin_and_destroy(
257 charon
->ike_sa_manager
, ike_sa
);
265 METHOD(ha_cache_t
, resync
, void,
266 private_ha_cache_t
*this, u_int segment
)
268 enumerator_t
*enumerator
, *updates
;
271 ha_message_t
*message
;
273 DBG1(DBG_CFG
, "resyncing HA segment %d", segment
);
275 this->mutex
->lock(this->mutex
);
276 enumerator
= this->cache
->create_enumerator(this->cache
);
277 while (enumerator
->enumerate(enumerator
, &ike_sa
, &entry
))
279 if (entry
->segment
== segment
)
281 this->socket
->push(this->socket
, entry
->add
);
282 updates
= entry
->updates
->create_enumerator(entry
->updates
);
283 while (updates
->enumerate(updates
, &message
))
285 this->socket
->push(this->socket
, message
);
287 updates
->destroy(updates
);
290 this->socket
->push(this->socket
, entry
->midi
);
294 this->socket
->push(this->socket
, entry
->midr
);
298 enumerator
->destroy(enumerator
);
299 this->mutex
->unlock(this->mutex
);
301 rekey_segment(this, segment
);
305 * Request a resync of all segments
307 static job_requeue_t
request_resync(private_ha_cache_t
*this)
309 ha_message_t
*message
;
312 DBG1(DBG_CFG
, "requesting HA resynchronization");
314 message
= ha_message_create(HA_RESYNC
);
315 for (i
= 1; i
<= this->count
; i
++)
317 message
->add_attribute(message
, HA_SEGMENT
, i
);
319 this->socket
->push(this->socket
, message
);
320 message
->destroy(message
);
321 return JOB_REQUEUE_NONE
;
324 METHOD(ha_cache_t
, destroy
, void,
325 private_ha_cache_t
*this)
327 this->cache
->destroy(this->cache
);
328 this->mutex
->destroy(this->mutex
);
335 ha_cache_t
*ha_cache_create(ha_kernel_t
*kernel
, ha_socket_t
*socket
,
336 bool sync
, u_int count
)
338 private_ha_cache_t
*this;
350 .cache
= hashtable_create(hash
, equals
, 8),
351 .mutex
= mutex_create(MUTEX_TYPE_DEFAULT
),
356 /* request a resync as soon as we are up */
357 lib
->scheduler
->schedule_job(lib
->scheduler
, (job_t
*)
358 callback_job_create((callback_job_cb_t
)request_resync
,
359 this, NULL
, NULL
), 1);
361 return &this->public;