Merge branch 'accounting-fixes'

This fixes the usage stats reported via RADIUS Accounting in several
corner cases (e.g. with interim updates while rekeying a CHILD_SA).

Fixes #891.
This commit is contained in:
Tobias Brunner
2015-05-21 15:40:05 +02:00
8 changed files with 412 additions and 56 deletions
+33 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011-2014 Tobias Brunner * Copyright (C) 2011-2015 Tobias Brunner
* Copyright (C) 2006 Martin Willi * Copyright (C) 2006 Martin Willi
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
@@ -687,6 +687,37 @@ METHOD(bus_t, child_rekey, void,
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
} }
METHOD(bus_t, children_migrate, void,
private_bus_t *this, ike_sa_id_t *new, u_int32_t unique)
{
enumerator_t *enumerator;
ike_sa_t *ike_sa;
entry_t *entry;
bool keep;
ike_sa = this->thread_sa->get(this->thread_sa);
this->mutex->lock(this->mutex);
enumerator = this->listeners->create_enumerator(this->listeners);
while (enumerator->enumerate(enumerator, &entry))
{
if (entry->calling || !entry->listener->children_migrate)
{
continue;
}
entry->calling++;
keep = entry->listener->children_migrate(entry->listener, ike_sa, new,
unique);
entry->calling--;
if (!keep)
{
unregister_listener(this, entry, enumerator);
}
}
enumerator->destroy(enumerator);
this->mutex->unlock(this->mutex);
}
METHOD(bus_t, ike_updown, void, METHOD(bus_t, ike_updown, void,
private_bus_t *this, ike_sa_t *ike_sa, bool up) private_bus_t *this, ike_sa_t *ike_sa, bool up)
{ {
@@ -1038,6 +1069,7 @@ bus_t *bus_create()
.ike_reestablish_post = _ike_reestablish_post, .ike_reestablish_post = _ike_reestablish_post,
.child_updown = _child_updown, .child_updown = _child_updown,
.child_rekey = _child_rekey, .child_rekey = _child_rekey,
.children_migrate = _children_migrate,
.authorize = _authorize, .authorize = _authorize,
.narrow = _narrow, .narrow = _narrow,
.assign_vips = _assign_vips, .assign_vips = _assign_vips,
+9 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012-2014 Tobias Brunner * Copyright (C) 2012-2015 Tobias Brunner
* Copyright (C) 2006-2009 Martin Willi * Copyright (C) 2006-2009 Martin Willi
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
@@ -426,6 +426,14 @@ struct bus_t {
*/ */
void (*child_rekey)(bus_t *this, child_sa_t *old, child_sa_t *new); void (*child_rekey)(bus_t *this, child_sa_t *old, child_sa_t *new);
/**
* CHILD_SA migration hook.
*
* @param new ID of new SA when called for the old, NULL otherwise
* @param uniue unique ID of new SA when called for the old, 0 otherwise
*/
void (*children_migrate)(bus_t *this, ike_sa_id_t *new, u_int32_t unique);
/** /**
* Virtual IP assignment hook. * Virtual IP assignment hook.
* *
+16 -1
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2011-2014 Tobias Brunner * Copyright (C) 2011-2015 Tobias Brunner
* Copyright (C) 2009 Martin Willi * Copyright (C) 2009 Martin Willi
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
@@ -187,6 +187,21 @@ struct listener_t {
bool (*child_rekey)(listener_t *this, ike_sa_t *ike_sa, bool (*child_rekey)(listener_t *this, ike_sa_t *ike_sa,
child_sa_t *old, child_sa_t *new); child_sa_t *old, child_sa_t *new);
/**
* Hook called when CHILD_SAs get migrated from one IKE_SA to another during
* IKEv1 reauthentication.
*
* This is called twice, once for the old IKE_SA before the CHILD_SAs are
* removed, and once for the new IKE_SA just after they got added.
*
* @param ike_sa new or old IKE_SA
* @param new ID of new SA when called for the old, NULL otherwise
* @param unique unique ID of new SA when called for the old, 0 otherwise
* @return TRUE to stay registered, FALSE to unregister
*/
bool (*children_migrate)(listener_t *this, ike_sa_t *ike_sa,
ike_sa_id_t *new, u_int32_t unique);
/** /**
* Hook called to invoke additional authorization rules. * Hook called to invoke additional authorization rules.
* *
@@ -1,4 +1,7 @@
/* /*
* Copyright (C) 2015 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* Copyright (C) 2012 Martin Willi * Copyright (C) 2012 Martin Willi
* Copyright (C) 2012 revosec AG * Copyright (C) 2012 revosec AG
* *
@@ -21,6 +24,7 @@
#include <radius_message.h> #include <radius_message.h>
#include <radius_client.h> #include <radius_client.h>
#include <daemon.h> #include <daemon.h>
#include <collections/array.h>
#include <collections/hashtable.h> #include <collections/hashtable.h>
#include <threading/mutex.h> #include <threading/mutex.h>
#include <processing/jobs/callback_job.h> #include <processing/jobs/callback_job.h>
@@ -92,6 +96,62 @@ typedef enum {
ACCT_CAUSE_HOST_REQUEST = 18, ACCT_CAUSE_HOST_REQUEST = 18,
} radius_acct_terminate_cause_t; } radius_acct_terminate_cause_t;
/**
* Usage stats for bytes and packets
*/
typedef struct {
struct {
u_int64_t sent;
u_int64_t received;
} bytes, packets;
} usage_t;
/**
* Add usage stats (modifies a)
*/
static inline void add_usage(usage_t *a, usage_t b)
{
a->bytes.sent += b.bytes.sent;
a->bytes.received += b.bytes.received;
a->packets.sent += b.packets.sent;
a->packets.received += b.packets.received;
}
/**
* Subtract usage stats (modifies a)
*/
static inline void sub_usage(usage_t *a, usage_t b)
{
a->bytes.sent -= b.bytes.sent;
a->bytes.received -= b.bytes.received;
a->packets.sent -= b.packets.sent;
a->packets.received -= b.packets.received;
}
/**
* Usage stats for a cached/migrated SAs
*/
typedef struct {
/** unique CHILD_SA identifier */
u_int32_t id;
/** usage stats for this SA */
usage_t usage;
} sa_entry_t;
/**
* Clone an sa_entry_t
*/
static sa_entry_t *clone_sa(sa_entry_t *sa)
{
sa_entry_t *this;
INIT(this,
.id = sa->id,
.usage = sa->usage,
);
return this;
}
/** /**
* Hashtable entry with usage stats * Hashtable entry with usage stats
*/ */
@@ -100,11 +160,12 @@ typedef struct {
ike_sa_id_t *id; ike_sa_id_t *id;
/** RADIUS accounting session ID */ /** RADIUS accounting session ID */
char sid[24]; char sid[24];
/** number of sent/received octets/packets */ /** number of sent/received octets/packets for expired SAs */
struct { usage_t usage;
u_int64_t sent; /** list of cached SAs, sa_entry_t (sorted by their unique ID) */
u_int64_t received; array_t *cached;
} bytes, packets; /** list of migrated SAs, sa_entry_t (sorted by their unique ID) */
array_t *migrated;
/** session creation time */ /** session creation time */
time_t created; time_t created;
/** terminate cause */ /** terminate cause */
@@ -123,6 +184,8 @@ typedef struct {
*/ */
static void destroy_entry(entry_t *this) static void destroy_entry(entry_t *this)
{ {
array_destroy_function(this->cached, (void*)free, NULL);
array_destroy_function(this->migrated, (void*)free, NULL);
this->id->destroy(this->id); this->id->destroy(this->id);
free(this); free(this);
} }
@@ -154,30 +217,157 @@ static bool equals(ike_sa_id_t *a, ike_sa_id_t *b)
return a->equals(a, b); return a->equals(a, b);
} }
/**
* Sort cached SAs
*/
static int sa_sort(const void *a, const void *b, void *user)
{
const sa_entry_t *ra = a, *rb = b;
return ra->id - rb->id;
}
/**
* Find a cached SA
*/
static int sa_find(const void *a, const void *b)
{
return sa_sort(a, b, NULL);
}
/**
* Update or create usage counters of a cached SA
*/
static void update_sa(entry_t *entry, u_int32_t id, usage_t usage)
{
sa_entry_t *sa, lookup;
lookup.id = id;
if (array_bsearch(entry->cached, &lookup, sa_find, &sa) == -1)
{
INIT(sa,
.id = id,
);
array_insert_create(&entry->cached, ARRAY_TAIL, sa);
array_sort(entry->cached, sa_sort, NULL);
}
sa->usage = usage;
}
/** /**
* Update usage counter when a CHILD_SA rekeys/goes down * Update usage counter when a CHILD_SA rekeys/goes down
*/ */
static void update_usage(private_eap_radius_accounting_t *this, static void update_usage(private_eap_radius_accounting_t *this,
ike_sa_t *ike_sa, child_sa_t *child_sa) ike_sa_t *ike_sa, child_sa_t *child_sa)
{ {
u_int64_t bytes_in, bytes_out, packets_in, packets_out; usage_t usage;
entry_t *entry; entry_t *entry;
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out, &packets_out); child_sa->get_usestats(child_sa, TRUE, NULL, &usage.bytes.received,
child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in, &packets_in); &usage.packets.received);
child_sa->get_usestats(child_sa, FALSE, NULL, &usage.bytes.sent,
&usage.packets.sent);
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa)); entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
if (entry) if (entry)
{ {
entry->bytes.sent += bytes_out; update_sa(entry, child_sa->get_unique_id(child_sa), usage);
entry->bytes.received += bytes_in;
entry->packets.sent += packets_out;
entry->packets.received += packets_in;
} }
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
} }
/**
* Collect usage stats for all CHILD_SAs of the given IKE_SA, optionally returns
* the total number of bytes and packets
*/
static array_t *collect_stats(ike_sa_t *ike_sa, usage_t *total)
{
enumerator_t *enumerator;
child_sa_t *child_sa;
array_t *stats;
sa_entry_t *sa;
usage_t usage;
if (total)
{
*total = (usage_t){};
}
stats = array_create(0, 0);
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
while (enumerator->enumerate(enumerator, &child_sa))
{
INIT(sa,
.id = child_sa->get_unique_id(child_sa),
);
array_insert(stats, ARRAY_TAIL, sa);
array_sort(stats, sa_sort, NULL);
child_sa->get_usestats(child_sa, TRUE, NULL, &usage.bytes.received,
&usage.packets.received);
child_sa->get_usestats(child_sa, FALSE, NULL, &usage.bytes.sent,
&usage.packets.sent);
sa->usage = usage;
if (total)
{
add_usage(total, usage);
}
}
enumerator->destroy(enumerator);
return stats;
}
/**
* Cleanup cached SAs
*/
static void cleanup_sas(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
entry_t *entry)
{
enumerator_t *enumerator;
child_sa_t *child_sa;
sa_entry_t *sa, *found;
array_t *sas;
sas = array_create(0, 0);
enumerator = ike_sa->create_child_sa_enumerator(ike_sa);
while (enumerator->enumerate(enumerator, &child_sa))
{
INIT(sa,
.id = child_sa->get_unique_id(child_sa),
);
array_insert(sas, ARRAY_TAIL, sa);
array_sort(sas, sa_sort, NULL);
}
enumerator->destroy(enumerator);
enumerator = array_create_enumerator(entry->cached);
while (enumerator->enumerate(enumerator, &sa))
{
if (array_bsearch(sas, sa, sa_find, &found) == -1)
{
/* SA is gone, add its latest stats to the total for this IKE_SA
* and remove the cache entry */
add_usage(&entry->usage, sa->usage);
array_remove_at(entry->cached, enumerator);
free(sa);
}
}
enumerator->destroy(enumerator);
enumerator = array_create_enumerator(entry->migrated);
while (enumerator->enumerate(enumerator, &sa))
{
if (array_bsearch(sas, sa, sa_find, &found) == -1)
{
/* SA is gone, subtract stats from the total for this IKE_SA */
sub_usage(&entry->usage, sa->usage);
array_remove_at(entry->migrated, enumerator);
free(sa);
}
}
enumerator->destroy(enumerator);
array_destroy_function(sas, (void*)free, NULL);
}
/** /**
* Send a RADIUS message, wait for response * Send a RADIUS message, wait for response
*/ */
@@ -273,17 +463,15 @@ static void add_ike_sa_parameters(private_eap_radius_accounting_t *this,
* Get an existing or create a new entry from the locked session table * Get an existing or create a new entry from the locked session table
*/ */
static entry_t* get_or_create_entry(private_eap_radius_accounting_t *this, static entry_t* get_or_create_entry(private_eap_radius_accounting_t *this,
ike_sa_t *ike_sa) ike_sa_id_t *id, u_int32_t unique)
{ {
ike_sa_id_t *id;
entry_t *entry; entry_t *entry;
time_t now; time_t now;
entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa)); entry = this->sessions->get(this->sessions, id);
if (!entry) if (!entry)
{ {
now = time_monotonic(NULL); now = time_monotonic(NULL);
id = ike_sa->get_id(ike_sa);
INIT(entry, INIT(entry,
.id = id->clone(id), .id = id->clone(id),
@@ -294,8 +482,7 @@ static entry_t* get_or_create_entry(private_eap_radius_accounting_t *this,
/* default terminate cause, if none other catched */ /* default terminate cause, if none other catched */
.cause = ACCT_CAUSE_USER_REQUEST, .cause = ACCT_CAUSE_USER_REQUEST,
); );
snprintf(entry->sid, sizeof(entry->sid), "%u-%u", snprintf(entry->sid, sizeof(entry->sid), "%u-%u", this->prefix, unique);
this->prefix, ike_sa->get_unique_id(ike_sa));
this->sessions->put(this->sessions, entry->id, entry); this->sessions->put(this->sessions, entry->id, entry);
} }
return entry; return entry;
@@ -330,31 +517,21 @@ void destroy_interim_data(interim_data_t *this)
static job_requeue_t send_interim(interim_data_t *data) static job_requeue_t send_interim(interim_data_t *data)
{ {
private_eap_radius_accounting_t *this = data->this; private_eap_radius_accounting_t *this = data->this;
u_int64_t bytes_in = 0, bytes_out = 0, packets_in = 0, packets_out = 0; usage_t usage;
u_int64_t bytes, packets;
radius_message_t *message = NULL; radius_message_t *message = NULL;
enumerator_t *enumerator; enumerator_t *enumerator;
child_sa_t *child_sa;
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
entry_t *entry; entry_t *entry;
u_int32_t value; u_int32_t value;
array_t *stats;
sa_entry_t *sa, *found;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, data->id); ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, data->id);
if (!ike_sa) if (!ike_sa)
{ {
return JOB_REQUEUE_NONE; return JOB_REQUEUE_NONE;
} }
enumerator = ike_sa->create_child_sa_enumerator(ike_sa); stats = collect_stats(ike_sa, &usage);
while (enumerator->enumerate(enumerator, &child_sa))
{
child_sa->get_usestats(child_sa, FALSE, NULL, &bytes, &packets);
bytes_out += bytes;
packets_out += packets;
child_sa->get_usestats(child_sa, TRUE, NULL, &bytes, &packets);
bytes_in += bytes;
packets_in += packets;
}
enumerator->destroy(enumerator);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
/* avoid any races by returning IKE_SA before acquiring lock */ /* avoid any races by returning IKE_SA before acquiring lock */
@@ -365,10 +542,45 @@ static job_requeue_t send_interim(interim_data_t *data)
{ {
entry->interim.last = time_monotonic(NULL); entry->interim.last = time_monotonic(NULL);
bytes_in += entry->bytes.received; enumerator = array_create_enumerator(entry->cached);
bytes_out += entry->bytes.sent; while (enumerator->enumerate(enumerator, &sa))
packets_in += entry->packets.received; {
packets_out += entry->packets.sent; if (array_bsearch(stats, sa, sa_find, &found) != -1)
{
/* SA is still around, update stats (e.g. for IKEv1 where
* SA might get used even after rekeying) */
sa->usage = found->usage;
}
else
{
/* SA is gone, add its last stats to the total for this IKE_SA
* and remove the cache entry */
add_usage(&entry->usage, sa->usage);
array_remove_at(entry->cached, enumerator);
free(sa);
}
}
enumerator->destroy(enumerator);
enumerator = array_create_enumerator(entry->migrated);
while (enumerator->enumerate(enumerator, &sa))
{
if (array_bsearch(stats, sa, sa_find, &found) != -1)
{
/* SA is still around, but we have to compensate */
sub_usage(&usage, sa->usage);
}
else
{
/* SA is gone, subtract stats from the total for this IKE_SA */
sub_usage(&entry->usage, sa->usage);
array_remove_at(entry->migrated, enumerator);
free(sa);
}
}
enumerator->destroy(enumerator);
add_usage(&usage, entry->usage);
message = radius_message_create(RMC_ACCOUNTING_REQUEST); message = radius_message_create(RMC_ACCOUNTING_REQUEST);
value = htonl(ACCT_STATUS_INTERIM_UPDATE); value = htonl(ACCT_STATUS_INTERIM_UPDATE);
@@ -377,26 +589,26 @@ static job_requeue_t send_interim(interim_data_t *data)
chunk_create(entry->sid, strlen(entry->sid))); chunk_create(entry->sid, strlen(entry->sid)));
add_ike_sa_parameters(this, message, ike_sa); add_ike_sa_parameters(this, message, ike_sa);
value = htonl(bytes_out); value = htonl(usage.bytes.sent);
message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
value = htonl(bytes_out >> 32); value = htonl(usage.bytes.sent >> 32);
if (value) if (value)
{ {
message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS, message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
chunk_from_thing(value)); chunk_from_thing(value));
} }
value = htonl(packets_out); value = htonl(usage.packets.sent);
message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value));
value = htonl(bytes_in); value = htonl(usage.bytes.received);
message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
value = htonl(bytes_in >> 32); value = htonl(usage.bytes.received >> 32);
if (value) if (value)
{ {
message->add(message, RAT_ACCT_INPUT_GIGAWORDS, message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
chunk_from_thing(value)); chunk_from_thing(value));
} }
value = htonl(packets_in); value = htonl(usage.packets.received);
message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value));
value = htonl(entry->interim.last - entry->created); value = htonl(entry->interim.last - entry->created);
@@ -405,6 +617,7 @@ static job_requeue_t send_interim(interim_data_t *data)
schedule_interim(this, entry); schedule_interim(this, entry);
} }
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
array_destroy_function(stats, (void*)free, NULL);
if (message) if (message)
{ {
@@ -479,7 +692,8 @@ static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
entry = get_or_create_entry(this, ike_sa); entry = get_or_create_entry(this, ike_sa->get_id(ike_sa),
ike_sa->get_unique_id(ike_sa));
entry->start_sent = TRUE; entry->start_sent = TRUE;
message = radius_message_create(RMC_ACCOUNTING_REQUEST); message = radius_message_create(RMC_ACCOUNTING_REQUEST);
@@ -515,7 +729,9 @@ static void send_start(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa) static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
{ {
radius_message_t *message; radius_message_t *message;
enumerator_t *enumerator;
entry_t *entry; entry_t *entry;
sa_entry_t *sa;
u_int32_t value; u_int32_t value;
this->mutex->lock(this->mutex); this->mutex->lock(this->mutex);
@@ -528,6 +744,20 @@ static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
destroy_entry(entry); destroy_entry(entry);
return; return;
} }
enumerator = array_create_enumerator(entry->cached);
while (enumerator->enumerate(enumerator, &sa))
{
add_usage(&entry->usage, sa->usage);
}
enumerator->destroy(enumerator);
enumerator = array_create_enumerator(entry->migrated);
while (enumerator->enumerate(enumerator, &sa))
{
sub_usage(&entry->usage, sa->usage);
}
enumerator->destroy(enumerator);
message = radius_message_create(RMC_ACCOUNTING_REQUEST); message = radius_message_create(RMC_ACCOUNTING_REQUEST);
value = htonl(ACCT_STATUS_STOP); value = htonl(ACCT_STATUS_STOP);
message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value)); message->add(message, RAT_ACCT_STATUS_TYPE, chunk_from_thing(value));
@@ -535,26 +765,26 @@ static void send_stop(private_eap_radius_accounting_t *this, ike_sa_t *ike_sa)
chunk_create(entry->sid, strlen(entry->sid))); chunk_create(entry->sid, strlen(entry->sid)));
add_ike_sa_parameters(this, message, ike_sa); add_ike_sa_parameters(this, message, ike_sa);
value = htonl(entry->bytes.sent); value = htonl(entry->usage.bytes.sent);
message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_OUTPUT_OCTETS, chunk_from_thing(value));
value = htonl(entry->bytes.sent >> 32); value = htonl(entry->usage.bytes.sent >> 32);
if (value) if (value)
{ {
message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS, message->add(message, RAT_ACCT_OUTPUT_GIGAWORDS,
chunk_from_thing(value)); chunk_from_thing(value));
} }
value = htonl(entry->packets.sent); value = htonl(entry->usage.packets.sent);
message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_OUTPUT_PACKETS, chunk_from_thing(value));
value = htonl(entry->bytes.received); value = htonl(entry->usage.bytes.received);
message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_INPUT_OCTETS, chunk_from_thing(value));
value = htonl(entry->bytes.received >> 32); value = htonl(entry->usage.bytes.received >> 32);
if (value) if (value)
{ {
message->add(message, RAT_ACCT_INPUT_GIGAWORDS, message->add(message, RAT_ACCT_INPUT_GIGAWORDS,
chunk_from_thing(value)); chunk_from_thing(value));
} }
value = htonl(entry->packets.received); value = htonl(entry->usage.packets.received);
message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value)); message->add(message, RAT_ACCT_INPUT_PACKETS, chunk_from_thing(value));
value = htonl(time_monotonic(NULL) - entry->created); value = htonl(time_monotonic(NULL) - entry->created);
@@ -660,6 +890,8 @@ METHOD(listener_t, ike_rekey, bool,
/* fire new interim update job, old gets invalid */ /* fire new interim update job, old gets invalid */
schedule_interim(this, entry); schedule_interim(this, entry);
cleanup_sas(this, new, entry);
entry = this->sessions->put(this->sessions, entry->id, entry); entry = this->sessions->put(this->sessions, entry->id, entry);
if (entry) if (entry)
{ {
@@ -675,8 +907,64 @@ METHOD(listener_t, child_rekey, bool,
private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, private_eap_radius_accounting_t *this, ike_sa_t *ike_sa,
child_sa_t *old, child_sa_t *new) child_sa_t *old, child_sa_t *new)
{ {
update_usage(this, ike_sa, old); entry_t *entry;
update_usage(this, ike_sa, old);
this->mutex->lock(this->mutex);
entry = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
if (entry)
{
cleanup_sas(this, ike_sa, entry);
}
this->mutex->unlock(this->mutex);
return TRUE;
}
METHOD(listener_t, children_migrate, bool,
private_eap_radius_accounting_t *this, ike_sa_t *ike_sa, ike_sa_id_t *new,
u_int32_t unique)
{
enumerator_t *enumerator;
sa_entry_t *sa, *sa_new, *cached;
entry_t *entry_old, *entry_new;
array_t *stats;
if (!new)
{
return TRUE;
}
stats = collect_stats(ike_sa, NULL);
this->mutex->lock(this->mutex);
entry_old = this->sessions->get(this->sessions, ike_sa->get_id(ike_sa));
if (entry_old)
{
entry_new = get_or_create_entry(this, new, unique);
enumerator = array_create_enumerator(stats);
while (enumerator->enumerate(enumerator, &sa))
{
/* if the SA was already rekeyed/cached we cache it too on the new
* SA to track it properly until it's finally gone */
if (array_bsearch(entry_old->cached, sa, sa_find, &cached) != -1)
{
sa_new = clone_sa(sa);
array_insert_create(&entry_new->cached, ARRAY_TAIL, sa_new);
array_sort(entry_new->cached, sa_sort, NULL);
}
/* if the SA was used, we store it to compensate on the new SA */
if (sa->usage.bytes.sent || sa->usage.bytes.received ||
sa->usage.packets.sent || sa->usage.packets.received)
{
sa_new = clone_sa(sa);
array_insert_create(&entry_new->migrated, ARRAY_TAIL, sa_new);
array_sort(entry_new->migrated, sa_sort, NULL);
/* store/update latest stats on old SA to report in Stop */
update_sa(entry_old, sa->id, sa->usage);
}
}
enumerator->destroy(enumerator);
}
this->mutex->unlock(this->mutex);
array_destroy_function(stats, (void*)free, NULL);
return TRUE; return TRUE;
} }
@@ -717,6 +1005,7 @@ eap_radius_accounting_t *eap_radius_accounting_create()
.message = _message_hook, .message = _message_hook,
.child_updown = _child_updown, .child_updown = _child_updown,
.child_rekey = _child_rekey, .child_rekey = _child_rekey,
.children_migrate = _children_migrate,
}, },
.destroy = _destroy, .destroy = _destroy,
}, },
@@ -759,7 +1048,8 @@ void eap_radius_accounting_start_interim(ike_sa_t *ike_sa, u_int32_t interval)
DBG1(DBG_CFG, "scheduling RADIUS Interim-Updates every %us", interval); DBG1(DBG_CFG, "scheduling RADIUS Interim-Updates every %us", interval);
singleton->mutex->lock(singleton->mutex); singleton->mutex->lock(singleton->mutex);
entry = get_or_create_entry(singleton, ike_sa); entry = get_or_create_entry(singleton, ike_sa->get_id(ike_sa),
ike_sa->get_unique_id(ike_sa));
entry->interim.interval = interval; entry->interim.interval = interval;
singleton->mutex->unlock(singleton->mutex); singleton->mutex->unlock(singleton->mutex);
} }
@@ -64,11 +64,13 @@ METHOD(job_t, execute, job_requeue_t,
ike_sa_id_t *id; ike_sa_id_t *id;
ike_sa_t *ike_sa; ike_sa_t *ike_sa;
child_sa_t *child_sa; child_sa_t *child_sa;
u_int32_t unique;
ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->id); ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->id);
if (ike_sa) if (ike_sa)
{ {
/* get what we need from new SA */ /* get what we need from new SA */
unique = ike_sa->get_unique_id(ike_sa);
me = ike_sa->get_my_host(ike_sa); me = ike_sa->get_my_host(ike_sa);
me = me->clone(me); me = me->clone(me);
other = ike_sa->get_other_host(ike_sa); other = ike_sa->get_other_host(ike_sa);
@@ -106,6 +108,7 @@ METHOD(job_t, execute, job_requeue_t,
other_id->equals(other_id, ike_sa->get_other_id(ike_sa)) && other_id->equals(other_id, ike_sa->get_other_id(ike_sa)) &&
cfg->equals(cfg, ike_sa->get_peer_cfg(ike_sa))) cfg->equals(cfg, ike_sa->get_peer_cfg(ike_sa)))
{ {
charon->bus->children_migrate(charon->bus, this->id, unique);
subenum = ike_sa->create_child_sa_enumerator(ike_sa); subenum = ike_sa->create_child_sa_enumerator(ike_sa);
while (subenum->enumerate(subenum, &child_sa)) while (subenum->enumerate(subenum, &child_sa))
{ {
@@ -176,6 +179,7 @@ METHOD(job_t, execute, job_requeue_t,
} }
charon->bus->assign_vips(charon->bus, ike_sa, TRUE); charon->bus->assign_vips(charon->bus, ike_sa, TRUE);
} }
charon->bus->children_migrate(charon->bus, NULL, 0);
charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa);
} }
} }
+3 -1
View File
@@ -1737,7 +1737,8 @@ static void adopt_children_and_vips(ike_sa_t *old, ike_sa_t *new)
host_t *vip; host_t *vip;
int chcount = 0, vipcount = 0; int chcount = 0, vipcount = 0;
charon->bus->children_migrate(charon->bus, new->get_id(new),
new->get_unique_id(new));
enumerator = old->create_child_sa_enumerator(old); enumerator = old->create_child_sa_enumerator(old);
while (enumerator->enumerate(enumerator, &child_sa)) while (enumerator->enumerate(enumerator, &child_sa))
{ {
@@ -1760,6 +1761,7 @@ static void adopt_children_and_vips(ike_sa_t *old, ike_sa_t *new)
/* ...trigger the analogous event on the new SA */ /* ...trigger the analogous event on the new SA */
charon->bus->set_sa(charon->bus, new); charon->bus->set_sa(charon->bus, new);
charon->bus->assign_vips(charon->bus, new, TRUE); charon->bus->assign_vips(charon->bus, new, TRUE);
charon->bus->children_migrate(charon->bus, NULL, 0);
charon->bus->set_sa(charon->bus, old); charon->bus->set_sa(charon->bus, old);
if (chcount || vipcount) if (chcount || vipcount)
+5
View File
@@ -1475,6 +1475,8 @@ METHOD(task_manager_t, queue_ike_reauth, void,
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
charon->bus->children_migrate(charon->bus, new->get_id(new),
new->get_unique_id(new));
enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa);
while (enumerator->enumerate(enumerator, &child_sa)) while (enumerator->enumerate(enumerator, &child_sa))
{ {
@@ -1482,6 +1484,9 @@ METHOD(task_manager_t, queue_ike_reauth, void,
new->add_child_sa(new, child_sa); new->add_child_sa(new, child_sa);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
charon->bus->set_sa(charon->bus, new);
charon->bus->children_migrate(charon->bus, NULL, 0);
charon->bus->set_sa(charon->bus, this->ike_sa);
if (!new->get_child_count(new)) if (!new->get_child_count(new))
{ /* check if a Quick Mode task is queued (UNITY_LOAD_BALANCE case) */ { /* check if a Quick Mode task is queued (UNITY_LOAD_BALANCE case) */
+1 -1
View File
@@ -482,7 +482,7 @@ METHOD(ipsec_sa_mgr_t, add_sa, status_t,
entry = create_entry(sa_new); entry = create_entry(sa_new);
schedule_expiration(this, entry); schedule_expiration(this, entry);
this->sas->insert_last(this->sas, entry); this->sas->insert_first(this->sas, entry);
this->mutex->unlock(this->mutex); this->mutex->unlock(this->mutex);
return SUCCESS; return SUCCESS;