+ if (sa->async_op_data.crypto_async_enc_op_id &&
+ !ipsec_sa_is_set_IS_AEAD (sa))
+ { //AES-CBC & HMAC
+ sa->async_op_data.linked_key_index =
+ vnet_crypto_key_add_linked (vm, sa->crypto_key_index,
+ sa->integ_key_index);
+ }
+
+ if (im->async_mode)
+ sa->crypto_op_data = sa->async_op_data.data;
+ else
+ {
+ 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 (ipsec_sa_pool, sa);
+ return VNET_API_ERROR_UNIMPLEMENTED;
+ }
+
+ err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1);
+ if (err)
+ {
+ pool_put (ipsec_sa_pool, sa);
+ return VNET_API_ERROR_SYSCALL_ERROR_1;
+ }
+
+ if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa))
+ {
+ sa->tunnel_flags = sa->tunnel.t_encap_decap_flags;
+
+ rv = tunnel_resolve (&sa->tunnel, FIB_NODE_TYPE_IPSEC_SA, sa_index);
+
+ if (rv)
+ {
+ pool_put (ipsec_sa_pool, sa);
+ return rv;
+ }
+ ipsec_sa_stack (sa);
+
+ /* generate header templates */
+ if (ipsec_sa_is_set_IS_TUNNEL_V6 (sa))
+ {
+ tunnel_build_v6_hdr (&sa->tunnel,
+ (ipsec_sa_is_set_UDP_ENCAP (sa) ?
+ IP_PROTOCOL_UDP :
+ IP_PROTOCOL_IPSEC_ESP),
+ &sa->ip6_hdr);
+ }
+ else
+ {
+ tunnel_build_v4_hdr (&sa->tunnel,
+ (ipsec_sa_is_set_UDP_ENCAP (sa) ?
+ IP_PROTOCOL_UDP :
+ IP_PROTOCOL_IPSEC_ESP),
+ &sa->ip4_hdr);
+ }
+ }
+
+ if (ipsec_sa_is_set_UDP_ENCAP (sa))
+ {
+ if (dst_port == IPSEC_UDP_PORT_NONE)
+ sa->udp_hdr.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+ else
+ sa->udp_hdr.dst_port = clib_host_to_net_u16 (dst_port);
+
+ if (src_port == IPSEC_UDP_PORT_NONE)
+ sa->udp_hdr.src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+ else
+ 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));
+ }
+
+ hash_set (im->sa_index_by_sa_id, sa->id, sa_index);
+
+ if (sa_out_index)
+ *sa_out_index = sa_index;
+
+ return (0);