From: Martin Willi Date: Mon, 23 Sep 2013 10:10:07 +0000 (+0200) Subject: libipsec: Support usage statistics and query_sa() on IPsec SAs X-Git-Tag: 5.1.1rc1~47^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b08967d6d8b9377ac5cf375113c345b9b52d4f49;p=thirdparty%2Fstrongswan.git libipsec: Support usage statistics and query_sa() on IPsec SAs --- diff --git a/src/libipsec/ipsec_processor.c b/src/libipsec/ipsec_processor.c index eae2ed2f15..ee297a34b7 100644 --- a/src/libipsec/ipsec_processor.c +++ b/src/libipsec/ipsec_processor.c @@ -91,6 +91,7 @@ static void deliver_inbound(private_ipsec_processor_t *this, static job_requeue_t process_inbound(private_ipsec_processor_t *this) { esp_packet_t *packet; + ip_packet_t *ip_packet; ipsec_sa_t *sa; u_int8_t next_header; u_int32_t spi, reqid; @@ -126,6 +127,8 @@ static job_requeue_t process_inbound(private_ipsec_processor_t *this) packet->destroy(packet); return JOB_REQUEUE_DIRECT; } + ip_packet = packet->get_payload(packet); + sa->update_usestats(sa, ip_packet->get_encoding(ip_packet).len); reqid = sa->get_reqid(sa); ipsec->sas->checkin(ipsec->sas, sa); @@ -136,13 +139,11 @@ static job_requeue_t process_inbound(private_ipsec_processor_t *this) case IPPROTO_IPV6: { ipsec_policy_t *policy; - ip_packet_t *ip_packet; - ip_packet = packet->get_payload(packet); policy = ipsec->policies->find_by_packet(ipsec->policies, ip_packet, TRUE, reqid); if (policy) - { /* TODO-IPSEC: update policy/sa stats? */ + { deliver_inbound(this, packet); policy->destroy(policy); break; @@ -225,7 +226,7 @@ static job_requeue_t process_outbound(private_ipsec_processor_t *this) policy->destroy(policy); return JOB_REQUEUE_DIRECT; } - /* TODO-IPSEC: update policy/sa counters? */ + sa->update_usestats(sa, packet->get_encoding(packet).len); ipsec->sas->checkin(ipsec->sas, sa); policy->destroy(policy); send_outbound(this, esp_packet); diff --git a/src/libipsec/ipsec_sa.c b/src/libipsec/ipsec_sa.c index 2ff5cff55a..3fbe56240d 100644 --- a/src/libipsec/ipsec_sa.c +++ b/src/libipsec/ipsec_sa.c @@ -81,6 +81,18 @@ struct private_ipsec_sa_t { * ESP context */ esp_context_t *esp_context; + + /** + * Usage statistics + */ + struct { + /** last time of use */ + time_t time; + /** number of packets processed */ + u_int64_t packets; + /** number of bytes processed */ + u_int64_t bytes; + } use; }; METHOD(ipsec_sa_t, get_source, host_t*, @@ -145,6 +157,32 @@ METHOD(ipsec_sa_t, get_esp_context, esp_context_t*, return this->esp_context; } +METHOD(ipsec_sa_t, get_usestats, void, + private_ipsec_sa_t *this, u_int64_t *bytes, u_int64_t *packets, + time_t *time) +{ + if (bytes) + { + *bytes = this->use.bytes; + } + if (packets) + { + *packets = this->use.packets; + } + if (time) + { + *time = this->use.time; + } +} + +METHOD(ipsec_sa_t, update_usestats, void, + private_ipsec_sa_t *this, u_int32_t bytes) +{ + this->use.time = time_monotonic(NULL); + this->use.packets++; + this->use.bytes += bytes; +} + METHOD(ipsec_sa_t, match_by_spi_dst, bool, private_ipsec_sa_t *this, u_int32_t spi, host_t *dst) { @@ -227,6 +265,8 @@ ipsec_sa_t *ipsec_sa_create(u_int32_t spi, host_t *src, host_t *dst, .match_by_spi_src_dst = _match_by_spi_src_dst, .match_by_reqid = _match_by_reqid, .get_esp_context = _get_esp_context, + .get_usestats = _get_usestats, + .update_usestats = _update_usestats, }, .spi = spi, .src = src->clone(src), diff --git a/src/libipsec/ipsec_sa.h b/src/libipsec/ipsec_sa.h index dec688e687..9b77c80409 100644 --- a/src/libipsec/ipsec_sa.h +++ b/src/libipsec/ipsec_sa.h @@ -109,6 +109,23 @@ struct ipsec_sa_t { */ esp_context_t *(*get_esp_context)(ipsec_sa_t *this); + /** + * Get usage statistics for this SA. + * + * @param bytes receives number of processed bytes, or NULL + * @param packets receives number of processed packets, or NULL + * @param time receives last use time of this SA, or NULL + */ + void (*get_usestats)(ipsec_sa_t *this, u_int64_t *bytes, u_int64_t *packets, + time_t *time); + + /** + * Record en/decryption of a packet to update usage statistics. + * + * @param bytes length of packet processed + */ + void (*update_usestats)(ipsec_sa_t *this, u_int32_t bytes); + /** * Check if this SA matches all given parameters * diff --git a/src/libipsec/ipsec_sa_mgr.c b/src/libipsec/ipsec_sa_mgr.c index 928a53d50c..8da20cdc5e 100644 --- a/src/libipsec/ipsec_sa_mgr.c +++ b/src/libipsec/ipsec_sa_mgr.c @@ -530,6 +530,28 @@ METHOD(ipsec_sa_mgr_t, update_sa, status_t, return SUCCESS; } +METHOD(ipsec_sa_mgr_t, query_sa, status_t, + private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, mark_t mark, + u_int64_t *bytes, u_int64_t *packets, time_t *time) +{ + ipsec_sa_entry_t *entry = NULL; + + this->mutex->lock(this->mutex); + if (this->sas->find_first(this->sas, (void*)match_entry_by_spi_src_dst, + (void**)&entry, &spi, src, dst) == SUCCESS && + wait_for_entry(this, entry)) + { + entry->sa->get_usestats(entry->sa, bytes, packets, time); + /* checkin the entry */ + entry->locked = FALSE; + entry->condvar->signal(entry->condvar); + } + this->mutex->unlock(this->mutex); + + return entry ? SUCCESS : NOT_FOUND; +} + METHOD(ipsec_sa_mgr_t, del_sa, status_t, private_ipsec_sa_mgr_t *this, host_t *src, host_t *dst, u_int32_t spi, u_int8_t protocol, u_int16_t cpi, mark_t mark) @@ -653,6 +675,7 @@ ipsec_sa_mgr_t *ipsec_sa_mgr_create() .get_spi = _get_spi, .add_sa = _add_sa, .update_sa = _update_sa, + .query_sa = _query_sa, .del_sa = _del_sa, .checkout_by_spi = _checkout_by_spi, .checkout_by_reqid = _checkout_by_reqid, diff --git a/src/libipsec/ipsec_sa_mgr.h b/src/libipsec/ipsec_sa_mgr.h index e9ce5ee8fe..8c234cefa1 100644 --- a/src/libipsec/ipsec_sa_mgr.h +++ b/src/libipsec/ipsec_sa_mgr.h @@ -108,6 +108,23 @@ struct ipsec_sa_mgr_t { host_t *new_src, host_t *new_dst, bool encap, bool new_encap, mark_t mark); + /** + * Query the number of bytes processed by an SA from the SAD. + * + * @param src source address for this SA + * @param dst destination address for this SA + * @param spi SPI allocated by us or remote peer + * @param protocol protocol for this SA (ESP/AH) + * @param mark optional mark for this SA + * @param[out] bytes the number of bytes processed by SA + * @param[out] packets number of packets processed by SA + * @param[out] time last (monotonic) time of SA use + * @return SUCCESS if operation completed + */ + status_t (*query_sa)(ipsec_sa_mgr_t *this, host_t *src, host_t *dst, + u_int32_t spi, u_int8_t protocol, mark_t mark, + u_int64_t *bytes, u_int64_t *packets, time_t *time); + /** * Delete a previously added SA *