ipsec: manually binding an SA to a worker
[vpp.git] / src / vnet / ipsec / ipsec_api.c
index 73f4474..7fc68f6 100644 (file)
@@ -124,6 +124,7 @@ typedef struct ipsec_dump_walk_ctx_t_
 {
   vl_api_registration_t *reg;
   u32 context;
+  u32 sw_if_index;
 } ipsec_dump_walk_ctx_t;
 
 static walk_rc_t
@@ -232,7 +233,8 @@ static void vl_api_ipsec_spd_entry_add_del_t_handler
 
   p.is_ipv6 = (itype == IP46_TYPE_IP6);
 
-  p.protocol = mp->entry.protocol;
+  p.protocol =
+    mp->entry.protocol ? mp->entry.protocol : IPSEC_POLICY_PROTOCOL_ANY;
   p.rport.start = ntohs (mp->entry.remote_port_start);
   p.rport.stop = ntohs (mp->entry.remote_port_stop);
   p.lport.start = ntohs (mp->entry.local_port_start);
@@ -270,6 +272,65 @@ out:
   /* *INDENT-ON* */
 }
 
+static void
+vl_api_ipsec_spd_entry_add_del_v2_t_handler (
+  vl_api_ipsec_spd_entry_add_del_v2_t *mp)
+{
+  vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main ();
+  vl_api_ipsec_spd_entry_add_del_reply_t *rmp;
+  ip46_type_t itype;
+  u32 stat_index;
+  int rv;
+
+  stat_index = ~0;
+
+  ipsec_policy_t p;
+
+  clib_memset (&p, 0, sizeof (p));
+
+  p.id = ntohl (mp->entry.spd_id);
+  p.priority = ntohl (mp->entry.priority);
+
+  itype = ip_address_decode (&mp->entry.remote_address_start, &p.raddr.start);
+  ip_address_decode (&mp->entry.remote_address_stop, &p.raddr.stop);
+  ip_address_decode (&mp->entry.local_address_start, &p.laddr.start);
+  ip_address_decode (&mp->entry.local_address_stop, &p.laddr.stop);
+
+  p.is_ipv6 = (itype == IP46_TYPE_IP6);
+
+  p.protocol = mp->entry.protocol;
+  p.rport.start = ntohs (mp->entry.remote_port_start);
+  p.rport.stop = ntohs (mp->entry.remote_port_stop);
+  p.lport.start = ntohs (mp->entry.local_port_start);
+  p.lport.stop = ntohs (mp->entry.local_port_stop);
+
+  rv = ipsec_spd_action_decode (mp->entry.policy, &p.policy);
+
+  if (rv)
+    goto out;
+
+  /* policy action resolve unsupported */
+  if (p.policy == IPSEC_POLICY_ACTION_RESOLVE)
+    {
+      clib_warning ("unsupported action: 'resolve'");
+      rv = VNET_API_ERROR_UNIMPLEMENTED;
+      goto out;
+    }
+  p.sa_id = ntohl (mp->entry.sa_id);
+  rv =
+    ipsec_policy_mk_type (mp->entry.is_outbound, p.is_ipv6, p.policy, &p.type);
+  if (rv)
+    goto out;
+
+  rv = ipsec_add_del_policy (vm, &p, mp->is_add, &stat_index);
+  if (rv)
+    goto out;
+
+out:
+  REPLY_MACRO2 (VL_API_IPSEC_SPD_ENTRY_ADD_DEL_V2_REPLY,
+               ({ rmp->stat_index = ntohl (stat_index); }));
+}
+
 static void vl_api_ipsec_sad_entry_add_del_t_handler
   (vl_api_ipsec_sad_entry_add_del_t * mp)
 {
@@ -419,7 +480,7 @@ ipsec_sad_entry_add_v3 (const vl_api_ipsec_sad_entry_v3_t *entry,
   ipsec_protocol_t proto;
   ipsec_sa_flags_t flags;
   u32 id, spi;
-  tunnel_t tun;
+  tunnel_t tun = { 0 };
   int rv;
 
   id = ntohl (entry->sad_id);
@@ -506,6 +567,61 @@ vl_api_ipsec_sad_entry_add_t_handler (vl_api_ipsec_sad_entry_add_t *mp)
                { rmp->stat_index = htonl (sa_index); });
 }
 
+static void
+vl_api_ipsec_sad_entry_update_t_handler (vl_api_ipsec_sad_entry_update_t *mp)
+{
+  vl_api_ipsec_sad_entry_update_reply_t *rmp;
+  u32 id;
+  tunnel_t tun = { 0 };
+  int rv;
+
+  id = ntohl (mp->sad_id);
+
+  if (mp->is_tun)
+    {
+      rv = tunnel_decode (&mp->tunnel, &tun);
+
+      if (rv)
+       goto out;
+    }
+
+  rv = ipsec_sa_update (id, htons (mp->udp_src_port), htons (mp->udp_dst_port),
+                       &tun, mp->is_tun);
+
+out:
+  REPLY_MACRO (VL_API_IPSEC_SAD_ENTRY_UPDATE_REPLY);
+}
+
+static void
+vl_api_ipsec_sad_bind_t_handler (vl_api_ipsec_sad_bind_t *mp)
+{
+  vl_api_ipsec_sad_bind_reply_t *rmp;
+  u32 sa_id;
+  u32 worker;
+  int rv;
+
+  sa_id = ntohl (mp->sa_id);
+  worker = ntohl (mp->worker);
+
+  rv = ipsec_sa_bind (sa_id, worker, true /* bind */);
+
+  REPLY_MACRO (VL_API_IPSEC_SAD_BIND_REPLY);
+}
+
+static void
+vl_api_ipsec_sad_unbind_t_handler (vl_api_ipsec_sad_unbind_t *mp)
+{
+  vl_api_ipsec_sad_unbind_reply_t *rmp;
+  u32 sa_id;
+  int rv;
+
+  sa_id = ntohl (mp->sa_id);
+
+  rv = ipsec_sa_bind (sa_id, ~0, false /* bind */);
+
+  REPLY_MACRO (VL_API_IPSEC_SAD_UNBIND_REPLY);
+}
+
 static void
 send_ipsec_spds_details (ipsec_spd_t * spd, vl_api_registration_t * reg,
                         u32 context)
@@ -713,6 +829,9 @@ send_ipsec_itf_details (ipsec_itf_t *itf, void *arg)
   ipsec_dump_walk_ctx_t *ctx = arg;
   vl_api_ipsec_itf_details_t *mp;
 
+  if (~0 != ctx->sw_if_index && ctx->sw_if_index != itf->ii_sw_if_index)
+    return (WALK_CONTINUE);
+
   mp = vl_msg_api_alloc (sizeof (*mp));
   clib_memset (mp, 0, sizeof (*mp));
   mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_ITF_DETAILS);
@@ -738,6 +857,7 @@ vl_api_ipsec_itf_dump_t_handler (vl_api_ipsec_itf_dump_t * mp)
   ipsec_dump_walk_ctx_t ctx = {
     .reg = reg,
     .context = mp->context,
+    .sw_if_index = ntohl (mp->sw_if_index),
   };
 
   ipsec_itf_walk (send_ipsec_itf_details, &ctx);
@@ -826,11 +946,11 @@ send_ipsec_sa_details (ipsec_sa_t * sa, void *arg)
     }
 
   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
-  mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
+  mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
   if (ipsec_sa_is_set_USE_ESN (sa))
     {
       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
-      mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
+      mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
     }
   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
@@ -913,11 +1033,11 @@ send_ipsec_sa_v2_details (ipsec_sa_t * sa, void *arg)
   mp->entry.dscp = ip_dscp_encode (sa->tunnel.t_dscp);
 
   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
-  mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
+  mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
   if (ipsec_sa_is_set_USE_ESN (sa))
     {
       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
-      mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
+      mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
     }
   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
@@ -993,11 +1113,11 @@ send_ipsec_sa_v3_details (ipsec_sa_t *sa, void *arg)
     }
 
   mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
-  mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq));
+  mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
   if (ipsec_sa_is_set_USE_ESN (sa))
     {
       mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
-      mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->last_seq_hi));
+      mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
     }
   if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
     mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
@@ -1026,6 +1146,87 @@ vl_api_ipsec_sa_v3_dump_t_handler (vl_api_ipsec_sa_v3_dump_t *mp)
   ipsec_sa_walk (send_ipsec_sa_v3_details, &ctx);
 }
 
+static walk_rc_t
+send_ipsec_sa_v4_details (ipsec_sa_t *sa, void *arg)
+{
+  ipsec_dump_walk_ctx_t *ctx = arg;
+  vl_api_ipsec_sa_v4_details_t *mp;
+
+  mp = vl_msg_api_alloc (sizeof (*mp));
+  clib_memset (mp, 0, sizeof (*mp));
+  mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SA_V4_DETAILS);
+  mp->context = ctx->context;
+
+  mp->entry.sad_id = htonl (sa->id);
+  mp->entry.spi = htonl (sa->spi);
+  mp->entry.protocol = ipsec_proto_encode (sa->protocol);
+
+  mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
+  ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
+
+  mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
+  ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
+
+  mp->entry.flags = ipsec_sad_flags_encode (sa);
+  mp->entry.salt = clib_host_to_net_u32 (sa->salt);
+
+  if (ipsec_sa_is_set_IS_PROTECT (sa))
+    {
+      ipsec_sa_dump_match_ctx_t ctx = {
+       .sai = sa - ipsec_sa_pool,
+       .sw_if_index = ~0,
+      };
+      ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
+
+      mp->sw_if_index = htonl (ctx.sw_if_index);
+    }
+  else
+    mp->sw_if_index = ~0;
+
+  if (ipsec_sa_is_set_IS_TUNNEL (sa))
+    tunnel_encode (&sa->tunnel, &mp->entry.tunnel);
+
+  if (ipsec_sa_is_set_UDP_ENCAP (sa))
+    {
+      mp->entry.udp_src_port = sa->udp_hdr.src_port;
+      mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
+    }
+
+  mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
+  mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
+  if (ipsec_sa_is_set_USE_ESN (sa))
+    {
+      mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
+      mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
+    }
+  if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
+    mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
+
+  mp->thread_index = clib_host_to_net_u32 (sa->thread_index);
+  mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
+
+  vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+  return (WALK_CONTINUE);
+}
+
+static void
+vl_api_ipsec_sa_v4_dump_t_handler (vl_api_ipsec_sa_v4_dump_t *mp)
+{
+  vl_api_registration_t *reg;
+
+  reg = vl_api_client_index_to_registration (mp->client_index);
+  if (!reg)
+    return;
+
+  ipsec_dump_walk_ctx_t ctx = {
+    .reg = reg,
+    .context = mp->context,
+  };
+
+  ipsec_sa_walk (send_ipsec_sa_v4_details, &ctx);
+}
+
 static void
 vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t * mp)
 {