libipsec: Support usage statistics and query_sa() on IPsec SAs
authorMartin Willi <martin@revosec.ch>
Mon, 23 Sep 2013 10:10:07 +0000 (12:10 +0200)
committerMartin Willi <martin@revosec.ch>
Fri, 11 Oct 2013 08:23:17 +0000 (10:23 +0200)
src/libipsec/ipsec_processor.c
src/libipsec/ipsec_sa.c
src/libipsec/ipsec_sa.h
src/libipsec/ipsec_sa_mgr.c
src/libipsec/ipsec_sa_mgr.h

index eae2ed2..ee297a3 100644 (file)
@@ -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);
index 2ff5cff..3fbe562 100644 (file)
@@ -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),
index dec688e..9b77c80 100644 (file)
@@ -110,6 +110,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
         *
         * @param spi           SPI
index 928a53d..8da20cd 100644 (file)
@@ -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,
index e9ce5ee..8c234ce 100644 (file)
@@ -109,6 +109,23 @@ struct ipsec_sa_mgr_t {
                                                  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
         *
         * @param spi                   SPI of the SA