datapath: Call vswitch_skb_checksum_setup() before doing GSO.
authorJesse Gross <jesse@nicira.com>
Thu, 17 Jun 2010 22:15:11 +0000 (15:15 -0700)
committerJesse Gross <jesse@nicira.com>
Fri, 18 Jun 2010 18:38:10 +0000 (11:38 -0700)
Since GSO computes checksums as it does segmentation, we need to
setup the checksum pointers before calling skb_gso_segment().  Failing
to do so can potentially result in warnings, incorrect checksums,
crashes, or redundant checksum computation.  In general we don't
hit this case because the code path is run during the first packet
in a flow, which is generally not a large GSO packet.

This was found during the investigation of NIC-121 but has no impact
on it because vswitch_skb_checksum_setup() is a no-op on 2.6.27-based
XenServer kernels.

datapath/datapath.c

index 39bc190bcc9dcd816c9585c52c54094b6116d233..5907e81f28ae53b3bf1bc0857af36535394bb431 100644 (file)
@@ -743,13 +743,6 @@ queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue,
                nskb = skb->next;
                skb->next = NULL;
 
-               /* If a checksum-deferred packet is forwarded to the
-                * controller, correct the pointers and checksum.
-                */
-               err = vswitch_skb_checksum_setup(skb);
-               if (err)
-                       goto err_kfree_skbs;
-
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
@@ -810,6 +803,10 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no,
 
        forward_ip_summed(skb);
 
+       err = vswitch_skb_checksum_setup(skb);
+       if (err)
+               goto err_kfree_skb;
+
        /* Break apart GSO packets into their component pieces.  Otherwise
         * userspace may try to stuff a 64kB packet into a 1500-byte MTU. */
        if (skb_is_gso(skb)) {