diff options
author | Tom Herbert <therbert@google.com> | 2014-11-04 12:06:54 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-05 16:30:03 -0500 |
commit | e585f23636370320bc2071ca5ba2744ae37c3e51 (patch) | |
tree | c1d9d60bd084099f3e65155dd920ee72d41a808e | |
parent | 5024c33ac354577635c5671498891eb197f3ec4d (diff) |
udp: Changes to udp_offload to support remote checksum offload
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>
-rw-r--r-- | include/linux/netdev_features.h | 4 | ||||
-rw-r--r-- | include/linux/netdevice.h | 1 | ||||
-rw-r--r-- | include/linux/skbuff.h | 4 | ||||
-rw-r--r-- | net/core/skbuff.c | 4 | ||||
-rw-r--r-- | net/ipv4/af_inet.c | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_offload.c | 1 | ||||
-rw-r--r-- | net/ipv4/udp_offload.c | 18 | ||||
-rw-r--r-- | net/ipv6/ip6_offload.c | 1 | ||||
-rw-r--r-- | net/ipv6/udp_offload.c | 1 |
9 files changed, 29 insertions, 6 deletions
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h index dcfdecbfa0b7..8c94b07e654a 100644 --- a/include/linux/netdev_features.h +++ b/include/linux/netdev_features.h | |||
@@ -48,8 +48,9 @@ enum { | |||
48 | NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ | 48 | NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ |
49 | NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT,/* ... UDP TUNNEL with TSO & CSUM */ | 49 | NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT,/* ... UDP TUNNEL with TSO & CSUM */ |
50 | NETIF_F_GSO_MPLS_BIT, /* ... MPLS segmentation */ | 50 | NETIF_F_GSO_MPLS_BIT, /* ... MPLS segmentation */ |
51 | NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */ | ||
51 | /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ | 52 | /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ |
52 | NETIF_F_GSO_MPLS_BIT, | 53 | NETIF_F_GSO_TUNNEL_REMCSUM_BIT, |
53 | 54 | ||
54 | NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ | 55 | NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ |
55 | NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */ | 56 | NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */ |
@@ -119,6 +120,7 @@ enum { | |||
119 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) | 120 | #define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) |
120 | #define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM) | 121 | #define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM) |
121 | #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) | 122 | #define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS) |
123 | #define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM) | ||
122 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) | 124 | #define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) |
123 | #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) | 125 | #define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) |
124 | #define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) | 126 | #define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 5ed05bd764dc..4767f546d7c0 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -3584,6 +3584,7 @@ static inline bool net_gso_ok(netdev_features_t features, int gso_type) | |||
3584 | BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT)); | 3584 | BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT)); |
3585 | BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT)); | 3585 | BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT)); |
3586 | BUILD_BUG_ON(SKB_GSO_MPLS != (NETIF_F_GSO_MPLS >> NETIF_F_GSO_SHIFT)); | 3586 | BUILD_BUG_ON(SKB_GSO_MPLS != (NETIF_F_GSO_MPLS >> NETIF_F_GSO_SHIFT)); |
3587 | BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT)); | ||
3587 | 3588 | ||
3588 | return (features & feature) == feature; | 3589 | return (features & feature) == feature; |
3589 | } | 3590 | } |
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5ad9675b6fe1..74ed34413969 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -373,6 +373,7 @@ enum { | |||
373 | 373 | ||
374 | SKB_GSO_MPLS = 1 << 12, | 374 | SKB_GSO_MPLS = 1 << 12, |
375 | 375 | ||
376 | SKB_GSO_TUNNEL_REMCSUM = 1 << 13, | ||
376 | }; | 377 | }; |
377 | 378 | ||
378 | #if BITS_PER_LONG > 32 | 379 | #if BITS_PER_LONG > 32 |
@@ -603,7 +604,8 @@ struct sk_buff { | |||
603 | #endif | 604 | #endif |
604 | __u8 ipvs_property:1; | 605 | __u8 ipvs_property:1; |
605 | __u8 inner_protocol_type:1; | 606 | __u8 inner_protocol_type:1; |
606 | /* 4 or 6 bit hole */ | 607 | __u8 remcsum_offload:1; |
608 | /* 3 or 5 bit hole */ | ||
607 | 609 | ||
608 | #ifdef CONFIG_NET_SCHED | 610 | #ifdef CONFIG_NET_SCHED |
609 | __u16 tc_index; /* traffic control index */ | 611 | __u16 tc_index; /* traffic control index */ |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index e48e5c02e877..700189604f3d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -3013,7 +3013,7 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb, | |||
3013 | if (nskb->len == len + doffset) | 3013 | if (nskb->len == len + doffset) |
3014 | goto perform_csum_check; | 3014 | goto perform_csum_check; |
3015 | 3015 | ||
3016 | if (!sg) { | 3016 | if (!sg && !nskb->remcsum_offload) { |
3017 | nskb->ip_summed = CHECKSUM_NONE; | 3017 | nskb->ip_summed = CHECKSUM_NONE; |
3018 | nskb->csum = skb_copy_and_csum_bits(head_skb, offset, | 3018 | nskb->csum = skb_copy_and_csum_bits(head_skb, offset, |
3019 | skb_put(nskb, len), | 3019 | skb_put(nskb, len), |
@@ -3085,7 +3085,7 @@ skip_fraglist: | |||
3085 | nskb->truesize += nskb->data_len; | 3085 | nskb->truesize += nskb->data_len; |
3086 | 3086 | ||
3087 | perform_csum_check: | 3087 | perform_csum_check: |
3088 | if (!csum) { | 3088 | if (!csum && !nskb->remcsum_offload) { |
3089 | nskb->csum = skb_checksum(nskb, doffset, | 3089 | nskb->csum = skb_checksum(nskb, doffset, |
3090 | nskb->len - doffset, 0); | 3090 | nskb->len - doffset, 0); |
3091 | nskb->ip_summed = CHECKSUM_NONE; | 3091 | nskb->ip_summed = CHECKSUM_NONE; |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8b7fe5b03906..ed2c672c5b01 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1222,6 +1222,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb, | |||
1222 | SKB_GSO_TCPV6 | | 1222 | SKB_GSO_TCPV6 | |
1223 | SKB_GSO_UDP_TUNNEL | | 1223 | SKB_GSO_UDP_TUNNEL | |
1224 | SKB_GSO_UDP_TUNNEL_CSUM | | 1224 | SKB_GSO_UDP_TUNNEL_CSUM | |
1225 | SKB_GSO_TUNNEL_REMCSUM | | ||
1225 | SKB_GSO_MPLS | | 1226 | SKB_GSO_MPLS | |
1226 | 0))) | 1227 | 0))) |
1227 | goto out; | 1228 | goto out; |
diff --git a/net/ipv4/tcp_offload.c b/net/ipv4/tcp_offload.c index 5b90f2f447a5..a1b2a5624f91 100644 --- a/net/ipv4/tcp_offload.c +++ b/net/ipv4/tcp_offload.c | |||
@@ -97,6 +97,7 @@ struct sk_buff *tcp_gso_segment(struct sk_buff *skb, | |||
97 | SKB_GSO_MPLS | | 97 | SKB_GSO_MPLS | |
98 | SKB_GSO_UDP_TUNNEL | | 98 | SKB_GSO_UDP_TUNNEL | |
99 | SKB_GSO_UDP_TUNNEL_CSUM | | 99 | SKB_GSO_UDP_TUNNEL_CSUM | |
100 | SKB_GSO_TUNNEL_REMCSUM | | ||
100 | 0) || | 101 | 0) || |
101 | !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) | 102 | !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) |
102 | goto out; | 103 | goto out; |
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c index a774711a88b9..0a5a70d0e84c 100644 --- a/net/ipv4/udp_offload.c +++ b/net/ipv4/udp_offload.c | |||
@@ -41,7 +41,8 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, | |||
41 | unsigned int oldlen; | 41 | unsigned int oldlen; |
42 | bool need_csum = !!(skb_shinfo(skb)->gso_type & | 42 | bool need_csum = !!(skb_shinfo(skb)->gso_type & |
43 | SKB_GSO_UDP_TUNNEL_CSUM); | 43 | SKB_GSO_UDP_TUNNEL_CSUM); |
44 | bool offload_csum = false, dont_encap = need_csum; | 44 | bool remcsum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TUNNEL_REMCSUM); |
45 | bool offload_csum = false, dont_encap = (need_csum || remcsum); | ||
45 | 46 | ||
46 | oldlen = (u16)~skb->len; | 47 | oldlen = (u16)~skb->len; |
47 | 48 | ||
@@ -55,6 +56,7 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, | |||
55 | skb->mac_len = skb_inner_network_offset(skb); | 56 | skb->mac_len = skb_inner_network_offset(skb); |
56 | skb->protocol = new_protocol; | 57 | skb->protocol = new_protocol; |
57 | skb->encap_hdr_csum = need_csum; | 58 | skb->encap_hdr_csum = need_csum; |
59 | skb->remcsum_offload = remcsum; | ||
58 | 60 | ||
59 | /* Try to offload checksum if possible */ | 61 | /* Try to offload checksum if possible */ |
60 | offload_csum = !!(need_csum && | 62 | offload_csum = !!(need_csum && |
@@ -108,11 +110,22 @@ static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, | |||
108 | uh->check = ~csum_fold((__force __wsum) | 110 | uh->check = ~csum_fold((__force __wsum) |
109 | ((__force u32)uh->check + | 111 | ((__force u32)uh->check + |
110 | (__force u32)delta)); | 112 | (__force u32)delta)); |
111 | |||
112 | if (offload_csum) { | 113 | if (offload_csum) { |
113 | skb->ip_summed = CHECKSUM_PARTIAL; | 114 | skb->ip_summed = CHECKSUM_PARTIAL; |
114 | skb->csum_start = skb_transport_header(skb) - skb->head; | 115 | skb->csum_start = skb_transport_header(skb) - skb->head; |
115 | skb->csum_offset = offsetof(struct udphdr, check); | 116 | skb->csum_offset = offsetof(struct udphdr, check); |
117 | } else if (remcsum) { | ||
118 | /* Need to calculate checksum from scratch, | ||
119 | * inner checksums are never when doing | ||
120 | * remote_checksum_offload. | ||
121 | */ | ||
122 | |||
123 | skb->csum = skb_checksum(skb, udp_offset, | ||
124 | skb->len - udp_offset, | ||
125 | 0); | ||
126 | uh->check = csum_fold(skb->csum); | ||
127 | if (uh->check == 0) | ||
128 | uh->check = CSUM_MANGLED_0; | ||
116 | } else { | 129 | } else { |
117 | uh->check = gso_make_checksum(skb, ~uh->check); | 130 | uh->check = gso_make_checksum(skb, ~uh->check); |
118 | 131 | ||
@@ -192,6 +205,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, | |||
192 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | | 205 | if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | |
193 | SKB_GSO_UDP_TUNNEL | | 206 | SKB_GSO_UDP_TUNNEL | |
194 | SKB_GSO_UDP_TUNNEL_CSUM | | 207 | SKB_GSO_UDP_TUNNEL_CSUM | |
208 | SKB_GSO_TUNNEL_REMCSUM | | ||
195 | SKB_GSO_IPIP | | 209 | SKB_GSO_IPIP | |
196 | SKB_GSO_GRE | SKB_GSO_GRE_CSUM | | 210 | SKB_GSO_GRE | SKB_GSO_GRE_CSUM | |
197 | SKB_GSO_MPLS) || | 211 | SKB_GSO_MPLS) || |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index a071563a7e6e..e9767079a360 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -78,6 +78,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | |||
78 | SKB_GSO_SIT | | 78 | SKB_GSO_SIT | |
79 | SKB_GSO_UDP_TUNNEL | | 79 | SKB_GSO_UDP_TUNNEL | |
80 | SKB_GSO_UDP_TUNNEL_CSUM | | 80 | SKB_GSO_UDP_TUNNEL_CSUM | |
81 | SKB_GSO_TUNNEL_REMCSUM | | ||
81 | SKB_GSO_MPLS | | 82 | SKB_GSO_MPLS | |
82 | SKB_GSO_TCPV6 | | 83 | SKB_GSO_TCPV6 | |
83 | 0))) | 84 | 0))) |
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c index 6b8f543f6ac6..637ba2e438b7 100644 --- a/net/ipv6/udp_offload.c +++ b/net/ipv6/udp_offload.c | |||
@@ -42,6 +42,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, | |||
42 | SKB_GSO_DODGY | | 42 | SKB_GSO_DODGY | |
43 | SKB_GSO_UDP_TUNNEL | | 43 | SKB_GSO_UDP_TUNNEL | |
44 | SKB_GSO_UDP_TUNNEL_CSUM | | 44 | SKB_GSO_UDP_TUNNEL_CSUM | |
45 | SKB_GSO_TUNNEL_REMCSUM | | ||
45 | SKB_GSO_GRE | | 46 | SKB_GSO_GRE | |
46 | SKB_GSO_GRE_CSUM | | 47 | SKB_GSO_GRE_CSUM | |
47 | SKB_GSO_IPIP | | 48 | SKB_GSO_IPIP | |