dpdk-ipsec-nodes multiarch: nodes are formatted in VLIB_NODE_FN style
[vpp.git] / src / plugins / dpdk / ipsec / esp_encrypt.c
index b4873d4..2a8d610 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <vnet/ipsec/ipsec.h>
 #include <vnet/ipsec/esp.h>
+#include <vnet/udp/udp.h>
 #include <dpdk/ipsec/ipsec.h>
 #include <dpdk/device/dpdk.h>
 #include <dpdk/device/dpdk_priv.h>
@@ -62,7 +63,8 @@ static char *esp_encrypt_error_strings[] = {
 #undef _
 };
 
-vlib_node_registration_t dpdk_esp_encrypt_node;
+extern vlib_node_registration_t dpdk_esp4_encrypt_node;
+extern vlib_node_registration_t dpdk_esp6_encrypt_node;
 
 typedef struct
 {
@@ -104,10 +106,10 @@ format_esp_encrypt_trace (u8 * s, va_list * args)
   return s;
 }
 
-static uword
-dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
-                         vlib_node_runtime_t * node,
-                         vlib_frame_t * from_frame)
+always_inline uword
+dpdk_esp_encrypt_inline (vlib_main_t * vm,
+                        vlib_node_runtime_t * node,
+                        vlib_frame_t * from_frame, int is_ip6)
 {
   u32 n_left_from, *from, *to_next, next_index;
   ipsec_main_t *im = &ipsec_main;
@@ -130,8 +132,12 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
   ret = crypto_alloc_ops (numa, ops, n_left_from);
   if (ret)
     {
-      vlib_node_increment_counter (vm, dpdk_esp_encrypt_node.index,
-                                  ESP_ENCRYPT_ERROR_DISCARD, 1);
+      if (is_ip6)
+       vlib_node_increment_counter (vm, dpdk_esp6_encrypt_node.index,
+                                    ESP_ENCRYPT_ERROR_DISCARD, 1);
+      else
+       vlib_node_increment_counter (vm, dpdk_esp4_encrypt_node.index,
+                                    ESP_ENCRYPT_ERROR_DISCARD, 1);
       /* Discard whole frame */
       return n_left_from;
     }
@@ -152,12 +158,15 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
          u32 sa_index0;
          ip4_and_esp_header_t *ih0, *oh0 = 0;
          ip6_and_esp_header_t *ih6_0, *oh6_0 = 0;
+         ip4_and_udp_and_esp_header_t *ouh0 = 0;
          esp_header_t *esp0;
          esp_footer_t *f0;
-         u8 is_ipv6, next_hdr_type;
+         u8 next_hdr_type;
          u32 iv_size;
          u16 orig_sz;
          u8 trunc_size;
+         u16 rewrite_len;
+         u16 udp_encap_adv = 0;
          struct rte_mbuf *mb0 = 0;
          struct rte_crypto_op *op;
          u16 res_idx;
@@ -208,9 +217,14 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
                {
                  clib_warning ("unsupported SA by thread index %u",
                                thread_idx);
-                 vlib_node_increment_counter (vm,
-                                              dpdk_esp_encrypt_node.index,
-                                              ESP_ENCRYPT_ERROR_NOSUP, 1);
+                 if (is_ip6)
+                   vlib_node_increment_counter (vm,
+                                                dpdk_esp6_encrypt_node.index,
+                                                ESP_ENCRYPT_ERROR_NOSUP, 1);
+                 else
+                   vlib_node_increment_counter (vm,
+                                                dpdk_esp4_encrypt_node.index,
+                                                ESP_ENCRYPT_ERROR_NOSUP, 1);
                  to_next[0] = bi0;
                  to_next += 1;
                  n_left_to_next -= 1;
@@ -222,9 +236,16 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
              if (PREDICT_FALSE (error || !session))
                {
                  clib_warning ("failed to get crypto session");
-                 vlib_node_increment_counter (vm,
-                                              dpdk_esp_encrypt_node.index,
-                                              ESP_ENCRYPT_ERROR_SESSION, 1);
+                 if (is_ip6)
+                   vlib_node_increment_counter (vm,
+                                                dpdk_esp6_encrypt_node.index,
+                                                ESP_ENCRYPT_ERROR_SESSION,
+                                                1);
+                 else
+                   vlib_node_increment_counter (vm,
+                                                dpdk_esp4_encrypt_node.index,
+                                                ESP_ENCRYPT_ERROR_SESSION,
+                                                1);
                  to_next[0] = bi0;
                  to_next += 1;
                  n_left_to_next -= 1;
@@ -238,8 +259,14 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
            {
              clib_warning ("sequence number counter has cycled SPI %u",
                            sa0->spi);
-             vlib_node_increment_counter (vm, dpdk_esp_encrypt_node.index,
-                                          ESP_ENCRYPT_ERROR_SEQ_CYCLED, 1);
+             if (is_ip6)
+               vlib_node_increment_counter (vm,
+                                            dpdk_esp6_encrypt_node.index,
+                                            ESP_ENCRYPT_ERROR_SEQ_CYCLED, 1);
+             else
+               vlib_node_increment_counter (vm,
+                                            dpdk_esp4_encrypt_node.index,
+                                            ESP_ENCRYPT_ERROR_SEQ_CYCLED, 1);
              //TODO: rekey SA
              to_next[0] = bi0;
              to_next += 1;
@@ -260,21 +287,25 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
 
          crypto_set_icb (icb, sa0->salt, sa0->seq, sa0->seq_hi);
 
-         is_ipv6 = (ih0->ip4.ip_version_and_header_length & 0xF0) == 0x60;
-
          iv_size = cipher_alg->iv_len;
          trunc_size = auth_alg->trunc_size;
 
+         /* if UDP encapsulation is used adjust the address of the IP header */
+         if (sa0->udp_encap && !is_ip6)
+           udp_encap_adv = sizeof (udp_header_t);
+
          if (sa0->is_tunnel)
            {
-             if (!is_ipv6 && !sa0->is_tunnel_ip6)      /* ip4inip4 */
+             rewrite_len = 0;
+             if (!is_ip6 && !sa0->is_tunnel_ip6)       /* ip4inip4 */
                {
                  /* in tunnel mode send it back to FIB */
                  priv->next = DPDK_CRYPTO_INPUT_NEXT_IP4_LOOKUP;
-                 u8 adv =
-                   sizeof (ip4_header_t) + sizeof (esp_header_t) + iv_size;
+                 u8 adv = sizeof (ip4_header_t) + udp_encap_adv +
+                   sizeof (esp_header_t) + iv_size;
                  vlib_buffer_advance (b0, -adv);
                  oh0 = vlib_buffer_get_current (b0);
+                 ouh0 = vlib_buffer_get_current (b0);
                  next_hdr_type = IP_PROTOCOL_IP_IN_IP;
                  /*
                   * oh0->ip4.ip_version_and_header_length = 0x45;
@@ -295,11 +326,18 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
                    sa0->tunnel_src_addr.ip4.as_u32;
                  oh0->ip4.dst_address.as_u32 =
                    sa0->tunnel_dst_addr.ip4.as_u32;
-                 esp0 = &oh0->esp;
-                 oh0->esp.spi = clib_host_to_net_u32 (sa0->spi);
-                 oh0->esp.seq = clib_host_to_net_u32 (sa0->seq);
+
+                 if (sa0->udp_encap)
+                   {
+                     oh0->ip4.protocol = IP_PROTOCOL_UDP;
+                     esp0 = &ouh0->esp;
+                   }
+                 else
+                   esp0 = &oh0->esp;
+                 esp0->spi = clib_host_to_net_u32 (sa0->spi);
+                 esp0->seq = clib_host_to_net_u32 (sa0->seq);
                }
-             else if (is_ipv6 && sa0->is_tunnel_ip6)   /* ip6inip6 */
+             else if (is_ip6 && sa0->is_tunnel_ip6)    /* ip6inip6 */
                {
                  /* in tunnel mode send it back to FIB */
                  priv->next = DPDK_CRYPTO_INPUT_NEXT_IP6_LOOKUP;
@@ -331,9 +369,14 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
                }
              else              /* unsupported ip4inip6, ip6inip4 */
                {
-                 vlib_node_increment_counter (vm,
-                                              dpdk_esp_encrypt_node.index,
-                                              ESP_ENCRYPT_ERROR_NOSUP, 1);
+                 if (is_ip6)
+                   vlib_node_increment_counter (vm,
+                                                dpdk_esp6_encrypt_node.index,
+                                                ESP_ENCRYPT_ERROR_NOSUP, 1);
+                 else
+                   vlib_node_increment_counter (vm,
+                                                dpdk_esp4_encrypt_node.index,
+                                                ESP_ENCRYPT_ERROR_NOSUP, 1);
                  to_next[0] = bi0;
                  to_next += 1;
                  n_left_to_next -= 1;
@@ -344,14 +387,14 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
          else                  /* transport mode */
            {
              priv->next = DPDK_CRYPTO_INPUT_NEXT_INTERFACE_OUTPUT;
-             u16 rewrite_len = vnet_buffer (b0)->ip.save_rewrite_length;
-             u16 adv = sizeof (esp_header_t) + iv_size;
+             rewrite_len = vnet_buffer (b0)->ip.save_rewrite_length;
+             u16 adv = sizeof (esp_header_t) + iv_size + udp_encap_adv;
              vlib_buffer_advance (b0, -adv - rewrite_len);
              u8 *src = ((u8 *) ih0) - rewrite_len;
              u8 *dst = vlib_buffer_get_current (b0);
              oh0 = vlib_buffer_get_current (b0) + rewrite_len;
 
-             if (is_ipv6)
+             if (is_ip6)
                {
                  orig_sz -= sizeof (ip6_header_t);
                  ih6_0 = (ip6_and_esp_header_t *) ih0;
@@ -369,11 +412,28 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
                  memmove (dst, src, rewrite_len + ip_size);
                  oh0->ip4.protocol = IP_PROTOCOL_IPSEC_ESP;
                  esp0 = (esp_header_t *) (((u8 *) oh0) + ip_size);
+                 if (sa0->udp_encap)
+                   {
+                     oh0->ip4.protocol = IP_PROTOCOL_UDP;
+                     esp0 = (esp_header_t *)
+                       (((u8 *) oh0) + ip_size + udp_encap_adv);
+                   }
+                 else
+                   {
+                     oh0->ip4.protocol = IP_PROTOCOL_IPSEC_ESP;
+                     esp0 = (esp_header_t *) (((u8 *) oh0) + ip_size);
+                   }
                }
              esp0->spi = clib_host_to_net_u32 (sa0->spi);
              esp0->seq = clib_host_to_net_u32 (sa0->seq);
            }
 
+         if (sa0->udp_encap && ouh0)
+           {
+             ouh0->udp.src_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+             ouh0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_ipsec);
+             ouh0->udp.checksum = 0;
+           }
          ASSERT (is_pow2 (cipher_alg->boundary));
          u16 mask = cipher_alg->boundary - 1;
          u16 pad_payload_len = ((orig_sz + 2) + mask) & ~mask;
@@ -384,21 +444,30 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
 
          /* The extra pad bytes would be overwritten by the digest */
          if (pad_bytes)
-           clib_memcpy (padding, pad_data, 16);
+           clib_memcpy_fast (padding, pad_data, 16);
 
          f0 = (esp_footer_t *) (padding + pad_bytes);
          f0->pad_length = pad_bytes;
          f0->next_header = next_hdr_type;
 
-         if (is_ipv6)
+         if (is_ip6)
            {
              u16 len = b0->current_length - sizeof (ip6_header_t);
-             oh6_0->ip6.payload_length = clib_host_to_net_u16 (len);
+             oh6_0->ip6.payload_length =
+               clib_host_to_net_u16 (len - rewrite_len);
            }
          else
            {
-             oh0->ip4.length = clib_host_to_net_u16 (b0->current_length);
+             oh0->ip4.length =
+               clib_host_to_net_u16 (b0->current_length - rewrite_len);
              oh0->ip4.checksum = ip4_header_checksum (&oh0->ip4);
+             if (sa0->udp_encap && ouh0)
+               {
+                 ouh0->udp.length =
+                   clib_host_to_net_u16 (clib_net_to_host_u16
+                                         (ouh0->ip4.length) -
+                                         ip4_header_bytes (&ouh0->ip4));
+               }
            }
 
          vnet_buffer (b0)->sw_if_index[VLIB_RX] =
@@ -469,27 +538,68 @@ dpdk_esp_encrypt_node_fn (vlib_main_t * vm,
              u8 *p = vlib_buffer_get_current (b0);
              if (!sa0->is_tunnel)
                p += vnet_buffer (b0)->ip.save_rewrite_length;
-             clib_memcpy (tr->packet_data, p, sizeof (tr->packet_data));
+             clib_memcpy_fast (tr->packet_data, p, sizeof (tr->packet_data));
            }
        }
       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
     }
-  vlib_node_increment_counter (vm, dpdk_esp_encrypt_node.index,
-                              ESP_ENCRYPT_ERROR_RX_PKTS,
-                              from_frame->n_vectors);
+  if (is_ip6)
+    {
+      vlib_node_increment_counter (vm, dpdk_esp6_encrypt_node.index,
+                                  ESP_ENCRYPT_ERROR_RX_PKTS,
+                                  from_frame->n_vectors);
 
-  crypto_enqueue_ops (vm, cwm, 1, dpdk_esp_encrypt_node.index,
-                     ESP_ENCRYPT_ERROR_ENQ_FAIL, numa);
+      crypto_enqueue_ops (vm, cwm, 1, dpdk_esp6_encrypt_node.index,
+                         ESP_ENCRYPT_ERROR_ENQ_FAIL, numa);
+    }
+  else
+    {
+      vlib_node_increment_counter (vm, dpdk_esp4_encrypt_node.index,
+                                  ESP_ENCRYPT_ERROR_RX_PKTS,
+                                  from_frame->n_vectors);
+
+      crypto_enqueue_ops (vm, cwm, 1, dpdk_esp4_encrypt_node.index,
+                         ESP_ENCRYPT_ERROR_ENQ_FAIL, numa);
+    }
 
   crypto_free_ops (numa, ops, cwm->ops + from_frame->n_vectors - ops);
 
   return from_frame->n_vectors;
 }
 
+VLIB_NODE_FN (dpdk_esp4_encrypt_node) (vlib_main_t * vm,
+                                      vlib_node_runtime_t * node,
+                                      vlib_frame_t * from_frame)
+{
+  return dpdk_esp_encrypt_inline (vm, node, from_frame, 0 /*is_ip6 */ );
+}
+
+/* *INDENT-OFF* */
+VLIB_REGISTER_NODE (dpdk_esp4_encrypt_node) = {
+  .name = "dpdk-esp4-encrypt",
+  .flags = VLIB_NODE_FLAG_IS_OUTPUT,
+  .vector_size = sizeof (u32),
+  .format_trace = format_esp_encrypt_trace,
+  .n_errors = ARRAY_LEN (esp_encrypt_error_strings),
+  .error_strings = esp_encrypt_error_strings,
+  .n_next_nodes = 1,
+  .next_nodes =
+    {
+      [ESP_ENCRYPT_NEXT_DROP] = "error-drop",
+    }
+};
+/* *INDENT-ON* */
+
+VLIB_NODE_FN (dpdk_esp6_encrypt_node) (vlib_main_t * vm,
+                                      vlib_node_runtime_t * node,
+                                      vlib_frame_t * from_frame)
+{
+  return dpdk_esp_encrypt_inline (vm, node, from_frame, 1 /*is_ip6 */ );
+}
+
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (dpdk_esp_encrypt_node) = {
-  .function = dpdk_esp_encrypt_node_fn,
-  .name = "dpdk-esp-encrypt",
+VLIB_REGISTER_NODE (dpdk_esp6_encrypt_node) = {
+  .name = "dpdk-esp6-encrypt",
   .flags = VLIB_NODE_FLAG_IS_OUTPUT,
   .vector_size = sizeof (u32),
   .format_trace = format_esp_encrypt_trace,
@@ -503,7 +613,6 @@ VLIB_REGISTER_NODE (dpdk_esp_encrypt_node) = {
 };
 /* *INDENT-ON* */
 
-VLIB_NODE_FUNCTION_MULTIARCH (dpdk_esp_encrypt_node, dpdk_esp_encrypt_node_fn)
 /*
  * fd.io coding-style-patch-verification: ON
  *