datapath: Don't compute checksums on partial packets.
authorJesse Gross <jesse@nicira.com>
Sat, 19 Jun 2010 00:11:44 +0000 (17:11 -0700)
committerJesse Gross <jesse@nicira.com>
Sat, 19 Jun 2010 00:11:44 +0000 (17:11 -0700)
If we are only copying part of a packet to userspace don't bother
computing the checksum on that part since it is meaningless.
Instead, fall back to the old method of checksumming before
copying to ensure the correct result.

This was supposed to be part of the previous commit but was left
off.

datapath/datapath.c

index 491f98a..c715f0e 100644 (file)
@@ -744,16 +744,6 @@ queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue,
                nskb = skb->next;
                skb->next = NULL;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-               /* Until 2.6.22, the start of the transport header was
-                * also the start of data to be checksummed.  Linux
-                * 2.6.22 introduced the csum_start field for this
-                * purpose, but we should point the transport header to
-                * it anyway for backward compatibility, as
-                * dev_queue_xmit() does even in 2.6.28. */
-               skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb));
-#endif
-
                err = skb_cow(skb, sizeof *header);
                if (err)
                        goto err_kfree_skbs;
@@ -2201,19 +2191,25 @@ success:
        
        retval = 0;
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
-               __wsum csum = 0;
-               int csum_start, csum_offset;
+               if (copy_bytes == skb->len) {
+                       __wsum csum = 0;
+                       int csum_start, csum_offset;
 
-               csum_start = skb_transport_header(skb) - skb->data;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
-               csum_offset = skb->csum_offset;
+                       /* Until 2.6.22, the start of the transport header was
+                        * also the start of data to be checksummed.  Linux
+                        * 2.6.22 introduced the csum_start field for this
+                        * purpose, but we should point the transport header to
+                        * it anyway for backward compatibility, as
+                        * dev_queue_xmit() does even in 2.6.28. */
+                       skb_set_transport_header(skb, skb->csum_start - skb_headroom(skb));
+                       csum_offset = skb->csum_offset;
 #else
-               csum_offset = skb->csum;
+                       csum_offset = skb->csum;
 #endif
-               if (csum_start + csum_offset + sizeof(__sum16) <= copy_bytes) {
+                       csum_start = skb_transport_header(skb) - skb->data;
                        retval = skb_copy_and_csum_datagram(skb, csum_start, buf + csum_start,
                                                            copy_bytes - csum_start, &csum);
-
                        if (!retval) {
                                __sum16 __user *csump;
 
@@ -2221,7 +2217,8 @@ success:
                                csump = (__sum16 __user *)(buf + csum_start + csum_offset);
                                put_user(csum_fold(csum), csump);
                        }
-               }
+               } else
+                       retval = skb_checksum_help(skb);
        }
 
        if (!retval) {