aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSzymon Sliwa <szs@semihalf.com>2018-01-05 16:26:31 +0100
committerSzymon Sliwa <szs@semihalf.com>2018-02-19 17:47:48 +0100
commit3a6b2d99d969bbb90792e1d09e97aa1be40d10df (patch)
treec4738c6a4c85c8515a3675e51583cafa3cb591cc
parent808c3e6e7b1c764bd77b12d4bc5ffc68707971a9 (diff)
plugins: odp: Add new nodes using ODP IPsec API
Created two new nodes for encryption/decryption, based on user preferences we can use them to accellerate IPsec by offloading it to hardware or optimized software implementations To use the new nodes two flags are needed in the odp section of the startup.conf file, like this: To use the new nodes put the enable-odp-ipsec flag to startup.conf file, like this: odp { enable-odp-ipsec } Change-Id: Ib4bbc481efad7e90d63994580b57849b74400947 Signed-off-by: Szymon Sliwa <szs@semihalf.com>
-rw-r--r--src/plugins/odp.am2
-rw-r--r--src/plugins/odp/ipsec/esp_decrypt_ipsec_api.c262
-rw-r--r--src/plugins/odp/ipsec/esp_encrypt_ipsec_api.c305
-rw-r--r--src/plugins/odp/ipsec/ipsec.c101
-rw-r--r--src/plugins/odp/ipsec/ipsec.h7
-rwxr-xr-xsrc/plugins/odp/odp_packet.c7
-rw-r--r--src/vpp/conf/startup.conf3
7 files changed, 675 insertions, 12 deletions
diff --git a/src/plugins/odp.am b/src/plugins/odp.am
index 88c5c166..85860f48 100644
--- a/src/plugins/odp.am
+++ b/src/plugins/odp.am
@@ -23,7 +23,9 @@ odp_plugin_la_SOURCES = odp/cli.c \
odp/thread.c \
odp/ipsec/ipsec.c \
odp/ipsec/esp_encrypt.c \
+ odp/ipsec/esp_encrypt_ipsec_api.c \
odp/ipsec/esp_decrypt.c \
+ odp/ipsec/esp_decrypt_ipsec_api.c \
odp/ipsec/crypto_input.c
noinst_HEADERS += odp/odp_packet.h \
diff --git a/src/plugins/odp/ipsec/esp_decrypt_ipsec_api.c b/src/plugins/odp/ipsec/esp_decrypt_ipsec_api.c
new file mode 100644
index 00000000..aa9eeec9
--- /dev/null
+++ b/src/plugins/odp/ipsec/esp_decrypt_ipsec_api.c
@@ -0,0 +1,262 @@
+/*
+ * esp_decrypt.c : IPSec ESP decrypt node
+ *
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/api_errno.h>
+#include <vnet/ip/ip.h>
+
+#include <odp/ipsec/ipsec.h>
+#include <odp/ipsec/esp.h>
+#include <odp/odp_packet.h>
+
+#include <assert.h>
+
+#define foreach_esp_decrypt_next \
+_(DROP, "error-drop") \
+_(IP4_INPUT, "ip4-input") \
+_(IP6_INPUT, "ip6-input")
+
+#define _(v, s) ESP_DECRYPT_NEXT_##v,
+typedef enum
+{
+ foreach_esp_decrypt_next
+#undef _
+ ESP_DECRYPT_N_NEXT,
+} esp_decrypt_next_t;
+
+
+#define foreach_esp_decrypt_error \
+ _(RX_PKTS, "ESP pkts received") \
+ _(NO_BUFFER, "No buffer (packed dropped)") \
+ _(DECRYPTION_FAILED, "ESP decryption failed") \
+ _(INTEG_ERROR, "Integrity check failed") \
+ _(REPLAY, "SA replayed packet") \
+ _(NOT_IP, "Not IP packet (dropped)")
+
+
+typedef enum
+{
+#define _(sym,str) ESP_DECRYPT_ERROR_##sym,
+ foreach_esp_decrypt_error
+#undef _
+ ESP_DECRYPT_N_ERROR,
+} esp_decrypt_error_t;
+
+static char *esp_decrypt_error_strings[] = {
+#define _(sym,string) string,
+ foreach_esp_decrypt_error
+#undef _
+};
+
+typedef struct
+{
+ ipsec_crypto_alg_t crypto_alg;
+ ipsec_integ_alg_t integ_alg;
+} esp_decrypt_trace_t;
+
+vlib_node_registration_t odp_ipsec_esp_decrypt_node;
+vlib_node_registration_t odp_ipsec_esp_decrypt_post_node;
+
+/* packet trace format function */
+static u8 *
+format_esp_decrypt_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ esp_decrypt_trace_t *t = va_arg (*args, esp_decrypt_trace_t *);
+
+ s = format (s, "(ODP IPsec API) esp: crypto %U integrity %U",
+ format_ipsec_crypto_alg, t->crypto_alg,
+ format_ipsec_integ_alg, t->integ_alg);
+ return s;
+}
+
+static uword
+esp_decrypt_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+ u32 n_left_from, *from, next_index, *to_next;
+ ipsec_main_t *im = &ipsec_main;
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+ odp_crypto_main_t *ocm = &odp_crypto_main;
+ u32 thread_index = vlib_get_thread_index ();
+
+ ipsec_alloc_empty_buffers (vm, im);
+
+ u32 *empty_buffers = im->empty_buffers[thread_index];
+
+ odp_crypto_worker_main_t *cwm =
+ vec_elt_at_index (ocm->workers, thread_index);
+
+ if (PREDICT_FALSE (vec_len (empty_buffers) < n_left_from))
+ {
+ vlib_node_increment_counter (vm, odp_ipsec_esp_decrypt_node.index,
+ ESP_DECRYPT_ERROR_NO_BUFFER, n_left_from);
+ goto free_buffers_and_exit;
+ }
+
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+ u32 buffers_passed = 0;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0, next0;
+ vlib_buffer_t *i_b0, *o_b0;
+ ipsec_sa_t *sa0;
+ u32 sa_index0 = ~0;
+ sa_data_t *sa_sess_data;
+ u8 ip_hdr_size = sizeof (ip4_header_t);
+ ip4_header_t *ih4 = 0;
+
+ bi0 = from[0];
+ from += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ next0 = ESP_DECRYPT_NEXT_DROP;
+
+ i_b0 = vlib_get_buffer (vm, bi0);
+
+ sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
+ sa0 = pool_elt_at_index (im->sad, sa_index0);
+
+ ih4 = (ip4_header_t *) (i_b0->data + sizeof (ethernet_header_t));
+ if (PREDICT_TRUE
+ ((ih4->ip_version_and_header_length & 0xF0) != 0x40))
+ {
+ ip_hdr_size = sizeof (ip6_header_t);
+ }
+
+ sa0->total_data_size += i_b0->current_length;
+
+ sa_sess_data = pool_elt_at_index (cwm->sa_sess_d[0], sa_index0);
+ if (PREDICT_FALSE (!(sa_sess_data->is_odp_sa_present)))
+ {
+ int ret = create_odp_sa (sa0, sa_sess_data, 0, 0);
+
+ if (ret)
+ {
+ to_next[0] = bi0;
+ to_next += 1;
+ goto trace;
+ }
+ }
+
+ if (ip_hdr_size == sizeof (ip6_header_t))
+ next0 = ESP_DECRYPT_NEXT_IP6_INPUT;
+ else
+ next0 = ESP_DECRYPT_NEXT_IP4_INPUT;
+
+ odp_packet_t pkt = odp_packet_from_vlib_buffer (i_b0);
+ odp_packet_t out_pkt;
+
+ odp_ipsec_in_param_t oiopt;
+ oiopt.num_sa = 1;
+ oiopt.sa = &sa_sess_data->odp_sa;
+
+ odp_packet_l3_offset_set (pkt, i_b0->current_data - ip_hdr_size);
+
+ to_next[0] = bi0;
+ to_next += 1;
+
+ int processed = 1;
+
+ int ret = odp_ipsec_in (&pkt, 1, &out_pkt, &processed, &oiopt);
+
+ o_b0 = vlib_buffer_from_odp_packet (out_pkt);
+
+ if (ret < 1)
+ {
+ clib_error ("(in) IPsec packet not processed\n");
+ goto trace;
+ }
+
+ /* add the change of the ODP data offset
+ and the offset to IP within the packet data */
+ o_b0->current_data =
+ (i16) ((intptr_t) odp_packet_data (out_pkt) -
+ (intptr_t) o_b0->data +
+ (intptr_t) odp_packet_l3_offset (out_pkt));
+ o_b0->current_length =
+ odp_packet_len (out_pkt) - sizeof (ethernet_header_t);
+
+ vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
+
+ vnet_buffer (o_b0)->unused[0] = next0;
+
+ trace:
+ if (PREDICT_FALSE (o_b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ o_b0->flags |= VLIB_BUFFER_IS_TRACED;
+ o_b0->trace_index = o_b0->trace_index;
+ esp_decrypt_trace_t *tr =
+ vlib_add_trace (vm, node, o_b0, sizeof (*tr));
+ tr->crypto_alg = sa0->crypto_alg;
+ tr->integ_alg = sa0->integ_alg;
+ }
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
+ n_left_to_next, bi0, next0);
+ buffers_passed += 1;
+ }
+ if (buffers_passed > 0)
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+ vlib_node_increment_counter (vm, odp_ipsec_esp_decrypt_node.index,
+ ESP_DECRYPT_ERROR_RX_PKTS,
+ from_frame->n_vectors);
+
+free_buffers_and_exit:
+ return from_frame->n_vectors;
+}
+
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (odp_ipsec_esp_decrypt_node) = {
+ .function = esp_decrypt_node_fn,
+ .name = "odp-ipsec-esp-decrypt",
+ .vector_size = sizeof (u32),
+ .format_trace = format_esp_decrypt_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(esp_decrypt_error_strings),
+ .error_strings = esp_decrypt_error_strings,
+
+ .n_next_nodes = ESP_DECRYPT_N_NEXT,
+ .next_nodes = {
+#define _(s,n) [ESP_DECRYPT_NEXT_##s] = n,
+ foreach_esp_decrypt_next
+#undef _
+ },
+};
+
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/odp/ipsec/esp_encrypt_ipsec_api.c b/src/plugins/odp/ipsec/esp_encrypt_ipsec_api.c
new file mode 100644
index 00000000..a41f2821
--- /dev/null
+++ b/src/plugins/odp/ipsec/esp_encrypt_ipsec_api.c
@@ -0,0 +1,305 @@
+/*
+ * esp_encrypt.c : IPSec ESP encrypt node
+ *
+ * Copyright (c) 2015 Cisco and/or its affiliates.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <vnet/vnet.h>
+#include <vnet/api_errno.h>
+#include <vnet/ip/ip.h>
+
+#include <odp/ipsec/ipsec.h>
+#include <odp/ipsec/esp.h>
+#include <odp/odp_packet.h>
+
+#include <assert.h>
+
+#define foreach_esp_encrypt_next \
+_(DROP, "error-drop") \
+_(IP4_LOOKUP, "ip4-lookup") \
+_(IP6_LOOKUP, "ip6-lookup") \
+_(INTERFACE_OUTPUT, "interface-output")
+
+#define _(v, s) ESP_ENCRYPT_NEXT_##v,
+typedef enum
+{
+ foreach_esp_encrypt_next
+#undef _
+ ESP_ENCRYPT_N_NEXT,
+} esp_encrypt_next_t;
+
+#define foreach_esp_encrypt_error \
+ _(RX_PKTS, "ESP pkts received") \
+ _(NO_BUFFER, "No buffer (packet dropped)") \
+ _(DECRYPTION_FAILED, "ESP encryption failed") \
+ _(SEQ_CYCLED, "sequence number cycled")
+
+
+typedef enum
+{
+#define _(sym,str) ESP_ENCRYPT_ERROR_##sym,
+ foreach_esp_encrypt_error
+#undef _
+ ESP_ENCRYPT_N_ERROR,
+} esp_encrypt_error_t;
+
+static char *esp_encrypt_error_strings[] = {
+#define _(sym,string) string,
+ foreach_esp_encrypt_error
+#undef _
+};
+
+typedef struct
+{
+ u32 spi;
+ u32 seq;
+ ipsec_crypto_alg_t crypto_alg;
+ ipsec_integ_alg_t integ_alg;
+} esp_encrypt_trace_t;
+
+vlib_node_registration_t odp_ipsec_esp_encrypt_node;
+vlib_node_registration_t odp_ipsec_esp_encrypt_post_node;
+
+/* packet trace format function */
+static u8 *
+format_esp_encrypt_trace (u8 * s, va_list * args)
+{
+ CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
+ CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
+ esp_encrypt_trace_t *t = va_arg (*args, esp_encrypt_trace_t *);
+
+ s = format (s, "(ODP) esp: spi %u seq %u crypto %U integrity %U",
+ t->spi, t->seq,
+ format_ipsec_crypto_alg, t->crypto_alg,
+ format_ipsec_integ_alg, t->integ_alg);
+ return s;
+}
+
+
+static uword
+esp_encrypt_node_fn (vlib_main_t * vm,
+ vlib_node_runtime_t * node, vlib_frame_t * from_frame)
+{
+ u32 n_left_from, *from, *to_next = 0, next_index;
+ from = vlib_frame_vector_args (from_frame);
+ n_left_from = from_frame->n_vectors;
+ ipsec_main_t *im = &ipsec_main;
+ odp_crypto_main_t *ocm = &odp_crypto_main;
+ u32 thread_index = vlib_get_thread_index ();
+
+ ipsec_alloc_empty_buffers (vm, im);
+
+ u32 *empty_buffers = im->empty_buffers[thread_index];
+
+ odp_crypto_worker_main_t *cwm =
+ vec_elt_at_index (ocm->workers, thread_index);
+
+ if (PREDICT_FALSE (vec_len (empty_buffers) < n_left_from))
+ {
+ vlib_node_increment_counter (vm, odp_ipsec_esp_encrypt_node.index,
+ ESP_ENCRYPT_ERROR_NO_BUFFER, n_left_from);
+ clib_warning ("no enough empty buffers. discarding frame");
+ goto free_buffers_and_exit;
+ }
+
+ next_index = node->cached_next_index;
+
+ while (n_left_from > 0)
+ {
+ u32 n_left_to_next;
+ u32 buffers_passed = 0;
+
+ vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
+
+ while (n_left_from > 0 && n_left_to_next > 0)
+ {
+ u32 bi0, next0;
+ vlib_buffer_t *i_b0, *o_b0;
+ u32 sa_index0;
+ ipsec_sa_t *sa0;
+ ip6_header_t *h6 = 0;
+ ethernet_header_t old_eth_hdr;
+ u8 transport_mode = 0;
+ sa_data_t *sa_sess_data;
+ u32 flow_label;
+
+ bi0 = from[0];
+ from += 1;
+ n_left_from -= 1;
+ n_left_to_next -= 1;
+
+ next0 = ESP_ENCRYPT_NEXT_DROP;
+
+ i_b0 = vlib_get_buffer (vm, bi0);
+ sa_index0 = vnet_buffer (i_b0)->ipsec.sad_index;
+ sa0 = pool_elt_at_index (im->sad, sa_index0);
+
+ sa0->total_data_size += i_b0->current_length;
+
+ old_eth_hdr = *((ethernet_header_t *)
+ ((u8 *) vlib_buffer_get_current (i_b0) -
+ sizeof (ethernet_header_t)));
+
+ h6 = vlib_buffer_get_current (i_b0);
+
+ flow_label =
+ (0xFFFFF & h6->ip_version_traffic_class_and_flow_label);
+
+ sa_sess_data = pool_elt_at_index (cwm->sa_sess_d[1], sa_index0);
+ if (PREDICT_FALSE (!(sa_sess_data->is_odp_sa_present)))
+ {
+ int ret = create_odp_sa (sa0, sa_sess_data, flow_label, 1);
+
+ if (ret)
+ {
+ to_next[0] = bi0;
+ to_next += 1;
+ goto trace;
+ }
+ }
+
+ to_next[0] = bi0;
+ to_next += 1;
+
+
+ ASSERT (sa0->crypto_alg < IPSEC_CRYPTO_N_ALG);
+
+ if (PREDICT_TRUE (sa0->crypto_alg != IPSEC_CRYPTO_ALG_NONE))
+ {
+ odp_packet_t pkt = odp_packet_from_vlib_buffer (i_b0);
+ odp_packet_t out_pkt;
+
+ odp_ipsec_out_param_t oiopt;
+ oiopt.num_sa = 1;
+ oiopt.num_opt = 0;
+ oiopt.opt = NULL;
+ oiopt.sa = &sa_sess_data->odp_sa;
+
+ odp_adjust_data_pointers (i_b0, pkt);
+
+ odp_packet_l3_offset_set (pkt, 0);
+
+ int processed = 1;
+
+ int ret = odp_ipsec_out (&pkt, 1, &out_pkt, &processed, &oiopt);
+
+ o_b0 = vlib_buffer_from_odp_packet (out_pkt);
+
+ vnet_buffer (o_b0)->unused[0] = next0;
+
+ if (ret < 1)
+ {
+ clib_error ("(out) IPsec packet not processed\n");
+ goto trace;
+ }
+
+ o_b0->current_data =
+ (i16) ((intptr_t) odp_packet_data (out_pkt) -
+ (intptr_t) o_b0->data +
+ (intptr_t) odp_packet_l3_offset (out_pkt));
+ o_b0->current_length = odp_packet_len (out_pkt);
+
+
+ }
+
+ if (!sa0->is_tunnel)
+ {
+ if (vnet_buffer (o_b0)->sw_if_index[VLIB_TX] != ~0)
+ {
+ transport_mode = 1;
+ ethernet_header_t *ieh0, *oeh0;
+ ieh0 = &old_eth_hdr;
+ oeh0 =
+ (ethernet_header_t *) ((uintptr_t)
+ vlib_buffer_get_current (o_b0) -
+ sizeof (ethernet_header_t));
+ clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t));
+ next0 = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT;
+ }
+ }
+
+ if (transport_mode)
+ {
+ o_b0->current_data -= sizeof (ethernet_header_t);
+ o_b0->current_length += sizeof (ethernet_header_t);
+ }
+ else
+ {
+ if (sa0->is_tunnel_ip6)
+ next0 = ESP_ENCRYPT_NEXT_IP6_LOOKUP;
+ else
+ next0 = ESP_ENCRYPT_NEXT_IP4_LOOKUP;
+
+ vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
+ }
+
+ trace:
+ if (PREDICT_FALSE (o_b0->flags & VLIB_BUFFER_IS_TRACED))
+ {
+ o_b0->flags |= VLIB_BUFFER_IS_TRACED;
+ o_b0->trace_index = o_b0->trace_index;
+ esp_encrypt_trace_t *tr =
+ vlib_add_trace (vm, node, o_b0, sizeof (*tr));
+ tr->spi = sa0->spi;
+ tr->seq = sa0->seq - 1;
+ tr->crypto_alg = sa0->crypto_alg;
+ tr->integ_alg = sa0->integ_alg;
+ }
+
+ vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
+ to_next, n_left_to_next, bi0,
+ next0);
+ buffers_passed += 1;
+
+ }
+ if (buffers_passed > 0)
+ vlib_put_next_frame (vm, node, next_index, n_left_to_next);
+ }
+ vlib_node_increment_counter (vm, odp_ipsec_esp_encrypt_node.index,
+ ESP_ENCRYPT_ERROR_RX_PKTS,
+ from_frame->n_vectors);
+
+free_buffers_and_exit:
+ return from_frame->n_vectors;
+}
+
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (odp_ipsec_esp_encrypt_node) = {
+ .function = esp_encrypt_node_fn,
+ .name = "odp-ipsec-esp-encrypt",
+ .vector_size = sizeof (u32),
+ .format_trace = format_esp_encrypt_trace,
+ .type = VLIB_NODE_TYPE_INTERNAL,
+
+ .n_errors = ARRAY_LEN(esp_encrypt_error_strings),
+ .error_strings = esp_encrypt_error_strings,
+
+ .n_next_nodes = ESP_ENCRYPT_N_NEXT,
+ .next_nodes = {
+#define _(s,n) [ESP_ENCRYPT_NEXT_##s] = n,
+ foreach_esp_encrypt_next
+#undef _
+ },
+};
+
+/* *INDENT-ON* */
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */
diff --git a/src/plugins/odp/ipsec/ipsec.c b/src/plugins/odp/ipsec/ipsec.c
index 0e552fba..44a7714b 100644
--- a/src/plugins/odp/ipsec/ipsec.c
+++ b/src/plugins/odp/ipsec/ipsec.c
@@ -64,7 +64,9 @@ add_del_sa_sess (u32 sa_index, u8 is_add)
return 0;
}
-int vpp_to_odp_auth_alg(int vpp_auth_alg) {
+int
+vpp_to_odp_auth_alg (int vpp_auth_alg)
+{
switch (vpp_auth_alg)
{
case IPSEC_INTEG_ALG_SHA_512_256:
@@ -78,6 +80,79 @@ int vpp_to_odp_auth_alg(int vpp_auth_alg) {
}
}
+int // should flow_label be here?
+create_odp_sa (ipsec_sa_t * sa, sa_data_t * sa_sess_data, int flow_label,
+ int is_outbound)
+{
+ odp_ipsec_sa_param_t sa_params;
+ odp_ipsec_sa_param_init (&sa_params);
+
+ sa_params.dir =
+ (is_outbound ? ODP_IPSEC_DIR_OUTBOUND : ODP_IPSEC_DIR_INBOUND);
+ /* VPP does not currently support Authentication Headers (AH),
+ Encapsulating Security Payload (ESP), neither does this code.
+ Code needs modification, not only in this place. */
+ sa_params.proto = ODP_IPSEC_ESP;
+ sa_params.mode =
+ (sa->is_tunnel ? ODP_IPSEC_MODE_TUNNEL : ODP_IPSEC_MODE_TRANSPORT);
+
+ if (sa_params.mode == ODP_IPSEC_MODE_TUNNEL
+ && sa_params.dir == ODP_IPSEC_DIR_OUTBOUND)
+ {
+ if (sa->is_tunnel_ip6)
+ {
+ sa_sess_data->tunnel_src.ip6 = sa->tunnel_src_addr.ip6;
+ sa_sess_data->tunnel_dst.ip6 = sa->tunnel_dst_addr.ip6;
+ sa_params.outbound.tunnel.type = ODP_IPSEC_TUNNEL_IPV6;
+ sa_params.outbound.tunnel.ipv6.dst_addr =
+ &sa_sess_data->tunnel_dst.ip6;
+ sa_params.outbound.tunnel.ipv6.src_addr =
+ &sa_sess_data->tunnel_src.ip6;
+ sa_params.outbound.tunnel.ipv6.hlimit = 42;
+ sa_params.outbound.tunnel.ipv6.dscp = 0;
+ sa_params.outbound.tunnel.ipv6.flabel = flow_label;
+ }
+ else
+ {
+ sa_sess_data->tunnel_src.ip4 = sa->tunnel_src_addr.ip4;
+ sa_sess_data->tunnel_dst.ip4 = sa->tunnel_dst_addr.ip4;
+ sa_params.outbound.tunnel.type = ODP_IPSEC_TUNNEL_IPV4;
+ sa_params.outbound.tunnel.ipv4.dst_addr =
+ &sa_sess_data->tunnel_dst.ip4;
+ sa_params.outbound.tunnel.ipv4.src_addr =
+ &sa_sess_data->tunnel_src.ip4;
+ sa_params.outbound.tunnel.ipv4.ttl = 42;
+ sa_params.outbound.tunnel.ipv4.df = 42;
+ }
+ }
+
+ sa_params.crypto.cipher_alg = ODP_CIPHER_ALG_AES_CBC;
+ sa_params.crypto.cipher_key.data = sa->crypto_key;
+ sa_params.crypto.cipher_key.length = sa->crypto_key_len;
+
+ sa_params.crypto.auth_alg = vpp_to_odp_auth_alg (sa->integ_alg);
+ sa_params.crypto.auth_key.data = sa->integ_key;
+ sa_params.crypto.auth_key.length = sa->integ_key_len;
+
+ sa_params.lifetime.soft_limit.packets = 0;
+ sa_params.lifetime.hard_limit.packets = 0;
+
+ sa_params.spi = sa->spi;
+
+ sa_params.dest_queue = ODP_QUEUE_INVALID;
+ sa_params.context = NULL;
+ sa_params.context_len = 0;
+
+ sa_sess_data->odp_sa = odp_ipsec_sa_create (&sa_params); // check if there are no errors
+
+ if (sa_sess_data->odp_sa == ODP_IPSEC_SA_INVALID)
+ return -1;
+
+ sa_sess_data->is_odp_sa_present = 1;
+
+ return 0;
+}
+
int
create_sess (ipsec_sa_t * sa, sa_data_t * sa_sess_data, int is_outbound)
{
@@ -114,11 +189,11 @@ create_sess (ipsec_sa_t * sa, sa_data_t * sa_sess_data, int is_outbound)
crypto_params.cipher_alg = ODP_CIPHER_ALG_NULL;
}
- crypto_params.auth_alg = vpp_to_odp_auth_alg(sa->integ_alg);
+ crypto_params.auth_alg = vpp_to_odp_auth_alg (sa->integ_alg);
actual_capa_amount = odp_crypto_auth_capability (crypto_params.auth_alg,
- capa,
- max_auth_capa_amount);
+ capa,
+ max_auth_capa_amount);
int picked_capa = -1;
int i;
@@ -136,8 +211,8 @@ create_sess (ipsec_sa_t * sa, sa_data_t * sa_sess_data, int is_outbound)
{
if (actual_capa_amount)
clib_warning
- ("Failed to get matching capabilities, algorithm appears to be supported "\
- "but key or digest length incompatible\n");
+ ("Failed to get matching capabilities, algorithm appears to be supported "
+ "but key or digest length incompatible\n");
else
clib_warning
("Failed to get matching capabilities, algorithm probably not supported\n");
@@ -210,9 +285,9 @@ odp_ipsec_check_support (ipsec_sa_t * sa)
}
clib_error_t *
-ipsec_init (vlib_main_t * vm)
+ipsec_init (vlib_main_t * vm, u8 ipsec_api)
{
- if (!enable_odp_crypto)
+ if (!enable_odp_crypto && !ipsec_api)
return 0;
ipsec_main_t *im = &ipsec_main;
odp_crypto_main_t *ocm = &odp_crypto_main;
@@ -239,7 +314,10 @@ ipsec_init (vlib_main_t * vm)
ipsec_node = vlib_get_node_by_name (vm, (u8 *) "ipsec-output-ip4");
ASSERT (ipsec_node);
- crypto_node = vlib_get_node_by_name (vm, (u8 *) "odp-crypto-esp-encrypt");
+ if (ipsec_api)
+ crypto_node = vlib_get_node_by_name (vm, (u8 *) "odp-ipsec-esp-encrypt");
+ else
+ crypto_node = vlib_get_node_by_name (vm, (u8 *) "odp-crypto-esp-encrypt");
ASSERT (crypto_node);
im->esp_encrypt_node_index = crypto_node->index;
im->esp_encrypt_next_index =
@@ -247,7 +325,10 @@ ipsec_init (vlib_main_t * vm)
ipsec_node = vlib_get_node_by_name (vm, (u8 *) "ipsec-input-ip4");
ASSERT (ipsec_node);
- crypto_node = vlib_get_node_by_name (vm, (u8 *) "odp-crypto-esp-decrypt");
+ if (ipsec_api)
+ crypto_node = vlib_get_node_by_name (vm, (u8 *) "odp-ipsec-esp-decrypt");
+ else
+ crypto_node = vlib_get_node_by_name (vm, (u8 *) "odp-crypto-esp-decrypt");
ASSERT (crypto_node);
im->esp_decrypt_node_index = crypto_node->index;
im->esp_decrypt_next_index =
diff --git a/src/plugins/odp/ipsec/ipsec.h b/src/plugins/odp/ipsec/ipsec.h
index 0f3ceb86..c947d7ce 100644
--- a/src/plugins/odp/ipsec/ipsec.h
+++ b/src/plugins/odp/ipsec/ipsec.h
@@ -20,11 +20,14 @@
typedef struct
{
+ u8 is_odp_sa_present;
+ odp_ipsec_sa_t odp_sa;
odp_crypto_session_t sess;
u32 digest_size;
u8 iv_data[16];
u32 iv_len;
u32 key_size;
+ ip46_address_t tunnel_dst, tunnel_src;
} sa_data_t;
typedef struct
@@ -43,8 +46,10 @@ extern odp_crypto_main_t odp_crypto_main;
extern u8 enable_odp_crypto;
int create_sess (ipsec_sa_t * sa, sa_data_t * sess, int is_outbound);
+int create_odp_sa (ipsec_sa_t * sa, sa_data_t * sess, int flow_label,
+ int is_outbound);
-clib_error_t *ipsec_init (vlib_main_t * vm);
+clib_error_t *ipsec_init (vlib_main_t * vm, u8 ipsec_api);
#endif /* __IPSEC_H__ */
diff --git a/src/plugins/odp/odp_packet.c b/src/plugins/odp/odp_packet.c
index 43ad6772..5a43a444 100755
--- a/src/plugins/odp/odp_packet.c
+++ b/src/plugins/odp/odp_packet.c
@@ -24,6 +24,7 @@ odp_if_mode_t def_if_mode;
odp_if_config_t *if_config;
odp_crypto_main_t odp_crypto_main;
u8 enable_odp_crypto;
+u8 ipsec_api;
static u32
odp_packet_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
@@ -430,6 +431,10 @@ odp_config (vlib_main_t * vm, unformat_input_t * input)
{
enable_odp_crypto = 1;
}
+ else if (unformat (input, "enable-odp-ipsec"))
+ {
+ ipsec_api = 1;
+ }
else if (unformat (input, "%s", &param))
{
clib_warning ("%s: Unknown option %s\n", __func__, param);
@@ -472,7 +477,7 @@ odp_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
/* Initialization complete and worker threads can start */
tm->worker_thread_release = 1;
- ipsec_init (vlib_get_main ());
+ ipsec_init (vlib_get_main (), ipsec_api);
return 0;
}
diff --git a/src/vpp/conf/startup.conf b/src/vpp/conf/startup.conf
index 1aee5ca0..6ae0dc15 100644
--- a/src/vpp/conf/startup.conf
+++ b/src/vpp/conf/startup.conf
@@ -133,6 +133,9 @@ cpu {
## Make use of ODP crypto API to accelerate IPsec
# enable-odp-crypto
+ ## Use ODP ipsec API instead of ODP crypto API
+ # enable-odp-ipsec
+
## To use asynchronous mode of the crypto operations
# async
# }