Make tcp/udp/icmp compute checksum safer for buffer-chain case
[vpp.git] / src / vnet / ip / ip6_forward.c
index 8e96647..6df3d4b 100644 (file)
@@ -54,6 +54,7 @@
 #include <vppinfra/bihash_template.c>
 #endif
 #include <vnet/ip/ip6_forward.h>
+#include <vnet/interface_output.h>
 
 /* Flag used by IOAM code. Classifier sets it pop-hop-by-hop checks it */
 #define OI_DECAP   0x80000000
@@ -1010,7 +1011,7 @@ ip6_tcp_udp_icmp_compute_checksum (vlib_main_t * vm, vlib_buffer_t * p0,
        }
       p0 = vlib_get_buffer (vm, p0->next_buffer);
       data_this_buffer = vlib_buffer_get_current (p0);
-      n_this_buffer = p0->current_length;
+      n_this_buffer = clib_min (p0->current_length, n_bytes_left);
     }
 
   sum16 = ~ip_csum_fold (sum0);
@@ -1622,10 +1623,11 @@ ip6_mtu_check (vlib_buffer_t * b, u16 packet_bytes,
 }
 
 always_inline uword
-ip6_rewrite_inline (vlib_main_t * vm,
-                   vlib_node_runtime_t * node,
-                   vlib_frame_t * frame,
-                   int do_counters, int is_midchain, int is_mcast)
+ip6_rewrite_inline_with_gso (vlib_main_t * vm,
+                            vlib_node_runtime_t * node,
+                            vlib_frame_t * frame,
+                            int do_counters, int is_midchain, int is_mcast,
+                            int do_gso)
 {
   ip_lookup_main_t *lm = &ip6_main.lookup_main;
   u32 *from = vlib_frame_vector_args (frame);
@@ -1771,17 +1773,28 @@ ip6_rewrite_inline (vlib_main_t * vm,
            }
 
          /* Check MTU of outgoing interface. */
-         ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
-                        sizeof (ip6_header_t),
+         u16 ip0_len =
+           clib_net_to_host_u16 (ip0->payload_length) +
+           sizeof (ip6_header_t);
+         u16 ip1_len =
+           clib_net_to_host_u16 (ip1->payload_length) +
+           sizeof (ip6_header_t);
+         if (do_gso && (p0->flags & VNET_BUFFER_F_GSO))
+           ip0_len = gso_mtu_sz (p0);
+         if (do_gso && (p1->flags & VNET_BUFFER_F_GSO))
+           ip1_len = gso_mtu_sz (p1);
+
+
+
+         ip6_mtu_check (p0, ip0_len,
                         adj0[0].rewrite_header.max_l3_packet_bytes,
                         is_locally_originated0, &next0, &error0);
-         ip6_mtu_check (p1, clib_net_to_host_u16 (ip1->payload_length) +
-                        sizeof (ip6_header_t),
+         ip6_mtu_check (p1, ip1_len,
                         adj1[0].rewrite_header.max_l3_packet_bytes,
                         is_locally_originated1, &next1, &error1);
 
          /* Don't adjust the buffer for hop count issue; icmp-error node
-          * wants to see the IP headerr */
+          * wants to see the IP header */
          if (PREDICT_TRUE (error0 == IP6_ERROR_NONE))
            {
              p0->current_data -= rw_len0;
@@ -1796,6 +1809,10 @@ ip6_rewrite_inline (vlib_main_t * vm,
                vnet_feature_arc_start (lm->output_feature_arc_index,
                                        tx_sw_if_index0, &next0, p0);
            }
+         else
+           {
+             p0->error = error_node->errors[error0];
+           }
          if (PREDICT_TRUE (error1 == IP6_ERROR_NONE))
            {
              p1->current_data -= rw_len1;
@@ -1810,6 +1827,18 @@ ip6_rewrite_inline (vlib_main_t * vm,
                vnet_feature_arc_start (lm->output_feature_arc_index,
                                        tx_sw_if_index1, &next1, p1);
            }
+         else
+           {
+             p1->error = error_node->errors[error1];
+           }
+
+         if (is_midchain)
+           {
+             /* before we paint on the next header, update the L4
+              * checksums if required, since there's no offload on a tunnel */
+             calc_checksums (vm, p0);
+             calc_checksums (vm, p1);
+           }
 
          /* Guess we are only writing on simple Ethernet header. */
          vnet_rewrite_two_headers (adj0[0], adj1[0],
@@ -1817,10 +1846,12 @@ ip6_rewrite_inline (vlib_main_t * vm,
 
          if (is_midchain)
            {
-             adj0->sub_type.midchain.fixup_func
-               (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
-             adj1->sub_type.midchain.fixup_func
-               (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
+             if (adj0->sub_type.midchain.fixup_func)
+               adj0->sub_type.midchain.fixup_func
+                 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
+             if (adj1->sub_type.midchain.fixup_func)
+               adj1->sub_type.midchain.fixup_func
+                 (vm, adj1, p1, adj1->sub_type.midchain.fixup_data);
            }
          if (is_mcast)
            {
@@ -1899,6 +1930,11 @@ ip6_rewrite_inline (vlib_main_t * vm,
              p0->flags &= ~VNET_BUFFER_F_LOCALLY_ORIGINATED;
            }
 
+         if (is_midchain)
+           {
+             calc_checksums (vm, p0);
+           }
+
          /* Guess we are only writing on simple Ethernet header. */
          vnet_rewrite_one_header (adj0[0], ip0, sizeof (ethernet_header_t));
 
@@ -1915,8 +1951,13 @@ ip6_rewrite_inline (vlib_main_t * vm,
            }
 
          /* Check MTU of outgoing interface. */
-         ip6_mtu_check (p0, clib_net_to_host_u16 (ip0->payload_length) +
-                        sizeof (ip6_header_t),
+         u16 ip0_len =
+           clib_net_to_host_u16 (ip0->payload_length) +
+           sizeof (ip6_header_t);
+         if (do_gso && (p0->flags & VNET_BUFFER_F_GSO))
+           ip0_len = gso_mtu_sz (p0);
+
+         ip6_mtu_check (p0, ip0_len,
                         adj0[0].rewrite_header.max_l3_packet_bytes,
                         is_locally_originated0, &next0, &error0);
 
@@ -1937,11 +1978,16 @@ ip6_rewrite_inline (vlib_main_t * vm,
                vnet_feature_arc_start (lm->output_feature_arc_index,
                                        tx_sw_if_index0, &next0, p0);
            }
+         else
+           {
+             p0->error = error_node->errors[error0];
+           }
 
          if (is_midchain)
            {
-             adj0->sub_type.midchain.fixup_func
-               (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
+             if (adj0->sub_type.midchain.fixup_func)
+               adj0->sub_type.midchain.fixup_func
+                 (vm, adj0, p0, adj0->sub_type.midchain.fixup_data);
            }
          if (is_mcast)
            {
@@ -1952,8 +1998,6 @@ ip6_rewrite_inline (vlib_main_t * vm,
                                          (u8 *) ip0);
            }
 
-         p0->error = error_node->errors[error0];
-
          from += 1;
          n_left_from -= 1;
          to_next += 1;
@@ -1974,6 +2018,23 @@ ip6_rewrite_inline (vlib_main_t * vm,
   return frame->n_vectors;
 }
 
+always_inline uword
+ip6_rewrite_inline (vlib_main_t * vm,
+                   vlib_node_runtime_t * node,
+                   vlib_frame_t * frame,
+                   int do_counters, int is_midchain, int is_mcast)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  if (PREDICT_FALSE (vnm->interface_main.gso_interface_count > 0))
+    return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
+                                       is_midchain, is_mcast,
+                                       1 /* do_gso */ );
+  else
+    return ip6_rewrite_inline_with_gso (vm, node, frame, do_counters,
+                                       is_midchain, is_mcast,
+                                       0 /* no do_gso */ );
+}
+
 VLIB_NODE_FN (ip6_rewrite_node) (vlib_main_t * vm,
                                 vlib_node_runtime_t * node,
                                 vlib_frame_t * frame)