ipv6: Allow for partial checksums on non-ufo packets
authorVlad Yasevich <vyasevich@gmail.com>
Sat, 31 Jan 2015 15:40:18 +0000 (10:40 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 3 Feb 2015 03:28:05 +0000 (19:28 -0800)
Currntly, if we are not doing UFO on the packet, all UDP
packets will start with CHECKSUM_NONE and thus perform full
checksum computations in software even if device support
IPv6 checksum offloading.

Let's start start with CHECKSUM_PARTIAL if the device
supports it and we are sending only a single packet at
or below mtu size.

Signed-off-by: Vladislav Yasevich <vyasevic@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv6/ip6_output.c

index b89d3c27dac7a5001084a7430b0c8e2a5b7a3dc2..1a036f35d833e2555b915fadcd66317676eeeac8 100644 (file)
@@ -1227,6 +1227,7 @@ static int __ip6_append_data(struct sock *sk,
        u32 tskey = 0;
        struct rt6_info *rt = (struct rt6_info *)cork->dst;
        struct ipv6_txoptions *opt = v6_cork->opt;
+       int csummode = CHECKSUM_NONE;
 
        skb = skb_peek_tail(queue);
        if (!skb) {
@@ -1283,6 +1284,14 @@ emsgsize:
                        tskey = sk->sk_tskey++;
        }
 
+       /* If this is the first and only packet and device
+        * supports checksum offloading, let's use it.
+        */
+       if (!skb &&
+           length + fragheaderlen < mtu &&
+           rt->dst.dev->features & NETIF_F_V6_CSUM &&
+           !exthdrlen)
+               csummode = CHECKSUM_PARTIAL;
        /*
         * Let's try using as much space as possible.
         * Use MTU if total length of the message fits into the MTU.
@@ -1395,7 +1404,7 @@ alloc_new_skb:
                         *      Fill in the control structures
                         */
                        skb->protocol = htons(ETH_P_IPV6);
-                       skb->ip_summed = CHECKSUM_NONE;
+                       skb->ip_summed = csummode;
                        skb->csum = 0;
                        /* reserve for fragmentation and ipsec header */
                        skb_reserve(skb, hh_len + sizeof(struct frag_hdr) +