net: Save software checksum complete
authorTom Herbert <therbert@google.com>
Wed, 11 Jun 2014 01:54:19 +0000 (18:54 -0700)
committerDavid S. Miller <davem@davemloft.net>
Wed, 11 Jun 2014 22:46:13 +0000 (15:46 -0700)
In skb_checksum complete, if we need to compute the checksum for the
packet (via skb_checksum) save the result as CHECKSUM_COMPLETE.
Subsequent checksum verification can use this.

Also, added csum_complete_sw flag to distinguish between software and
hardware generated checksum complete, we should always be able to trust
the software computation.

Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/skbuff.h
net/core/datagram.c
net/ipv4/gre_offload.c
net/sunrpc/socklib.c

index 72a53805858a8e3a8a51d0d88e5c1f9871085edf..5b5cd3189c985f89a055e35d8d1c67c63879d8fc 100644 (file)
@@ -573,7 +573,8 @@ struct sk_buff {
        __u8                    encapsulation:1;
        __u8                    encap_hdr_csum:1;
        __u8                    csum_valid:1;
-       /* 4/6 bit hole (depending on ndisc_nodetype presence) */
+       __u8                    csum_complete_sw:1;
+       /* 3/5 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
 #if defined CONFIG_NET_DMA || defined CONFIG_NET_RX_BUSY_POLL
index a16ed7bbe37689007e1fabed938076619c65a2e2..6b1c04ca1d5090410f436fbf74e50813e09634c3 100644 (file)
@@ -739,11 +739,15 @@ __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len)
        __sum16 sum;
 
        sum = csum_fold(skb_checksum(skb, 0, len, skb->csum));
-       if (likely(!sum)) {
-               if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
-                       netdev_rx_csum_fault(skb->dev);
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
-       }
+       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && !sum &&
+           !skb->csum_complete_sw)
+               netdev_rx_csum_fault(skb->dev);
+
+       /* Save checksum complete for later use */
+       skb->csum = sum;
+       skb->ip_summed = CHECKSUM_COMPLETE;
+       skb->csum_complete_sw = 1;
+
        return sum;
 }
 EXPORT_SYMBOL(__skb_checksum_complete_head);
index 24deb3928b9e005f70eb62e4324274eb9ccf9ca3..eb92deb12666fb56b6a289c55b8205fc27117933 100644 (file)
@@ -131,10 +131,12 @@ static __sum16 gro_skb_checksum(struct sk_buff *skb)
                csum_partial(skb->data, skb_gro_offset(skb), 0));
        sum = csum_fold(NAPI_GRO_CB(skb)->csum);
        if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) {
-               if (unlikely(!sum))
+               if (unlikely(!sum) && !skb->csum_complete_sw)
                        netdev_rx_csum_fault(skb->dev);
-       } else
+       } else {
                skb->ip_summed = CHECKSUM_COMPLETE;
+               skb->csum_complete_sw = 1;
+       }
 
        return sum;
 }
index 0a648c502fc35e1f905fdd81667b4553d255932d..2df87f78e518eab4f4fedd37eb38de1ae6c8aaea 100644 (file)
@@ -173,7 +173,8 @@ int csum_partial_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
                return -1;
        if (csum_fold(desc.csum))
                return -1;
-       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE))
+       if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) &&
+           !skb->csum_complete_sw)
                netdev_rx_csum_fault(skb->dev);
        return 0;
 no_checksum: