devices: add support for pseudo header checksum
[vpp.git] / src / vnet / devices / virtio / device.c
index 6c2fe34..ac9be6b 100644 (file)
@@ -27,6 +27,7 @@
 #include <vnet/gso/hdr_offset_parser.h>
 #include <vnet/ip/ip4_packet.h>
 #include <vnet/ip/ip6_packet.h>
+#include <vnet/ip/ip_psh_cksum.h>
 #include <vnet/tcp/tcp_packet.h>
 #include <vnet/udp/udp_packet.h>
 #include <vnet/devices/virtio/virtio.h>
@@ -296,37 +297,60 @@ set_checksum_offsets (vlib_buffer_t *b, virtio_net_hdr_v1_t *hdr,
                                         0 /* ip6 */ );
       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
       hdr->csum_start = gho.l4_hdr_offset;     // 0x22;
+
+      /*
+       * virtio devices do not support IP4 checksum offload. So driver takes
+       * care of it while doing tx.
+       */
+      ip4 = (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
+      if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
+       ip4->checksum = ip4_header_checksum (ip4);
+
+      /*
+       * virtio devices assume the l4 header is set to the checksum of the
+       * l3 pseudo-header, so we compute it before tx-ing
+       */
       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
        {
+         tcp_header_t *tcp =
+           (tcp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset);
+         tcp->checksum = ip4_pseudo_header_cksum (ip4);
          hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
        }
       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
        {
+         udp_header_t *udp =
+           (udp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset);
+         udp->checksum = ip4_pseudo_header_cksum (ip4);
          hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
        }
-
-      /*
-       * virtio devices do not support IP4 checksum offload. So driver takes care
-       * of it while doing tx.
-       */
-      ip4 =
-       (ip4_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
-      if (oflags & VNET_BUFFER_OFFLOAD_F_IP_CKSUM)
-       ip4->checksum = ip4_header_checksum (ip4);
     }
   else if (b->flags & VNET_BUFFER_F_IS_IP6)
     {
+      ip6_header_t *ip6;
       generic_header_offset_t gho = { 0 };
       vnet_generic_header_offset_parser (b, &gho, is_l2, 0 /* ip4 */ ,
                                         1 /* ip6 */ );
       hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
       hdr->csum_start = gho.l4_hdr_offset;     // 0x36;
+      ip6 = (ip6_header_t *) (vlib_buffer_get_current (b) + gho.l3_hdr_offset);
+
+      /*
+       * virtio devices assume the l4 header is set to the checksum of the
+       * l3 pseudo-header, so we compute it before tx-ing
+       */
       if (oflags & VNET_BUFFER_OFFLOAD_F_TCP_CKSUM)
        {
+         tcp_header_t *tcp =
+           (tcp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset);
+         tcp->checksum = ip6_pseudo_header_cksum (ip6);
          hdr->csum_offset = STRUCT_OFFSET_OF (tcp_header_t, checksum);
        }
       else if (oflags & VNET_BUFFER_OFFLOAD_F_UDP_CKSUM)
        {
+         udp_header_t *udp =
+           (udp_header_t *) (vlib_buffer_get_current (b) + gho.l4_hdr_offset);
+         udp->checksum = ip6_pseudo_header_cksum (ip6);
          hdr->csum_offset = STRUCT_OFFSET_OF (udp_header_t, checksum);
        }
     }