From: Jesse Gross Date: Sat, 19 Jun 2010 00:11:44 +0000 (-0700) Subject: datapath: Don't compute checksums on partial packets. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9fc10ed911312c9cec86ef968877cae568770151;p=openvswitch datapath: Don't compute checksums on partial packets. 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. --- diff --git a/datapath/datapath.c b/datapath/datapath.c index 491f98a5..c715f0ec 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -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) {