ikev2: add per SA stats
[vpp.git] / src / plugins / ikev2 / ikev2.c
index 7aaf4f3..9b13991 100644 (file)
@@ -28,6 +28,7 @@
 #include <plugins/ikev2/ikev2_priv.h>
 #include <openssl/sha.h>
 #include <vnet/ipsec/ipsec_punt.h>
+#include <plugins/ikev2/ikev2.api_enum.h>
 
 #define IKEV2_LIVENESS_RETRIES 3
 #define IKEV2_LIVENESS_PERIOD_CHECK 30
@@ -92,31 +93,6 @@ format_ikev2_gen_sa_error (u8 * s, va_list * args)
   return s;
 }
 
-#define foreach_ikev2_error \
-_(PROCESSED, "IKEv2 packets processed") \
-_(IKE_SA_INIT_RETRANSMIT, "IKE_SA_INIT retransmit ") \
-_(IKE_SA_INIT_IGNORE, "IKE_SA_INIT ignore (IKE SA already auth)") \
-_(IKE_REQ_RETRANSMIT, "IKE request retransmit") \
-_(IKE_REQ_IGNORE, "IKE request ignore (old msgid)") \
-_(NOT_IKEV2, "Non IKEv2 packets received") \
-_(BAD_LENGTH, "Bad packet length") \
-_(MALFORMED_PACKET, "Malformed packet") \
-_(NO_BUFF_SPACE, "No buffer space")
-
-typedef enum
-{
-#define _(sym,str) IKEV2_ERROR_##sym,
-  foreach_ikev2_error
-#undef _
-    IKEV2_N_ERROR,
-} ikev2_error_t;
-
-static char *ikev2_error_strings[] = {
-#define _(sym,string) string,
-  foreach_ikev2_error
-#undef _
-};
-
 typedef enum
 {
   IKEV2_NEXT_IP4_LOOKUP,
@@ -716,9 +692,8 @@ ikev2_check_payload_length (const ike_payload_header_t * ikep, int rlen,
 }
 
 static int
-ikev2_process_sa_init_req (vlib_main_t * vm,
-                          ikev2_sa_t * sa, ike_header_t * ike,
-                          udp_header_t * udp, u32 len)
+ikev2_process_sa_init_req (vlib_main_t *vm, ikev2_sa_t *sa, ike_header_t *ike,
+                          udp_header_t *udp, u32 len, u32 sw_if_index)
 {
   u8 nonce[IKEV2_NONCE_SIZE];
   int p = 0;
@@ -733,6 +708,7 @@ ikev2_process_sa_init_req (vlib_main_t * vm,
                       ip_addr_version (&sa->iaddr) == AF_IP4);
 
   sa->ispi = clib_net_to_host_u64 (ike->ispi);
+  sa->sw_if_index = sw_if_index;
 
   /* store whole IKE payload - needed for PSK auth */
   vec_reset_length (sa->last_sa_init_req_packet_data);
@@ -2264,8 +2240,8 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa,
 }
 
 static u32
-ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa,
-                       ike_header_t * ike, void *user, udp_header_t * udp)
+ikev2_generate_message (vlib_buffer_t *b, ikev2_sa_t *sa, ike_header_t *ike,
+                       void *user, udp_header_t *udp, ikev2_stats_t *stats)
 {
   ikev2_main_t *km = &ikev2_main;
   u16 buffer_data_size = vlib_buffer_get_default_data_size (km->vlib_main);
@@ -2448,7 +2424,16 @@ ikev2_generate_message (vlib_buffer_t * b, ikev2_sa_t * sa,
          vec_free (data);
          sa->unsupported_cp = 0;
        }
-      /* else send empty response */
+      else
+       /* else send empty response */
+       {
+         if (ike_hdr_is_response (ike))
+           {
+             ASSERT (stats != 0);
+             stats->n_keepalives++;
+             sa->stats.n_keepalives++;
+           }
+       }
     }
   else if (ike->exchange == IKEV2_EXCHANGE_CREATE_CHILD_SA)
     {
@@ -2631,6 +2616,7 @@ ikev2_retransmit_sa_init_one (ikev2_sa_t * sa, ike_header_t * ike,
          /* req is retransmit */
          if (sa->state == IKEV2_STATE_SA_INIT)
            {
+             sa->stats.n_init_retransmit++;
              tmp = (ike_header_t *) sa->last_sa_init_res_packet_data;
              u32 slen = clib_net_to_host_u32 (tmp->length);
              ike->ispi = tmp->ispi;
@@ -2708,6 +2694,7 @@ ikev2_retransmit_resp (ikev2_sa_t * sa, ike_header_t * ike)
   /* retransmitted req */
   if (msg_id == sa->last_msg_id)
     {
+      sa->stats.n_retransmit++;
       ike_header_t *tmp = (ike_header_t *) sa->last_res_packet_data;
       u32 slen = clib_net_to_host_u32 (tmp->length);
       ike->ispi = tmp->ispi;
@@ -2792,8 +2779,8 @@ ikev2_rewrite_v4_addrs (ikev2_sa_t * sa, ip4_header_t * ih)
 }
 
 static_always_inline void
-ikev2_set_ip_address (ikev2_sa_t * sa, const void *iaddr,
-                     const void *raddr, const int af)
+ikev2_set_ip_address (ikev2_sa_t *sa, const void *iaddr, const void *raddr,
+                     const ip_address_family_t af)
 {
   ip_address_set (&sa->raddr, raddr, af);
   ip_address_set (&sa->iaddr, iaddr, af);
@@ -2833,18 +2820,32 @@ ikev2_generate_sa_init_data_and_log (ikev2_sa_t * sa)
     ikev2_elog_error (IKEV2_GENERATE_SA_INIT_OK_ERR_UNSUPP_STR);
 }
 
+static void
+ikev2_update_stats (vlib_main_t *vm, u32 node_index, ikev2_stats_t *s)
+{
+  vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_KEEPALIVE,
+                              s->n_keepalives);
+  vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_REKEY_REQ,
+                              s->n_rekey_req);
+  vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_INIT_SA_REQ,
+                              s->n_sa_init_req);
+  vlib_node_increment_counter (vm, node_index, IKEV2_ERROR_IKE_AUTH_REQ,
+                              s->n_sa_auth_req);
+}
+
 static_always_inline uword
-ikev2_node_internal (vlib_main_t * vm,
-                    vlib_node_runtime_t * node, vlib_frame_t * frame,
-                    u8 is_ip4)
+ikev2_node_internal (vlib_main_t *vm, vlib_node_runtime_t *node,
+                    vlib_frame_t *frame, u8 is_ip4, u8 natt)
 {
   u32 n_left = frame->n_vectors, *from;
   ikev2_main_t *km = &ikev2_main;
   vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b;
   u16 nexts[VLIB_FRAME_SIZE], *next = nexts;
   ikev2_main_per_thread_data_t *ptd = ikev2_get_per_thread_data ();
+  ikev2_stats_t _stats, *stats = &_stats;
   int res;
 
+  clib_memset_u16 (stats, 0, sizeof (stats[0]) / sizeof (u16));
   from = vlib_frame_vector_args (frame);
   vlib_get_buffers (vm, from, bufs, n_left);
   b = bufs;
@@ -2862,15 +2863,9 @@ ikev2_node_internal (vlib_main_t * vm,
       ikev2_sa_t sa;           /* temporary store for SA */
       u32 rlen, slen = 0;
       int ip_hdr_sz = 0;
-      int is_req = 0, has_non_esp_marker = 0;
-
-      ASSERT (0 == b0->punt_reason
-             || (is_ip4
-                 && b0->punt_reason ==
-                 ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0]));
+      int is_req = 0;
 
-      if (is_ip4
-         && b0->punt_reason == ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0])
+      if (natt)
        {
          u8 *ptr = vlib_buffer_get_current (b0);
          ip40 = (ip4_header_t *) ptr;
@@ -2903,12 +2898,12 @@ ikev2_node_internal (vlib_main_t * vm,
       rlen = b0->current_length - ip_hdr_sz - sizeof (*udp0);
 
       /* check for non-esp marker */
-      if (*((u32 *) ike0) == 0)
+      if (natt)
        {
+         ASSERT (*((u32 *) ike0) == 0);
          ike0 =
            (ike_header_t *) ((u8 *) ike0 + sizeof (ikev2_non_esp_marker));
          rlen -= sizeof (ikev2_non_esp_marker);
-         has_non_esp_marker = 1;
        }
 
       if (clib_net_to_host_u32 (ike0->length) != rlen)
@@ -2932,6 +2927,8 @@ ikev2_node_internal (vlib_main_t * vm,
 
          if (ike_hdr_is_initiator (ike0))
            {
+             sa0->stats.n_sa_init_req++;
+             stats->n_sa_init_req++;
              if (ike0->rspi == 0)
                {
                  if (is_ip4)
@@ -2958,7 +2955,9 @@ ikev2_node_internal (vlib_main_t * vm,
                      goto dispatch0;
                    }
 
-                 res = ikev2_process_sa_init_req (vm, sa0, ike0, udp0, rlen);
+                 res = ikev2_process_sa_init_req (
+                   vm, sa0, ike0, udp0, rlen,
+                   vnet_buffer (b0)->sw_if_index[VLIB_RX]);
                  if (!res)
                    vlib_node_increment_counter (vm, node->node_index,
                                                 IKEV2_ERROR_MALFORMED_PACKET,
@@ -2977,7 +2976,8 @@ ikev2_node_internal (vlib_main_t * vm,
                      || sa0->state == IKEV2_STATE_NOTIFY_AND_DELETE)
                    {
                      ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
-                     slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0);
+                     slen =
+                       ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats);
                      if (~0 == slen)
                        vlib_node_increment_counter (vm, node->node_index,
                                                     IKEV2_ERROR_NO_BUFF_SPACE,
@@ -3028,8 +3028,8 @@ ikev2_node_internal (vlib_main_t * vm,
                          ike0->msgid =
                            clib_net_to_host_u32 (sai->last_init_msg_id);
                          sa0->last_init_msg_id = sai->last_init_msg_id + 1;
-                         slen =
-                           ikev2_generate_message (b0, sa0, ike0, 0, udp0);
+                         slen = ikev2_generate_message (b0, sa0, ike0, 0,
+                                                        udp0, stats);
                          if (~0 == slen)
                            vlib_node_increment_counter (vm,
                                                         node->node_index,
@@ -3100,8 +3100,11 @@ ikev2_node_internal (vlib_main_t * vm,
                }
              else
                {
+                 sa0->stats.n_sa_auth_req++;
+                 stats->n_sa_auth_req++;
                  ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
-                 slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0);
+                 slen =
+                   ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats);
                  if (~0 == slen)
                    vlib_node_increment_counter (vm, node->node_index,
                                                 IKEV2_ERROR_NO_BUFF_SPACE,
@@ -3173,7 +3176,8 @@ ikev2_node_internal (vlib_main_t * vm,
              if (ike_hdr_is_request (ike0))
                {
                  ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
-                 slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0);
+                 slen =
+                   ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats);
                  if (~0 == slen)
                    vlib_node_increment_counter (vm, node->node_index,
                                                 IKEV2_ERROR_NO_BUFF_SPACE,
@@ -3233,8 +3237,11 @@ ikev2_node_internal (vlib_main_t * vm,
                    }
                  else
                    {
+                     stats->n_rekey_req++;
+                     sa0->stats.n_rekey_req++;
                      ike0->flags = IKEV2_HDR_FLAG_RESPONSE;
-                     slen = ikev2_generate_message (b0, sa0, ike0, 0, udp0);
+                     slen =
+                       ikev2_generate_message (b0, sa0, ike0, 0, udp0, stats);
                      if (~0 == slen)
                        vlib_node_increment_counter (vm, node->node_index,
                                                     IKEV2_ERROR_NO_BUFF_SPACE,
@@ -3271,13 +3278,13 @@ ikev2_node_internal (vlib_main_t * vm,
              if (udp0->dst_port == clib_net_to_host_u16 (IKEV2_PORT_NATT)
                  && ikev2_natt_active (sa0))
                {
-                 if (!has_non_esp_marker)
+                 if (!natt)
                    slen = ikev2_insert_non_esp_marker (ike0, slen);
                }
            }
          else
            {
-             if (has_non_esp_marker)
+             if (natt)
                slen += sizeof (ikev2_non_esp_marker);
 
              u16 tp = udp0->dst_port;
@@ -3323,6 +3330,7 @@ ikev2_node_internal (vlib_main_t * vm,
       b += 1;
     }
 
+  ikev2_update_stats (vm, node->node_index, stats);
   vlib_node_increment_counter (vm, node->node_index,
                               IKEV2_ERROR_PROCESSED, frame->n_vectors);
   vlib_buffer_enqueue_to_next (vm, node, from, nexts, frame->n_vectors);
@@ -3332,13 +3340,20 @@ ikev2_node_internal (vlib_main_t * vm,
 static uword
 ikev2_ip4 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
-  return ikev2_node_internal (vm, node, frame, 1 /* is_ip4 */ );
+  return ikev2_node_internal (vm, node, frame, 1 /* is_ip4 */, 0);
+}
+
+static uword
+ikev2_ip4_natt (vlib_main_t *vm, vlib_node_runtime_t *node,
+               vlib_frame_t *frame)
+{
+  return ikev2_node_internal (vm, node, frame, 1 /* is_ip4 */, 1 /* natt */);
 }
 
 static uword
 ikev2_ip6 (vlib_main_t * vm, vlib_node_runtime_t * node, vlib_frame_t * frame)
 {
-  return ikev2_node_internal (vm, node, frame, 0 /* is_ip4 */ );
+  return ikev2_node_internal (vm, node, frame, 0 /* is_ip4 */, 0);
 }
 
 /* *INDENT-OFF* */
@@ -3349,8 +3364,25 @@ VLIB_REGISTER_NODE (ikev2_node_ip4,static) = {
   .format_trace = format_ikev2_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(ikev2_error_strings),
-  .error_strings = ikev2_error_strings,
+  .n_errors = IKEV2_N_ERROR,
+  .error_counters = ikev2_error_counters,
+
+  .n_next_nodes = IKEV2_IP4_N_NEXT,
+  .next_nodes = {
+    [IKEV2_NEXT_IP4_LOOKUP] = "ip4-lookup",
+    [IKEV2_NEXT_IP4_ERROR_DROP] = "error-drop",
+  },
+};
+
+VLIB_REGISTER_NODE (ikev2_node_ip4_natt,static) = {
+  .function = ikev2_ip4_natt,
+  .name = "ikev2-ip4-natt",
+  .vector_size = sizeof (u32),
+  .format_trace = format_ikev2_trace,
+  .type = VLIB_NODE_TYPE_INTERNAL,
+
+  .n_errors = IKEV2_N_ERROR,
+  .error_counters = ikev2_error_counters,
 
   .n_next_nodes = IKEV2_IP4_N_NEXT,
   .next_nodes = {
@@ -3366,8 +3398,8 @@ VLIB_REGISTER_NODE (ikev2_node_ip6,static) = {
   .format_trace = format_ikev2_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
 
-  .n_errors = ARRAY_LEN(ikev2_error_strings),
-  .error_strings = ikev2_error_strings,
+  .n_errors = IKEV2_N_ERROR,
+  .error_counters = ikev2_error_counters,
 
   .n_next_nodes = IKEV2_IP6_N_NEXT,
   .next_nodes = {
@@ -3703,7 +3735,7 @@ ikev2_initiate_delete_ike_sa_internal (vlib_main_t * vm,
       ike0->flags = 0;
       ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id);
       sa->last_init_msg_id += 1;
-      len = ikev2_generate_message (b0, sa, ike0, 0, 0);
+      len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0);
       if (~0 == len)
        return;
 
@@ -4373,7 +4405,7 @@ ikev2_delete_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa,
   sa->del->spi = csa->i_proposals->spi;
   ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id);
   sa->last_init_msg_id += 1;
-  len = ikev2_generate_message (b0, sa, ike0, 0, 0);
+  len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0);
   if (~0 == len)
     return;
 
@@ -4499,7 +4531,7 @@ ikev2_rekey_child_sa_internal (vlib_main_t * vm, ikev2_sa_t * sa,
   RAND_bytes ((u8 *) & proposals[0].spi, sizeof (proposals[0].spi));
   rekey->spi = proposals[0].spi;
   rekey->ispi = csa->i_proposals->spi;
-  len = ikev2_generate_message (b0, sa, ike0, proposals, 0);
+  len = ikev2_generate_message (b0, sa, ike0, proposals, 0, 0);
   if (~0 == len)
     return;
 
@@ -4664,9 +4696,9 @@ ikev2_init (vlib_main_t * vm)
   udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip4.index, 1);
   udp_register_dst_port (vm, IKEV2_PORT_NATT, ikev2_node_ip6.index, 0);
 
-  vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("ikev2-ip4");
+  vlib_punt_hdl_t punt_hdl = vlib_punt_client_register ("ikev2-ip4-natt");
   vlib_punt_register (punt_hdl, ipsec_punt_reason[IPSEC_PUNT_IP4_SPI_UDP_0],
-                     "ikev2-ip4");
+                     "ikev2-ip4-natt");
   ikev2_cli_reference ();
 
   km->log_level = IKEV2_LOG_ERROR;
@@ -4953,7 +4985,7 @@ ikev2_send_informational_request (ikev2_sa_t * sa)
   ike0->msgid = clib_host_to_net_u32 (sa->last_init_msg_id);
   ike0->flags = 0;
   sa->last_init_msg_id += 1;
-  len = ikev2_generate_message (b0, sa, ike0, 0, 0);
+  len = ikev2_generate_message (b0, sa, ike0, 0, 0, 0);
   if (~0 == len)
     return;