fixed some rekey collision issues
added retry with jitter when rekeying fails
This commit is contained in:
@@ -72,6 +72,16 @@
|
||||
*/
|
||||
#define KEEPALIVE_INTERVAL 20
|
||||
|
||||
/**
|
||||
* retry interval in seconds.
|
||||
*/
|
||||
#define RETRY_INTERVAL 15
|
||||
|
||||
/**
|
||||
* jitter to user for retrying
|
||||
*/
|
||||
#define RETRY_JITTER 5
|
||||
|
||||
|
||||
typedef struct private_configuration_t private_configuration_t;
|
||||
|
||||
@@ -118,6 +128,14 @@ static u_int32_t get_keepalive_interval (private_configuration_t *this)
|
||||
return KEEPALIVE_INTERVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.get_retry_interval.
|
||||
*/
|
||||
static u_int32_t get_retry_interval (private_configuration_t *this)
|
||||
{
|
||||
return RETRY_INTERVAL - (random() % RETRY_JITTER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of configuration_t.destroy.
|
||||
*/
|
||||
@@ -138,6 +156,7 @@ configuration_t *configuration_create()
|
||||
this->public.get_retransmit_timeout = (u_int32_t (*) (configuration_t*,u_int32_t))get_retransmit_timeout;
|
||||
this->public.get_half_open_ike_sa_timeout = (u_int32_t (*) (configuration_t*)) get_half_open_ike_sa_timeout;
|
||||
this->public.get_keepalive_interval = (u_int32_t (*) (configuration_t*)) get_keepalive_interval;
|
||||
this->public.get_retry_interval = (u_int32_t (*) (configuration_t*)) get_retry_interval;
|
||||
|
||||
return (&this->public);
|
||||
}
|
||||
|
||||
@@ -61,16 +61,27 @@ struct configuration_t {
|
||||
u_int32_t (*get_half_open_ike_sa_timeout) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Returns the keepalive interval in ms.
|
||||
* @brief Returns the keepalive interval in s.
|
||||
*
|
||||
* The keepalive interval defines the idle time after which a
|
||||
* NAT keepalive packet should be sent.
|
||||
*
|
||||
* @param this calling object
|
||||
* @return interval in seconds
|
||||
* @return interval in s
|
||||
*/
|
||||
u_int32_t (*get_keepalive_interval) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Returns the interval to retry a failed action again.
|
||||
*
|
||||
* In some situations, the protocol may be in a state where processing
|
||||
* is not possible and an action must be retried (e.g. rekeying).
|
||||
*
|
||||
* @param this calling object
|
||||
* @return interval in s
|
||||
*/
|
||||
u_int32_t (*get_retry_interval) (configuration_t *this);
|
||||
|
||||
/**
|
||||
* @brief Destroys a configuration_t object.
|
||||
*
|
||||
|
||||
@@ -444,43 +444,43 @@ static void handle_collisions(private_task_manager_t *this, task_t *task)
|
||||
|
||||
type = task->get_type(task);
|
||||
|
||||
/* check if we have initiated rekeying ourself */
|
||||
if (this->initiating.type != CREATE_CHILD_SA ||
|
||||
(type != IKE_REKEY && type != CHILD_REKEY && type != CHILD_DELETE))
|
||||
{
|
||||
task->destroy(task);
|
||||
return;
|
||||
/* do we have to check */
|
||||
if (type == IKE_REKEY || type == CHILD_REKEY ||
|
||||
type == CHILD_DELETE || type == IKE_DELETE)
|
||||
{
|
||||
/* find an exchange collision, and notify these tasks */
|
||||
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&active))
|
||||
{
|
||||
switch (active->get_type(active))
|
||||
{
|
||||
case IKE_REKEY:
|
||||
if (type == IKE_REKEY || type == IKE_DELETE)
|
||||
{
|
||||
ike_rekey_t *rekey = (ike_rekey_t*)active;
|
||||
rekey->collide(rekey, task);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case CHILD_REKEY:
|
||||
/* TODO: check if it is the SAME child we are talking about! */
|
||||
if (type == CHILD_REKEY || type == CHILD_DELETE)
|
||||
{
|
||||
child_rekey_t *rekey = (child_rekey_t*)active;
|
||||
rekey->collide(rekey, task);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
return;
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
}
|
||||
|
||||
/* find an exchange collision, and notify these tasks */
|
||||
iterator = this->active_tasks->create_iterator(this->active_tasks, TRUE);
|
||||
while (iterator->iterate(iterator, (void**)&active))
|
||||
{
|
||||
switch (active->get_type(active))
|
||||
{
|
||||
case IKE_REKEY:
|
||||
if (type == IKE_REKEY || type == IKE_DELETE)
|
||||
{
|
||||
ike_rekey_t *rekey = (ike_rekey_t*)active;
|
||||
rekey->collide(rekey, task);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case CHILD_REKEY:
|
||||
/* TODO: check if it is the SAME child we are talking about! */
|
||||
if (type == CHILD_REKEY || type == CHILD_DELETE)
|
||||
{
|
||||
child_rekey_t *rekey = (child_rekey_t*)active;
|
||||
rekey->collide(rekey, task);
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
iterator->destroy(iterator);
|
||||
/* destroy task if not registered in any active task */
|
||||
task->destroy(task);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -633,7 +633,6 @@ static status_t process_request(private_task_manager_t *this,
|
||||
task = (task_t*)ike_rekey_create(this->ike_sa, FALSE);
|
||||
}
|
||||
this->passive_tasks->insert_last(this->passive_tasks, task);
|
||||
|
||||
break;
|
||||
}
|
||||
case INFORMATIONAL:
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <daemon.h>
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <sa/tasks/child_create.h>
|
||||
#include <queues/jobs/rekey_child_sa_job.h>
|
||||
|
||||
|
||||
typedef struct private_child_rekey_t private_child_rekey_t;
|
||||
@@ -165,12 +166,10 @@ static status_t build_r(private_child_rekey_t *this, message_t *message)
|
||||
{
|
||||
/* rekeying failed, reuse old child */
|
||||
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
|
||||
/* TODO: reschedule rekeying */
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
this->child_sa->set_state(this->child_sa, CHILD_REKEYING);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -191,8 +190,17 @@ static status_t process_i(private_child_rekey_t *this, message_t *message)
|
||||
if (!(this->collision &&
|
||||
this->collision->get_type(this->collision) == CHILD_DELETE))
|
||||
{
|
||||
job_t *job;
|
||||
u_int32_t retry = charon->configuration->get_retry_interval(
|
||||
charon->configuration);
|
||||
job = (job_t*)rekey_child_sa_job_create(
|
||||
this->child_sa->get_reqid(this->child_sa),
|
||||
this->child_sa->get_protocol(this->child_sa),
|
||||
this->child_sa->get_spi(this->child_sa, TRUE));
|
||||
DBG1(DBG_IKE, "CHILD_SA rekeying failed, "
|
||||
"trying again in %d seconds", retry);
|
||||
this->child_sa->set_state(this->child_sa, CHILD_INSTALLED);
|
||||
/* TODO: rescedule rekeying */
|
||||
charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <encoding/payloads/notify_payload.h>
|
||||
#include <sa/tasks/ike_init.h>
|
||||
#include <queues/jobs/delete_ike_sa_job.h>
|
||||
#include <queues/jobs/rekey_ike_sa_job.h>
|
||||
|
||||
|
||||
typedef struct private_ike_rekey_t private_ike_rekey_t;
|
||||
@@ -180,8 +181,15 @@ static status_t process_i(private_ike_rekey_t *this, message_t *message)
|
||||
if (!(this->collision &&
|
||||
this->collision->get_type(this->collision) == IKE_DELETE))
|
||||
{
|
||||
job_t *job;
|
||||
u_int32_t retry = charon->configuration->get_retry_interval(
|
||||
charon->configuration);
|
||||
job = (job_t*)rekey_ike_sa_job_create(
|
||||
this->ike_sa->get_id(this->ike_sa), FALSE);
|
||||
DBG1(DBG_IKE, "IKE_SA rekeying failed, "
|
||||
"trying again in %d seconds", retry);
|
||||
this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED);
|
||||
/* TODO: reschedule rekeying */
|
||||
charon->event_queue->add_relative(charon->event_queue, job, retry * 1000);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user