summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-11-26 12:25:51 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-26 12:25:51 -0500
commit12bbd595ab45f093db36d12768926422013b3441 (patch)
tree553e4f9745b404e0d1db149192e303fd51681e80
parentced7a04e394fe1df41d13b833baab5cfcb1d03b3 (diff)
parent4fd671ded14f92cb8db0bf72747f4df508ba5e3d (diff)
downloadlinux-12bbd595ab45f093db36d12768926422013b3441.tar.gz
linux-12bbd595ab45f093db36d12768926422013b3441.tar.bz2
linux-12bbd595ab45f093db36d12768926422013b3441.zip
Merge branch 'remcsum_adjust'
Tom Herbert says: ==================== gue: Generalize remote checksum offload The remote checksum offload is generalized by creating a common function (remcsum_adjust) that does the work of modifying the checksum in remote checksum offload. This function can be called from normal or GRO path. GUE was modified to use this function. Remote checksum offload is described in https://tools.ietf.org/html/draft-herbert-remotecsumoffload-01 Tested by running 200 TCP_STREAM connections over GUE, did not see any problems with remote checksum offload enabled. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/checksum.h16
-rw-r--r--net/ipv4/fou.c84
2 files changed, 33 insertions, 67 deletions
diff --git a/include/net/checksum.h b/include/net/checksum.h
index 6465bae80a4f..e339a9513e29 100644
--- a/include/net/checksum.h
+++ b/include/net/checksum.h
@@ -151,4 +151,20 @@ static inline void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb,
(__force __be32)to, pseudohdr);
}
+static inline __wsum remcsum_adjust(void *ptr, __wsum csum,
+ int start, int offset)
+{
+ __sum16 *psum = (__sum16 *)(ptr + offset);
+ __wsum delta;
+
+ /* Subtract out checksum up to start */
+ csum = csum_sub(csum, csum_partial(ptr, start, 0));
+
+ /* Set derived checksum in packet */
+ delta = csum_sub(csum_fold(csum), *psum);
+ *psum = csum_fold(csum);
+
+ return delta;
+}
+
#endif
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 3dfe9828e7ef..b986298a7ba3 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -64,15 +64,13 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
}
static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr,
- void *data, int hdrlen, u8 ipproto)
+ void *data, size_t hdrlen, u8 ipproto)
{
__be16 *pd = data;
- u16 start = ntohs(pd[0]);
- u16 offset = ntohs(pd[1]);
- u16 poffset = 0;
- u16 plen;
- __wsum csum, delta;
- __sum16 *psum;
+ size_t start = ntohs(pd[0]);
+ size_t offset = ntohs(pd[1]);
+ size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start);
+ __wsum delta;
if (skb->remcsum_offload) {
/* Already processed in GRO path */
@@ -80,35 +78,15 @@ static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr,
return guehdr;
}
- if (start > skb->len - hdrlen ||
- offset > skb->len - hdrlen - sizeof(u16))
- return NULL;
-
- if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE))
- __skb_checksum_complete(skb);
-
- plen = hdrlen + offset + sizeof(u16);
if (!pskb_may_pull(skb, plen))
return NULL;
guehdr = (struct guehdr *)&udp_hdr(skb)[1];
- if (ipproto == IPPROTO_IP && sizeof(struct iphdr) < plen) {
- struct iphdr *ip = (struct iphdr *)(skb->data + hdrlen);
-
- /* If next header happens to be IP we can skip that for the
- * checksum calculation since the IP header checksum is zero
- * if correct.
- */
- poffset = ip->ihl * 4;
- }
-
- csum = csum_sub(skb->csum, skb_checksum(skb, poffset + hdrlen,
- start - poffset - hdrlen, 0));
+ if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE))
+ __skb_checksum_complete(skb);
- /* Set derived checksum in packet */
- psum = (__sum16 *)(skb->data + hdrlen + offset);
- delta = csum_sub(csum_fold(csum), *psum);
- *psum = csum_fold(csum);
+ delta = remcsum_adjust((void *)guehdr + hdrlen,
+ skb->csum, start, offset);
/* Adjust skb->csum since we changed the packet */
skb->csum = csum_add(skb->csum, delta);
@@ -158,9 +136,6 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(skb)->tot_len) - len);
- /* Pull UDP header now, skb->data points to guehdr */
- __skb_pull(skb, sizeof(struct udphdr));
-
/* Pull csum through the guehdr now . This can be used if
* there is a remote checksum offload.
*/
@@ -188,7 +163,7 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
if (unlikely(guehdr->control))
return gue_control_message(skb, guehdr);
- __skb_pull(skb, hdrlen);
+ __skb_pull(skb, sizeof(struct udphdr) + hdrlen);
skb_reset_transport_header(skb);
return -guehdr->proto_ctype;
@@ -248,24 +223,17 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off,
size_t hdrlen, u8 ipproto)
{
__be16 *pd = data;
- u16 start = ntohs(pd[0]);
- u16 offset = ntohs(pd[1]);
- u16 poffset = 0;
- u16 plen;
- void *ptr;
- __wsum csum, delta;
- __sum16 *psum;
+ size_t start = ntohs(pd[0]);
+ size_t offset = ntohs(pd[1]);
+ size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start);
+ __wsum delta;
if (skb->remcsum_offload)
return guehdr;
- if (start > skb_gro_len(skb) - hdrlen ||
- offset > skb_gro_len(skb) - hdrlen - sizeof(u16) ||
- !NAPI_GRO_CB(skb)->csum_valid || skb->remcsum_offload)
+ if (!NAPI_GRO_CB(skb)->csum_valid)
return NULL;
- plen = hdrlen + offset + sizeof(u16);
-
/* Pull checksum that will be written */
if (skb_gro_header_hard(skb, off + plen)) {
guehdr = skb_gro_header_slow(skb, off + plen, off);
@@ -273,26 +241,8 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off,
return NULL;
}
- ptr = (void *)guehdr + hdrlen;
-
- if (ipproto == IPPROTO_IP &&
- (hdrlen + sizeof(struct iphdr) < plen)) {
- struct iphdr *ip = (struct iphdr *)(ptr + hdrlen);
-
- /* If next header happens to be IP we can skip
- * that for the checksum calculation since the
- * IP header checksum is zero if correct.
- */
- poffset = ip->ihl * 4;
- }
-
- csum = csum_sub(NAPI_GRO_CB(skb)->csum,
- csum_partial(ptr + poffset, start - poffset, 0));
-
- /* Set derived checksum in packet */
- psum = (__sum16 *)(ptr + offset);
- delta = csum_sub(csum_fold(csum), *psum);
- *psum = csum_fold(csum);
+ delta = remcsum_adjust((void *)guehdr + hdrlen,
+ NAPI_GRO_CB(skb)->csum, start, offset);
/* Adjust skb->csum since we changed the packet */
skb->csum = csum_add(skb->csum, delta);