ipsec: make chacha20-poly1305 available via API
[vpp.git] / src / vnet / ipsec / ipsec_sa.c
index 0a24aa2..a330abc 100644 (file)
@@ -28,7 +28,12 @@ vlib_combined_counter_main_t ipsec_sa_counters = {
   .name = "SA",
   .stat_segment_name = "/net/ipsec/sa",
 };
+vlib_simple_counter_main_t ipsec_sa_lost_counters = {
+  .name = "SA-lost",
+  .stat_segment_name = "/net/ipsec/sa/lost",
+};
 
+ipsec_sa_t *ipsec_sa_pool;
 
 static clib_error_t *
 ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa,
@@ -99,7 +104,8 @@ ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg)
   sa->crypto_calg = im->crypto_algs[crypto_alg].alg;
   ASSERT (sa->crypto_iv_size <= ESP_MAX_IV_SIZE);
   ASSERT (sa->esp_block_align <= ESP_MAX_BLOCK_SIZE);
-  if (IPSEC_CRYPTO_ALG_IS_GCM (crypto_alg))
+  if (IPSEC_CRYPTO_ALG_IS_GCM (crypto_alg) ||
+      IPSEC_CRYPTO_ALG_CTR_AEAD_OTHERS (crypto_alg))
     {
       sa->integ_icv_size = im->crypto_algs[crypto_alg].icv_size;
       ipsec_sa_set_IS_CTR (sa);
@@ -184,14 +190,16 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
   if (p)
     return VNET_API_ERROR_ENTRY_ALREADY_EXISTS;
 
-  pool_get_aligned_zero (im->sad, sa, CLIB_CACHE_LINE_BYTES);
+  pool_get_aligned_zero (ipsec_sa_pool, sa, CLIB_CACHE_LINE_BYTES);
 
   fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA);
   fib_node_lock (&sa->node);
-  sa_index = sa - im->sad;
+  sa_index = sa - ipsec_sa_pool;
 
   vlib_validate_combined_counter (&ipsec_sa_counters, sa_index);
   vlib_zero_combined_counter (&ipsec_sa_counters, sa_index);
+  vlib_validate_simple_counter (&ipsec_sa_lost_counters, sa_index);
+  vlib_zero_simple_counter (&ipsec_sa_lost_counters, sa_index);
 
   tunnel_copy (tun, &sa->tunnel);
   sa->id = id;
@@ -216,7 +224,7 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
                                              (u8 *) ck->data, ck->len);
   if (~0 == sa->crypto_key_index)
     {
-      pool_put (im->sad, sa);
+      pool_put (ipsec_sa_pool, sa);
       return VNET_API_ERROR_KEY_LENGTH;
     }
 
@@ -228,7 +236,7 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
                                                 (u8 *) ik->data, ik->len);
       if (~0 == sa->integ_key_index)
        {
-         pool_put (im->sad, sa);
+         pool_put (ipsec_sa_pool, sa);
          return VNET_API_ERROR_KEY_LENGTH;
        }
     }
@@ -244,23 +252,35 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
   if (im->async_mode)
     sa->crypto_op_data = sa->async_op_data.data;
   else
-    sa->crypto_op_data = sa->sync_op_data.data;
+    {
+      if (ipsec_sa_is_set_IS_ASYNC (sa))
+       {
+         vnet_crypto_request_async_mode (1);
+         sa->crypto_op_data = sa->async_op_data.data;
+       }
+      else
+       sa->crypto_op_data = sa->sync_op_data.data;
+    }
 
   err = ipsec_check_support_cb (im, sa);
   if (err)
     {
       clib_warning ("%s", err->what);
-      pool_put (im->sad, sa);
+      pool_put (ipsec_sa_pool, sa);
       return VNET_API_ERROR_UNIMPLEMENTED;
     }
 
   err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
   if (err)
     {
-      pool_put (im->sad, sa);
+      pool_put (ipsec_sa_pool, sa);
       return VNET_API_ERROR_SYSCALL_ERROR_1;
     }
 
+  if (ipsec_sa_is_set_IS_TUNNEL (sa) &&
+      AF_IP6 == ip_addr_version (&tun->t_src))
+    ipsec_sa_set_IS_TUNNEL_V6 (sa);
+
   if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa))
     {
       sa->tunnel_flags = sa->tunnel.t_encap_decap_flags;
@@ -269,7 +289,7 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
 
       if (rv)
        {
-         pool_put (im->sad, sa);
+         pool_put (ipsec_sa_pool, sa);
          return rv;
        }
       ipsec_sa_stack (sa);
@@ -306,7 +326,8 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
        sa->udp_hdr.src_port = clib_host_to_net_u16 (src_port);
 
       if (ipsec_sa_is_set_IS_INBOUND (sa))
-       ipsec_register_udp_port (clib_host_to_net_u16 (sa->udp_hdr.dst_port));
+       ipsec_register_udp_port (clib_host_to_net_u16 (sa->udp_hdr.dst_port),
+                                !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
     }
 
   hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
@@ -324,34 +345,36 @@ ipsec_sa_del (ipsec_sa_t * sa)
   ipsec_main_t *im = &ipsec_main;
   u32 sa_index;
 
-  sa_index = sa - im->sad;
+  sa_index = sa - ipsec_sa_pool;
   hash_unset (im->sa_index_by_sa_id, sa->id);
   tunnel_unresolve (&sa->tunnel);
 
   /* no recovery possible when deleting an SA */
   (void) ipsec_call_add_del_callbacks (im, sa, sa_index, 0);
 
+  if (ipsec_sa_is_set_IS_ASYNC (sa))
+    vnet_crypto_request_async_mode (0);
   if (ipsec_sa_is_set_UDP_ENCAP (sa) && ipsec_sa_is_set_IS_INBOUND (sa))
-    ipsec_unregister_udp_port (clib_net_to_host_u16 (sa->udp_hdr.dst_port));
+    ipsec_unregister_udp_port (clib_net_to_host_u16 (sa->udp_hdr.dst_port),
+                              !ipsec_sa_is_set_IS_TUNNEL_V6 (sa));
 
   if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa))
     dpo_reset (&sa->dpo);
   vnet_crypto_key_del (vm, sa->crypto_key_index);
   if (sa->integ_alg != IPSEC_INTEG_ALG_NONE)
     vnet_crypto_key_del (vm, sa->integ_key_index);
-  pool_put (im->sad, sa);
+  pool_put (ipsec_sa_pool, sa);
 }
 
 void
 ipsec_sa_unlock (index_t sai)
 {
-  ipsec_main_t *im = &ipsec_main;
   ipsec_sa_t *sa;
 
   if (INDEX_INVALID == sai)
     return;
 
-  sa = pool_elt_at_index (im->sad, sai);
+  sa = ipsec_sa_get (sai);
 
   fib_node_unlock (&sa->node);
 }
@@ -359,13 +382,12 @@ ipsec_sa_unlock (index_t sai)
 void
 ipsec_sa_lock (index_t sai)
 {
-  ipsec_main_t *im = &ipsec_main;
   ipsec_sa_t *sa;
 
   if (INDEX_INVALID == sai)
     return;
 
-  sa = pool_elt_at_index (im->sad, sai);
+  sa = ipsec_sa_get (sai);
 
   fib_node_lock (&sa->node);
 }
@@ -382,7 +404,7 @@ ipsec_sa_find_and_lock (u32 id)
   if (!p)
     return INDEX_INVALID;
 
-  sa = pool_elt_at_index (im->sad, p[0]);
+  sa = ipsec_sa_get (p[0]);
 
   fib_node_lock (&sa->node);
 
@@ -409,20 +431,20 @@ void
 ipsec_sa_clear (index_t sai)
 {
   vlib_zero_combined_counter (&ipsec_sa_counters, sai);
+  vlib_zero_simple_counter (&ipsec_sa_lost_counters, sai);
 }
 
 void
 ipsec_sa_walk (ipsec_sa_walk_cb_t cb, void *ctx)
 {
-  ipsec_main_t *im = &ipsec_main;
   ipsec_sa_t *sa;
 
   /* *INDENT-OFF* */
-  pool_foreach (sa, im->sad)
-   {
-    if (WALK_CONTINUE != cb(sa, ctx))
-      break;
-  }
+  pool_foreach (sa, ipsec_sa_pool)
+    {
+      if (WALK_CONTINUE != cb (sa, ctx))
+       break;
+    }
   /* *INDENT-ON* */
 }
 
@@ -432,11 +454,9 @@ ipsec_sa_walk (ipsec_sa_walk_cb_t cb, void *ctx)
 static fib_node_t *
 ipsec_sa_fib_node_get (fib_node_index_t index)
 {
-  ipsec_main_t *im;
   ipsec_sa_t *sa;
 
-  im = &ipsec_main;
-  sa = pool_elt_at_index (im->sad, index);
+  sa = ipsec_sa_get (index);
 
   return (&sa->node);
 }