aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2014-11-04 12:06:54 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-05 16:30:03 -0500
commite585f23636370320bc2071ca5ba2744ae37c3e51 (patch)
treec1d9d60bd084099f3e65155dd920ee72d41a808e
parent5024c33ac354577635c5671498891eb197f3ec4d (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.h4
-rw-r--r--include/linux/netdevice.h1
-rw-r--r--include/linux/skbuff.h4
-rw-r--r--net/core/skbuff.c4
-rw-r--r--net/ipv4/af_inet.c1
-rw-r--r--net/ipv4/tcp_offload.c1
-rw-r--r--net/ipv4/udp_offload.c18
-rw-r--r--net/ipv6/ip6_offload.c1
-rw-r--r--net/ipv6/udp_offload.c1
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
3087perform_csum_check: 3087perform_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 |