udp: Changes to udp_offload to support remote checksum offload
authorTom Herbert <therbert@google.com>
Tue, 4 Nov 2014 17:06:54 +0000 (09:06 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 5 Nov 2014 21:30:03 +0000 (16:30 -0500)
Add a new GSO type, SKB_GSO_TUNNEL_REMCSUM, which indicates remote
checksum offload being done (in this case inner checksum must not
be offloaded to the NIC).

Added logic in __skb_udp_tunnel_segment to handle remote checksum
offload case.

Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/skbuff.h
net/core/skbuff.c
net/ipv4/af_inet.c
net/ipv4/tcp_offload.c
net/ipv4/udp_offload.c
net/ipv6/ip6_offload.c
net/ipv6/udp_offload.c

index dcfdecbfa0b711e52f3f629ec02ea3cbd70a6c1d..8c94b07e654a46c7de8eddc79c49202a2f68f461 100644 (file)
@@ -48,8 +48,9 @@ enum {
        NETIF_F_GSO_UDP_TUNNEL_BIT,     /* ... UDP TUNNEL with TSO */
        NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT,/* ... UDP TUNNEL with TSO & CSUM */
        NETIF_F_GSO_MPLS_BIT,           /* ... MPLS segmentation */
+       NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */
        /**/NETIF_F_GSO_LAST =          /* last bit, see GSO_MASK */
-               NETIF_F_GSO_MPLS_BIT,
+               NETIF_F_GSO_TUNNEL_REMCSUM_BIT,
 
        NETIF_F_FCOE_CRC_BIT,           /* FCoE CRC32 */
        NETIF_F_SCTP_CSUM_BIT,          /* SCTP checksum offload */
@@ -119,6 +120,7 @@ enum {
 #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL)
 #define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM)
 #define NETIF_F_GSO_MPLS       __NETIF_F(GSO_MPLS)
+#define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM)
 #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
 #define NETIF_F_HW_VLAN_STAG_RX        __NETIF_F(HW_VLAN_STAG_RX)
 #define NETIF_F_HW_VLAN_STAG_TX        __NETIF_F(HW_VLAN_STAG_TX)
index 5ed05bd764dcf3699afdd9a7b17600246de22d1d..4767f546d7c07d11e091558861c608c5c43a770c 100644 (file)
@@ -3584,6 +3584,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type)
        BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT));
        BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT));
        BUILD_BUG_ON(SKB_GSO_MPLS    != (NETIF_F_GSO_MPLS >> NETIF_F_GSO_SHIFT));
+       BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT));
 
        return (features & feature) == feature;
 }
index 5ad9675b6fe17b2819476c181a4707780a2e03f2..74ed3441396929b498916fea43d43c89ca3ad1ec 100644 (file)
@@ -373,6 +373,7 @@ enum {
 
        SKB_GSO_MPLS = 1 << 12,
 
+       SKB_GSO_TUNNEL_REMCSUM = 1 << 13,
 };
 
 #if BITS_PER_LONG > 32
@@ -603,7 +604,8 @@ struct sk_buff {
 #endif
        __u8                    ipvs_property:1;
        __u8                    inner_protocol_type:1;
-       /* 4 or 6 bit hole */
+       __u8                    remcsum_offload:1;
+       /* 3 or 5 bit hole */
 
 #ifdef CONFIG_NET_SCHED
        __u16                   tc_index;       /* traffic control index */
index e48e5c02e877d9a9389ea54f0e015ba041d3f2a7..700189604f3d90a855bee2a712a60cf77f1cac02 100644 (file)
@@ -3013,7 +3013,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
                if (nskb->len == len + doffset)
                        goto perform_csum_check;
 
-               if (!sg) {
+               if (!sg && !nskb->remcsum_offload) {
                        nskb->ip_summed = CHECKSUM_NONE;
                        nskb->csum = skb_copy_and_csum_bits(head_skb, offset,
                                                            skb_put(nskb, len),
@@ -3085,7 +3085,7 @@ skip_fraglist:
                nskb->truesize += nskb->data_len;
 
 perform_csum_check:
-               if (!csum) {
+               if (!csum && !nskb->remcsum_offload) {
                        nskb->csum = skb_checksum(nskb, doffset,
                                                  nskb->len - doffset, 0);
                        nskb->ip_summed = CHECKSUM_NONE;
index 8b7fe5b039068559a931b931529f02841cc13fe2..ed2c672c5b01d0522203beeb1a1963165e740d82 100644 (file)
@@ -1222,6 +1222,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
                       SKB_GSO_TCPV6 |
                       SKB_GSO_UDP_TUNNEL |
                       SKB_GSO_UDP_TUNNEL_CSUM |
+                      SKB_GSO_TUNNEL_REMCSUM |
                       SKB_GSO_MPLS |
                       0)))
                goto out;
index 5b90f2f447a511703bbce1e22e8ef55888c43479..a1b2a5624f91cfc08c7aff20bc05da4e24a97147 100644 (file)
@@ -97,6 +97,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
                               SKB_GSO_MPLS |
                               SKB_GSO_UDP_TUNNEL |
                               SKB_GSO_UDP_TUNNEL_CSUM |
+                              SKB_GSO_TUNNEL_REMCSUM |
                               0) ||
                             !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
                        goto out;
index a774711a88b9de0a11a00df68462c6b824f929f1..0a5a70d0e84c083e1d09d5f52105eb0ad309907d 100644 (file)
@@ -41,7 +41,8 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
        unsigned int oldlen;
        bool need_csum = !!(skb_shinfo(skb)->gso_type &
                            SKB_GSO_UDP_TUNNEL_CSUM);
-       bool offload_csum = false, dont_encap = need_csum;
+       bool remcsum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TUNNEL_REMCSUM);
+       bool offload_csum = false, dont_encap = (need_csum || remcsum);
 
        oldlen = (u16)~skb->len;
 
@@ -55,6 +56,7 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
        skb->mac_len = skb_inner_network_offset(skb);
        skb->protocol = new_protocol;
        skb->encap_hdr_csum = need_csum;
+       skb->remcsum_offload = remcsum;
 
        /* Try to offload checksum if possible */
        offload_csum = !!(need_csum &&
@@ -108,11 +110,22 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
                uh->check = ~csum_fold((__force __wsum)
                                       ((__force u32)uh->check +
                                        (__force u32)delta));
-
                if (offload_csum) {
                        skb->ip_summed = CHECKSUM_PARTIAL;
                        skb->csum_start = skb_transport_header(skb) - skb->head;
                        skb->csum_offset = offsetof(struct udphdr, check);
+               } else if (remcsum) {
+                       /* Need to calculate checksum from scratch,
+                        * inner checksums are never when doing
+                        * remote_checksum_offload.
+                        */
+
+                       skb->csum = skb_checksum(skb, udp_offset,
+                                                skb->len - udp_offset,
+                                                0);
+                       uh->check = csum_fold(skb->csum);
+                       if (uh->check == 0)
+                               uh->check = CSUM_MANGLED_0;
                } else {
                        uh->check = gso_make_checksum(skb, ~uh->check);
 
@@ -192,6 +205,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
                if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY |
                                      SKB_GSO_UDP_TUNNEL |
                                      SKB_GSO_UDP_TUNNEL_CSUM |
+                                     SKB_GSO_TUNNEL_REMCSUM |
                                      SKB_GSO_IPIP |
                                      SKB_GSO_GRE | SKB_GSO_GRE_CSUM |
                                      SKB_GSO_MPLS) ||
index a071563a7e6e9c1f6d0fa9d8490c1d35ce89b3f7..e9767079a36080668a6266ae77de91ca79151989 100644 (file)
@@ -78,6 +78,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
                       SKB_GSO_SIT |
                       SKB_GSO_UDP_TUNNEL |
                       SKB_GSO_UDP_TUNNEL_CSUM |
+                      SKB_GSO_TUNNEL_REMCSUM |
                       SKB_GSO_MPLS |
                       SKB_GSO_TCPV6 |
                       0)))
index 6b8f543f6ac6ac76c2efaec21b4489fe347f9544..637ba2e438b73e017ec9530e861e0f8711fd234a 100644 (file)
@@ -42,6 +42,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
                                      SKB_GSO_DODGY |
                                      SKB_GSO_UDP_TUNNEL |
                                      SKB_GSO_UDP_TUNNEL_CSUM |
+                                     SKB_GSO_TUNNEL_REMCSUM |
                                      SKB_GSO_GRE |
                                      SKB_GSO_GRE_CSUM |
                                      SKB_GSO_IPIP |