vlib: clean up r2 plugin registration relocator
[vpp.git] / src / vnet / gso / node.c
index ecbdc18..c1d4459 100644 (file)
 #include <vnet/ip/ip6.h>
 #include <vnet/udp/udp_packet.h>
 
+#define foreach_gso_error                                                     \
+  _ (NO_BUFFERS, "no buffers to segment GSO")                                 \
+  _ (UNHANDLED_TYPE, "unhandled gso type")
+
+static char *gso_error_strings[] = {
+#define _(sym, string) string,
+  foreach_gso_error
+#undef _
+};
+
+typedef enum
+{
+#define _(sym, str) GSO_ERROR_##sym,
+  foreach_gso_error
+#undef _
+    GSO_N_ERROR,
+} gso_error_t;
+
+typedef enum
+{
+  GSO_NEXT_DROP,
+  GSO_N_NEXT,
+} gso_next_t;
+
 typedef struct
 {
   u32 flags;
@@ -56,119 +80,108 @@ format_gso_trace (u8 * s, va_list * args)
   return s;
 }
 
-static_always_inline u16
-tso_segment_ipip_tunnel_fixup (vlib_main_t * vm,
-                              vnet_interface_per_thread_data_t * ptd,
-                              vlib_buffer_t * sb0,
-                              generic_header_offset_t * gho)
+static_always_inline void
+tso_segment_ipip_tunnel_fixup (vlib_main_t *vm,
+                              vnet_interface_per_thread_data_t *ptd,
+                              vlib_buffer_t *sb0)
 {
   u16 n_tx_bufs = vec_len (ptd->split_buffers);
-  u16 i = 0, n_tx_bytes = 0;
+  u16 i = 0;
 
   while (i < n_tx_bufs)
     {
       vlib_buffer_t *b0 = vlib_get_buffer (vm, ptd->split_buffers[i]);
-      vnet_get_outer_header (b0, gho);
-      clib_memcpy_fast (vlib_buffer_get_current (b0),
-                       vlib_buffer_get_current (sb0), gho->outer_hdr_sz);
-
-      ip4_header_t *ip4 =
-       (ip4_header_t *) (vlib_buffer_get_current (b0) +
-                         gho->outer_l3_hdr_offset);
-      ip6_header_t *ip6 =
-       (ip6_header_t *) (vlib_buffer_get_current (b0) +
-                         gho->outer_l3_hdr_offset);
-
-      if (gho->gho_flags & GHO_F_OUTER_IP4)
+      i16 outer_l3_hdr_offset = vnet_buffer2 (b0)->outer_l3_hdr_offset;
+      i16 l3_hdr_offset = vnet_buffer (b0)->l3_hdr_offset;
+
+      ip4_header_t *ip4 = (ip4_header_t *) (b0->data + outer_l3_hdr_offset);
+      ip6_header_t *ip6 = (ip6_header_t *) (b0->data + outer_l3_hdr_offset);
+
+      if (vnet_buffer (b0)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM)
        {
-         ip4->length =
-           clib_host_to_net_u16 (b0->current_length -
-                                 gho->outer_l3_hdr_offset);
+         ip4->length = clib_host_to_net_u16 (
+           b0->current_length - (outer_l3_hdr_offset - b0->current_data));
          ip4->checksum = ip4_header_checksum (ip4);
+         vnet_buffer_offload_flags_clear (
+           b0, VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM |
+                 VNET_BUFFER_OFFLOAD_F_TNL_IPIP);
        }
-      else if (gho->gho_flags & GHO_F_OUTER_IP6)
+      else
        {
-         ip6->payload_length =
-           clib_host_to_net_u16 (b0->current_length -
-                                 gho->outer_l4_hdr_offset);
+         ip6->payload_length = clib_host_to_net_u16 (
+           b0->current_length - (l3_hdr_offset - b0->current_data));
+         vnet_buffer_offload_flags_clear (b0, VNET_BUFFER_OFFLOAD_F_TNL_IPIP);
        }
 
-      n_tx_bytes += gho->outer_hdr_sz;
       i++;
     }
-  return n_tx_bytes;
 }
 
 static_always_inline void
-tso_segment_vxlan_tunnel_headers_fixup (vlib_main_t * vm, vlib_buffer_t * b,
-                                       generic_header_offset_t * gho)
+tso_segment_vxlan_tunnel_headers_fixup (vlib_main_t *vm, vlib_buffer_t *b)
 {
-  u8 proto = 0;
   ip4_header_t *ip4 = 0;
   ip6_header_t *ip6 = 0;
   udp_header_t *udp = 0;
+  i16 outer_l3_hdr_offset = vnet_buffer2 (b)->outer_l3_hdr_offset;
+  i16 outer_l4_hdr_offset = vnet_buffer2 (b)->outer_l4_hdr_offset;
 
-  ip4 =
-    (ip4_header_t *) (vlib_buffer_get_current (b) + gho->outer_l3_hdr_offset);
-  ip6 =
-    (ip6_header_t *) (vlib_buffer_get_current (b) + gho->outer_l3_hdr_offset);
-  udp =
-    (udp_header_t *) (vlib_buffer_get_current (b) + gho->outer_l4_hdr_offset);
+  ip4 = (ip4_header_t *) (b->data + outer_l3_hdr_offset);
+  ip6 = (ip6_header_t *) (b->data + outer_l3_hdr_offset);
+  udp = (udp_header_t *) (b->data + outer_l4_hdr_offset);
 
-  if (gho->gho_flags & GHO_F_OUTER_IP4)
+  if (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM)
     {
-      proto = ip4->protocol;
-      ip4->length =
-       clib_host_to_net_u16 (b->current_length - gho->outer_l3_hdr_offset);
+      ip4->length = clib_host_to_net_u16 (
+       b->current_length - (outer_l3_hdr_offset - b->current_data));
       ip4->checksum = ip4_header_checksum (ip4);
+      if (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM)
+       {
+         udp->length = clib_host_to_net_u16 (
+           b->current_length - (outer_l4_hdr_offset - b->current_data));
+         // udp checksum is 0, in udp tunnel
+         udp->checksum = 0;
+       }
+      vnet_buffer_offload_flags_clear (
+       b, VNET_BUFFER_OFFLOAD_F_OUTER_IP_CKSUM |
+            VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM |
+            VNET_BUFFER_OFFLOAD_F_TNL_VXLAN);
     }
-  else if (gho->gho_flags & GHO_F_OUTER_IP6)
-    {
-      proto = ip6->protocol;
-      ip6->payload_length =
-       clib_host_to_net_u16 (b->current_length - gho->outer_l4_hdr_offset);
-    }
-  if (proto == IP_PROTOCOL_UDP)
+  else
     {
-      int bogus;
-      udp->length =
-       clib_host_to_net_u16 (b->current_length - gho->outer_l4_hdr_offset);
-      udp->checksum = 0;
-      if (gho->gho_flags & GHO_F_OUTER_IP6)
+      ip6->payload_length = clib_host_to_net_u16 (
+       b->current_length - (outer_l4_hdr_offset - b->current_data));
+
+      if (vnet_buffer (b)->oflags & VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM)
        {
+         int bogus;
+         udp->length = ip6->payload_length;
+         // udp checksum is 0, in udp tunnel
+         udp->checksum = 0;
          udp->checksum =
            ip6_tcp_udp_icmp_compute_checksum (vm, b, ip6, &bogus);
+         vnet_buffer_offload_flags_clear (
+           b, VNET_BUFFER_OFFLOAD_F_OUTER_UDP_CKSUM |
+                VNET_BUFFER_OFFLOAD_F_TNL_VXLAN);
        }
-      else if (gho->gho_flags & GHO_F_OUTER_IP4)
-       {
-         udp->checksum = ip4_tcp_udp_compute_checksum (vm, b, ip4);
-       }
-      /* FIXME: it should be OUTER_UDP_CKSUM */
-      vnet_buffer_offload_flags_clear (b, VNET_BUFFER_OFFLOAD_F_UDP_CKSUM);
     }
 }
 
-static_always_inline u16
-tso_segment_vxlan_tunnel_fixup (vlib_main_t * vm,
-                               vnet_interface_per_thread_data_t * ptd,
-                               vlib_buffer_t * sb0,
-                               generic_header_offset_t * gho)
+static_always_inline void
+tso_segment_vxlan_tunnel_fixup (vlib_main_t *vm,
+                               vnet_interface_per_thread_data_t *ptd,
+                               vlib_buffer_t *sb0)
 {
   u16 n_tx_bufs = vec_len (ptd->split_buffers);
-  u16 i = 0, n_tx_bytes = 0;
+  u16 i = 0;
 
   while (i < n_tx_bufs)
     {
       vlib_buffer_t *b0 = vlib_get_buffer (vm, ptd->split_buffers[i]);
-      vnet_get_outer_header (b0, gho);
-      clib_memcpy_fast (vlib_buffer_get_current (b0),
-                       vlib_buffer_get_current (sb0), gho->outer_hdr_sz);
 
-      tso_segment_vxlan_tunnel_headers_fixup (vm, b0, gho);
-      n_tx_bytes += gho->outer_hdr_sz;
+      tso_segment_vxlan_tunnel_headers_fixup (vm, b0);
       i++;
     }
-  return n_tx_bytes;
 }
 
 static_always_inline u16
@@ -444,6 +457,15 @@ tso_segment_buffer (vlib_main_t * vm, vnet_interface_per_thread_data_t * ptd,
   return n_tx_bytes;
 }
 
+__clib_unused u32
+gso_segment_buffer (vlib_main_t *vm, vnet_interface_per_thread_data_t *ptd,
+                   u32 bi, vlib_buffer_t *b, generic_header_offset_t *gho,
+                   u32 n_bytes_b, u8 is_l2, u8 is_ip6)
+{
+
+  return tso_segment_buffer (vm, ptd, bi, b, gho, n_bytes_b, is_l2, is_ip6);
+}
+
 static_always_inline void
 drop_one_buffer_and_count (vlib_main_t * vm, vnet_main_t * vnm,
                           vlib_node_runtime_t * node, u32 * pbi0,
@@ -459,9 +481,8 @@ drop_one_buffer_and_count (vlib_main_t * vm, vnet_main_t * vnm,
 
   vlib_error_drop_buffers (vm, node, pbi0,
                           /* buffer stride */ 1,
-                          /* n_buffers */ 1,
-                          VNET_INTERFACE_OUTPUT_NEXT_DROP,
-                          node->node_index, drop_error_code);
+                          /* n_buffers */ 1, GSO_NEXT_DROP, node->node_index,
+                          drop_error_code);
 }
 
 static_always_inline uword
@@ -523,28 +544,28 @@ vnet_gso_node_inline (vlib_main_t * vm,
            if (PREDICT_FALSE (hi->sw_if_index != swif0))
              {
                hi0 = vnet_get_sup_hw_interface (vnm, swif0);
-               if ((hi0->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO) == 0 &&
+               if ((hi0->caps & VNET_HW_IF_CAP_TCP_GSO) == 0 &&
                    (b[0]->flags & VNET_BUFFER_F_GSO))
                  break;
              }
            if (PREDICT_FALSE (hi->sw_if_index != swif1))
              {
                hi1 = vnet_get_sup_hw_interface (vnm, swif1);
-               if (!(hi1->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO) &&
+               if (!(hi1->caps & VNET_HW_IF_CAP_TCP_GSO) &&
                    (b[1]->flags & VNET_BUFFER_F_GSO))
                  break;
              }
            if (PREDICT_FALSE (hi->sw_if_index != swif2))
              {
                hi2 = vnet_get_sup_hw_interface (vnm, swif2);
-               if ((hi2->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO) == 0 &&
+               if ((hi2->caps & VNET_HW_IF_CAP_TCP_GSO) == 0 &&
                    (b[2]->flags & VNET_BUFFER_F_GSO))
                  break;
              }
            if (PREDICT_FALSE (hi->sw_if_index != swif3))
              {
                hi3 = vnet_get_sup_hw_interface (vnm, swif3);
-               if (!(hi3->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO) &&
+               if (!(hi3->caps & VNET_HW_IF_CAP_TCP_GSO) &&
                    (b[3]->flags & VNET_BUFFER_F_GSO))
                  break;
              }
@@ -555,6 +576,7 @@ vnet_gso_node_inline (vlib_main_t * vm,
                t0->flags = b[0]->flags & VNET_BUFFER_F_GSO;
                t0->gso_size = vnet_buffer2 (b[0])->gso_size;
                t0->gso_l4_hdr_sz = vnet_buffer2 (b[0])->gso_l4_hdr_sz;
+               clib_memset (&t0->gho, 0, sizeof (t0->gho));
                vnet_generic_header_offset_parser (b[0], &t0->gho, is_l2,
                                                   is_ip4, is_ip6);
              }
@@ -564,6 +586,7 @@ vnet_gso_node_inline (vlib_main_t * vm,
                t1->flags = b[1]->flags & VNET_BUFFER_F_GSO;
                t1->gso_size = vnet_buffer2 (b[1])->gso_size;
                t1->gso_l4_hdr_sz = vnet_buffer2 (b[1])->gso_l4_hdr_sz;
+               clib_memset (&t1->gho, 0, sizeof (t1->gho));
                vnet_generic_header_offset_parser (b[1], &t1->gho, is_l2,
                                                   is_ip4, is_ip6);
              }
@@ -573,6 +596,7 @@ vnet_gso_node_inline (vlib_main_t * vm,
                t2->flags = b[2]->flags & VNET_BUFFER_F_GSO;
                t2->gso_size = vnet_buffer2 (b[2])->gso_size;
                t2->gso_l4_hdr_sz = vnet_buffer2 (b[2])->gso_l4_hdr_sz;
+               clib_memset (&t2->gho, 0, sizeof (t2->gho));
                vnet_generic_header_offset_parser (b[2], &t2->gho, is_l2,
                                                   is_ip4, is_ip6);
              }
@@ -582,6 +606,7 @@ vnet_gso_node_inline (vlib_main_t * vm,
                t3->flags = b[3]->flags & VNET_BUFFER_F_GSO;
                t3->gso_size = vnet_buffer2 (b[3])->gso_size;
                t3->gso_l4_hdr_sz = vnet_buffer2 (b[3])->gso_l4_hdr_sz;
+               clib_memset (&t3->gho, 0, sizeof (t3->gho));
                vnet_generic_header_offset_parser (b[3], &t3->gho, is_l2,
                                                   is_ip4, is_ip6);
              }
@@ -615,7 +640,7 @@ vnet_gso_node_inline (vlib_main_t * vm,
          if (PREDICT_FALSE (hi->sw_if_index != swif0))
            {
              hi0 = vnet_get_sup_hw_interface (vnm, swif0);
-             if ((hi0->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO) == 0 &&
+             if ((hi0->caps & VNET_HW_IF_CAP_TCP_GSO) == 0 &&
                  (b[0]->flags & VNET_BUFFER_F_GSO))
                do_segmentation0 = 1;
            }
@@ -635,6 +660,7 @@ vnet_gso_node_inline (vlib_main_t * vm,
              t0->flags = b[0]->flags & VNET_BUFFER_F_GSO;
              t0->gso_size = vnet_buffer2 (b[0])->gso_size;
              t0->gso_l4_hdr_sz = vnet_buffer2 (b[0])->gso_l4_hdr_sz;
+             clib_memset (&t0->gho, 0, sizeof (t0->gho));
              vnet_generic_header_offset_parser (b[0], &t0->gho, is_l2,
                                                 is_ip4, is_ip6);
            }
@@ -651,62 +677,29 @@ vnet_gso_node_inline (vlib_main_t * vm,
                  to_next -= 1;
                  n_left_to_next += 1;
                  /* undo the counting. */
-                 generic_header_offset_t gho = { 0 };
-                 u32 n_bytes_b0 = vlib_buffer_length_in_chain (vm, b[0]);
                  u32 n_tx_bytes = 0;
-                 u32 inner_is_ip6 = is_ip6;
-
-                 vnet_generic_header_offset_parser (b[0], &gho, is_l2,
-                                                    is_ip4, is_ip6);
-
-                 if (PREDICT_FALSE (gho.gho_flags & GHO_F_TUNNEL))
-                   {
-                     if (PREDICT_FALSE
-                         (gho.gho_flags & (GHO_F_GRE_TUNNEL |
-                                           GHO_F_GENEVE_TUNNEL)))
-                       {
-                         /* not supported yet */
-                         drop_one_buffer_and_count (vm, vnm, node, from - 1,
-                                                    hi->sw_if_index,
-                                                    VNET_INTERFACE_OUTPUT_ERROR_UNHANDLED_GSO_TYPE);
-                         b += 1;
-                         continue;
-                       }
-
-                     vnet_get_inner_header (b[0], &gho);
-
-                     n_bytes_b0 -= gho.outer_hdr_sz;
-                     inner_is_ip6 = (gho.gho_flags & GHO_F_IP6) != 0;
-                   }
 
                  n_tx_bytes =
-                   tso_segment_buffer (vm, ptd, bi0, b[0], &gho, n_bytes_b0,
-                                       is_l2, inner_is_ip6);
+                   gso_segment_buffer_inline (vm, ptd, b[0], is_l2);
 
                  if (PREDICT_FALSE (n_tx_bytes == 0))
                    {
                      drop_one_buffer_and_count (vm, vnm, node, from - 1,
                                                 hi->sw_if_index,
-                                                VNET_INTERFACE_OUTPUT_ERROR_NO_BUFFERS_FOR_GSO);
+                                                GSO_ERROR_NO_BUFFERS);
                      b += 1;
                      continue;
                    }
 
-
-                 if (PREDICT_FALSE (gho.gho_flags & GHO_F_VXLAN_TUNNEL))
+                 if (PREDICT_FALSE (vnet_buffer (b[0])->oflags &
+                                    VNET_BUFFER_OFFLOAD_F_TNL_VXLAN))
                    {
-                     vnet_get_outer_header (b[0], &gho);
-                     n_tx_bytes +=
-                       tso_segment_vxlan_tunnel_fixup (vm, ptd, b[0], &gho);
+                     tso_segment_vxlan_tunnel_fixup (vm, ptd, b[0]);
                    }
-                 else
-                   if (PREDICT_FALSE
-                       (gho.gho_flags & (GHO_F_IPIP_TUNNEL |
-                                         GHO_F_IPIP6_TUNNEL)))
+                 else if (PREDICT_FALSE (vnet_buffer (b[0])->oflags &
+                                         VNET_BUFFER_OFFLOAD_F_TNL_IPIP))
                    {
-                     vnet_get_outer_header (b[0], &gho);
-                     n_tx_bytes +=
-                       tso_segment_ipip_tunnel_fixup (vm, ptd, b[0], &gho);
+                     tso_segment_ipip_tunnel_fixup (vm, ptd, b[0]);
                    }
 
                  u16 n_tx_bufs = vec_len (ptd->split_buffers);
@@ -740,7 +733,7 @@ vnet_gso_node_inline (vlib_main_t * vm,
                                             to_next, n_left_to_next);
                    }
                  /* The buffers were enqueued. Reset the length */
-                 _vec_len (ptd->split_buffers) = 0;
+                 vec_set_len (ptd->split_buffers, 0);
                  /* Free the now segmented buffer */
                  vlib_buffer_free_one (vm, bi0);
                  b += 1;
@@ -774,7 +767,7 @@ vnet_gso_inline (vlib_main_t * vm,
       hi = vnet_get_sup_hw_interface (vnm,
                                      vnet_buffer (b)->sw_if_index[VLIB_TX]);
 
-      if (hi->flags & VNET_HW_INTERFACE_FLAG_SUPPORTS_GSO)
+      if (hi->caps & (VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_VXLAN_TNL_GSO))
        return vnet_gso_node_inline (vm, node, frame, vnm, hi,
                                     is_l2, is_ip4, is_ip6,
                                     /* do_segmentation */ 0);
@@ -814,14 +807,17 @@ VLIB_NODE_FN (gso_ip6_node) (vlib_main_t * vm, vlib_node_runtime_t * node,
                          1 /* ip6 */ );
 }
 
-/* *INDENT-OFF* */
 
 VLIB_REGISTER_NODE (gso_l2_ip4_node) = {
   .vector_size = sizeof (u32),
   .format_trace = format_gso_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = 0,
-  .n_next_nodes = 0,
+  .n_errors = ARRAY_LEN(gso_error_strings),
+  .error_strings = gso_error_strings,
+  .n_next_nodes = GSO_N_NEXT,
+  .next_nodes = {
+        [GSO_NEXT_DROP] = "error-drop",
+  },
   .name = "gso-l2-ip4",
 };
 
@@ -829,8 +825,12 @@ VLIB_REGISTER_NODE (gso_l2_ip6_node) = {
   .vector_size = sizeof (u32),
   .format_trace = format_gso_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = 0,
-  .n_next_nodes = 0,
+  .n_errors = ARRAY_LEN(gso_error_strings),
+  .error_strings = gso_error_strings,
+  .n_next_nodes = GSO_N_NEXT,
+  .next_nodes = {
+        [GSO_NEXT_DROP] = "error-drop",
+  },
   .name = "gso-l2-ip6",
 };
 
@@ -838,8 +838,12 @@ VLIB_REGISTER_NODE (gso_ip4_node) = {
   .vector_size = sizeof (u32),
   .format_trace = format_gso_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = 0,
-  .n_next_nodes = 0,
+  .n_errors = ARRAY_LEN(gso_error_strings),
+  .error_strings = gso_error_strings,
+  .n_next_nodes = GSO_N_NEXT,
+  .next_nodes = {
+        [GSO_NEXT_DROP] = "error-drop",
+  },
   .name = "gso-ip4",
 };
 
@@ -847,8 +851,12 @@ VLIB_REGISTER_NODE (gso_ip6_node) = {
   .vector_size = sizeof (u32),
   .format_trace = format_gso_trace,
   .type = VLIB_NODE_TYPE_INTERNAL,
-  .n_errors = 0,
-  .n_next_nodes = 0,
+  .n_errors = ARRAY_LEN(gso_error_strings),
+  .error_strings = gso_error_strings,
+  .n_next_nodes = GSO_N_NEXT,
+  .next_nodes = {
+        [GSO_NEXT_DROP] = "error-drop",
+  },
   .name = "gso-ip6",
 };