af_packet: invalid TCP/UDP offload checksum on RX node recalculation 38/8938/4
authorJakub Grajciar <Jakub.Grajciar@pantheon.tech>
Fri, 20 Oct 2017 11:37:28 +0000 (13:37 +0200)
committerDamjan Marion <dmarion.lists@gmail.com>
Mon, 23 Oct 2017 16:00:38 +0000 (16:00 +0000)
Change-Id: I1075e5d2a1b6dfe3a443b40b41b8458a30505680
Signed-off-by: Jakub Grajciar <Jakub.Grajciar@pantheon.tech>
Signed-off-by: Jakub.Grajciar@pantheon.tech <Jakub.Grajciar@pantheon.tech>
src/vnet/devices/af_packet/af_packet.api
src/vnet/devices/af_packet/af_packet.c
src/vnet/devices/af_packet/af_packet.h
src/vnet/devices/af_packet/af_packet_api.c
src/vnet/devices/af_packet/cli.c
src/vnet/devices/af_packet/node.c

index f815042..a1b30d5 100644 (file)
@@ -56,6 +56,19 @@ autoreply define af_packet_delete
   u8 host_if_name[64];
 };
 
+/** \brief Set l4 offload ckecksum calculation
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+autoreply define af_packet_set_l4_cksum_offload
+{
+  u32 client_index;
+  u32 context;
+  
+  u8 sw_if_index;
+  u8 set;
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
index 3269601..e7bbdfd 100644 (file)
@@ -406,6 +406,22 @@ af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name)
   return 0;
 }
 
+int
+af_packet_set_l4_cksum_offload (vlib_main_t * vm, u32 sw_if_index, u8 set)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_hw_interface_t *hw;
+
+  hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
+
+  if (set)
+    hw->flags &= ~VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD;
+  else
+    hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_TX_L4_CKSUM_OFFLOAD;
+
+  return 0;
+}
+
 static clib_error_t *
 af_packet_init (vlib_main_t * vm)
 {
index 95c7e7c..66e2dea 100644 (file)
@@ -63,6 +63,8 @@ extern vlib_node_registration_t af_packet_input_node;
 int af_packet_create_if (vlib_main_t * vm, u8 * host_if_name,
                         u8 * hw_addr_set, u32 * sw_if_index);
 int af_packet_delete_if (vlib_main_t * vm, u8 * host_if_name);
+int af_packet_set_l4_cksum_offload (vlib_main_t * vm, u32 sw_if_index,
+                                   u8 set);
 
 /*
  * fd.io coding-style-patch-verification: ON
index 414c838..c7dfabc 100644 (file)
 
 #include <vlibapi/api_helper_macros.h>
 
-#define foreach_vpe_api_msg                             \
-_(AF_PACKET_CREATE, af_packet_create)                   \
-_(AF_PACKET_DELETE, af_packet_delete)
+#define foreach_vpe_api_msg                                          \
+_(AF_PACKET_CREATE, af_packet_create)                                \
+_(AF_PACKET_DELETE, af_packet_delete)                                \
+_(AF_PACKET_SET_L4_CKSUM_OFFLOAD, af_packet_set_l4_cksum_offload)
 
 static void
 vl_api_af_packet_create_t_handler (vl_api_af_packet_create_t * mp)
@@ -90,6 +91,18 @@ vl_api_af_packet_delete_t_handler (vl_api_af_packet_delete_t * mp)
   REPLY_MACRO (VL_API_AF_PACKET_DELETE_REPLY);
 }
 
+static void
+  vl_api_af_packet_set_l4_cksum_offload_t_handler
+  (vl_api_af_packet_set_l4_cksum_offload_t * mp)
+{
+  vlib_main_t *vm = vlib_get_main ();
+  vl_api_af_packet_delete_reply_t *rmp;
+  int rv = 0;
+
+  rv = af_packet_set_l4_cksum_offload (vm, mp->sw_if_index, mp->set);
+  REPLY_MACRO (VL_API_AF_PACKET_SET_L4_CKSUM_OFFLOAD_REPLY);
+}
+
 /*
  * af_packet_api_hookup
  * Add vpe's API message handlers to the table.
index 44dc517..29c0e06 100644 (file)
@@ -194,6 +194,62 @@ VLIB_CLI_COMMAND (af_packet_delete_command, static) = {
 };
 /* *INDENT-ON* */
 
+static clib_error_t *
+af_packet_set_l4_cksum_offload_command_fn (vlib_main_t * vm,
+                                          unformat_input_t * input,
+                                          vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  u8 set = 0;
+  clib_error_t *error = NULL;
+  vnet_main_t *vnm = vnet_get_main ();
+  u32 sw_if_index;
+
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat
+         (line_input, "%U", unformat_vnet_sw_interface, vnm, &sw_if_index))
+       ;
+      else if (unformat (line_input, "on"))
+       set = 1;
+      else if (unformat (line_input, "off"))
+       set = 0;
+      else
+       {
+         error = clib_error_return (0, "unknown input '%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+  af_packet_set_l4_cksum_offload (vm, sw_if_index, set);
+
+done:
+  unformat_free (line_input);
+  return error;
+}
+
+/*?
+ * Set TCP/UDP offload checksum calculation. Use interface
+ * name to identify the interface to set TCP/UDP offload checksum
+ * calculation.
+ *
+ * @cliexpar
+ * Example of how to set TCP/UDP offload checksum calculation on host-vpp0:
+ * @cliexcmd{set host-interface l4-cksum-offload host-vpp0 off}
+ * @cliexcmd{set host-interface l4-cksum-offload host-vpp0 on}
+?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (af_packet_set_l4_cksum_offload_command, static) = {
+  .path = "set host-interface l4-cksum-offload",
+  .short_help = "set host-interface l4-cksum-offload <host-if-name> <on|off>",
+  .function = af_packet_set_l4_cksum_offload_command_fn,
+};
+/* *INDENT-ON* */
+
 clib_error_t *
 af_packet_cli_init (vlib_main_t * vm)
 {
index 8539ff5..b627cfc 100644 (file)
@@ -25,6 +25,7 @@
 #include <vnet/ethernet/ethernet.h>
 #include <vnet/devices/devices.h>
 #include <vnet/feature/feature.h>
+#include <vnet/ethernet/packet.h>
 
 #include <vnet/devices/af_packet/af_packet.h>
 
@@ -106,6 +107,71 @@ buffer_add_to_chain (vlib_main_t * vm, u32 bi, u32 first_bi, u32 prev_bi)
   b->next_buffer = 0;
 }
 
+static_always_inline void
+mark_tcp_udp_cksum_calc (vlib_buffer_t * b)
+{
+  ethernet_header_t *eth = vlib_buffer_get_current (b);
+  if (clib_net_to_host_u16 (eth->type) == ETHERNET_TYPE_IP4)
+    {
+      ip4_header_t *ip4 =
+       (vlib_buffer_get_current (b) + sizeof (ethernet_header_t));
+      b->flags |= VNET_BUFFER_F_IS_IP4;
+      if (ip4->protocol == IP_PROTOCOL_TCP)
+       {
+         b->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+         ((tcp_header_t
+           *) (vlib_buffer_get_current (b) +
+               sizeof (ethernet_header_t) +
+               ip4_header_bytes (ip4)))->checksum = 0;
+       }
+      else if (ip4->protocol == IP_PROTOCOL_UDP)
+       {
+         b->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+         ((udp_header_t
+           *) (vlib_buffer_get_current (b) +
+               sizeof (ethernet_header_t) +
+               ip4_header_bytes (ip4)))->checksum = 0;
+       }
+      vnet_buffer (b)->l3_hdr_offset = sizeof (ethernet_header_t);
+      vnet_buffer (b)->l4_hdr_offset =
+       sizeof (ethernet_header_t) + ip4_header_bytes (ip4);
+    }
+  else if (clib_net_to_host_u16 (eth->type) == ETHERNET_TYPE_IP6)
+    {
+      ip6_header_t *ip6 =
+       (vlib_buffer_get_current (b) + sizeof (ethernet_header_t));
+      b->flags |= VNET_BUFFER_F_IS_IP6;
+      u16 ip6_hdr_len = sizeof (ip6_header_t);
+      if (ip6_ext_hdr (ip6->protocol))
+       {
+         ip6_ext_header_t *p = (void *) (ip6 + 1);
+         ip6_hdr_len += ip6_ext_header_len (p);
+         while (ip6_ext_hdr (p->next_hdr))
+           {
+             ip6_hdr_len += ip6_ext_header_len (p);
+             p = ip6_ext_next_header (p);
+           }
+       }
+      if (ip6->protocol == IP_PROTOCOL_TCP)
+       {
+         b->flags |= VNET_BUFFER_F_OFFLOAD_TCP_CKSUM;
+         ((tcp_header_t
+           *) (vlib_buffer_get_current (b) +
+               sizeof (ethernet_header_t) + ip6_hdr_len))->checksum = 0;
+       }
+      else if (ip6->protocol == IP_PROTOCOL_UDP)
+       {
+         b->flags |= VNET_BUFFER_F_OFFLOAD_UDP_CKSUM;
+         ((udp_header_t
+           *) (vlib_buffer_get_current (b) +
+               sizeof (ethernet_header_t) + ip6_hdr_len))->checksum = 0;
+       }
+      vnet_buffer (b)->l3_hdr_offset = sizeof (ethernet_header_t);
+      vnet_buffer (b)->l4_hdr_offset =
+       sizeof (ethernet_header_t) + ip6_hdr_len;
+    }
+}
+
 always_inline uword
 af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
                           vlib_frame_t * frame, af_packet_if_t * apif)
@@ -211,6 +277,8 @@ af_packet_device_input_fn (vlib_main_t * vm, vlib_node_runtime_t * node,
                  vnet_buffer (b0)->sw_if_index[VLIB_TX] = (u32) ~ 0;
                  first_bi0 = bi0;
                  first_b0 = vlib_get_buffer (vm, first_bi0);
+                 if (tph->tp_status & TP_STATUS_CSUMNOTREADY)
+                   mark_tcp_udp_cksum_calc (first_b0);
                }
              else
                buffer_add_to_chain (vm, bi0, first_bi0, prev_bi0);