igb/igbvf: Don't use lco_csum to compute IPv4 checksum
authorAlexander Duyck <alexander.h.duyck@intel.com>
Mon, 28 Nov 2016 15:42:23 +0000 (10:42 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 1 Dec 2016 20:41:35 +0000 (15:41 -0500)
In the case of IPIP and SIT tunnel frames the outer transport header
offset is actually set to the same offset as the inner transport header.
This results in the lco_csum call not doing any checksum computation over
the inner IPv4/v6 header data.

In order to account for that I am updating the code so that we determine
the location to start the checksum ourselves based on the location of the
IPv4 header and the length.

Fixes: e10715d3e961 ("igb/igbvf: Add support for GSO partial")
Reported-by: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/intel/igb/igb_main.c
drivers/net/ethernet/intel/igbvf/netdev.c

index edc9a6a..9affd7c 100644 (file)
@@ -4931,11 +4931,15 @@ static int igb_tso(struct igb_ring *tx_ring,
 
        /* initialize outer IP header fields */
        if (ip.v4->version == 4) {
+               unsigned char *csum_start = skb_checksum_start(skb);
+               unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4);
+
                /* IP header will have to cancel out any data that
                 * is not a part of the outer IP header
                 */
-               ip.v4->check = csum_fold(csum_add(lco_csum(skb),
-                                                 csum_unfold(l4.tcp->check)));
+               ip.v4->check = csum_fold(csum_partial(trans_start,
+                                                     csum_start - trans_start,
+                                                     0));
                type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
 
                ip.v4->tot_len = 0;
index 12bb877..7dff7f6 100644 (file)
@@ -1965,11 +1965,15 @@ static int igbvf_tso(struct igbvf_ring *tx_ring,
 
        /* initialize outer IP header fields */
        if (ip.v4->version == 4) {
+               unsigned char *csum_start = skb_checksum_start(skb);
+               unsigned char *trans_start = ip.hdr + (ip.v4->ihl * 4);
+
                /* IP header will have to cancel out any data that
                 * is not a part of the outer IP header
                 */
-               ip.v4->check = csum_fold(csum_add(lco_csum(skb),
-                                                 csum_unfold(l4.tcp->check)));
+               ip.v4->check = csum_fold(csum_partial(trans_start,
+                                                     csum_start - trans_start,
+                                                     0));
                type_tucmd |= E1000_ADVTXD_TUCMD_IPV4;
 
                ip.v4->tot_len = 0;