netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Edward Cree <ecree@solarflare.com>
To: David Miller <davem@davemloft.net>
Cc: <netdev@vger.kernel.org>, <linux-net-drivers@solarflare.com>,
	<tom@herbertland.com>, <alexander.duyck@gmail.com>
Subject: [PATCH net-next 1/8] net: local checksum offload for encapsulation
Date: Fri, 8 Jan 2016 19:45:24 +0000	[thread overview]
Message-ID: <569011D4.60002@solarflare.com> (raw)
In-Reply-To: <56901197.8040808@solarflare.com>

The arithmetic properties of the ones-complement checksum mean that a
 correctly checksummed inner packet, including its checksum, has a ones
 complement sum depending only on whatever value was used to initialise
 the checksum field before checksumming (in the case of TCP and UDP,
 this is the ones complement sum of the pseudo header, complemented).
Consequently, if we are going to offload the inner checksum with
 CHECKSUM_PARTIAL, we can compute the outer checksum based only on the
 packed data not covered by the inner checksum, and the initial value of
 the inner checksum field.

Signed-off-by: Edward Cree <ecree@solarflare.com>
---
 include/linux/skbuff.h  | 24 ++++++++++++++++++++++++
 net/ipv4/udp.c          | 20 ++++++++++----------
 net/ipv6/ip6_checksum.c | 14 +++++++-------
 3 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 6b6bd42..ee063ff 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3665,5 +3665,29 @@ static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb)
 	return hdr_len + skb_gso_transport_seglen(skb);
 }
 
+/* Local Checksum Offload.
+ * Compute outer checksum based on the assumption that the
+ * inner checksum will be offloaded later.
+ * Fill in outer checksum adjustment (e.g. with sum of outer
+ * pseudo-header) before calling.
+ * Also ensure that inner checksum is in linear data area.
+ */
+static inline __wsum lco_csum(struct sk_buff *skb)
+{
+	char *inner_csum_field;
+	__wsum csum;
+
+	/* Start with complement of inner checksum adjustment */
+	inner_csum_field = skb->data + skb_checksum_start_offset(skb) +
+				skb->csum_offset;
+	csum = ~csum_unfold(*(__force __sum16 *)inner_csum_field);
+	/* Add in checksum of our headers (incl. outer checksum
+	 * adjustment filled in by caller)
+	 */
+	csum = skb_checksum(skb, 0, skb_checksum_start_offset(skb), csum);
+	/* The result is the checksum from skb->data to end of packet */
+	return csum;
+}
+
 #endif	/* __KERNEL__ */
 #endif	/* _LINUX_SKBUFF_H */
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 8841e98..f9bd5db 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -767,16 +767,18 @@ void udp_set_csum(bool nocheck, struct sk_buff *skb,
 {
 	struct udphdr *uh = udp_hdr(skb);
 
-	if (nocheck)
+	if (nocheck) {
 		uh->check = 0;
-	else if (skb_is_gso(skb))
+	} else if (skb_is_gso(skb)) {
 		uh->check = ~udp_v4_check(len, saddr, daddr, 0);
-	else if (skb_dst(skb) && skb_dst(skb)->dev &&
-		 (skb_dst(skb)->dev->features &
-		  (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM))) {
-
-		BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
-
+	} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		uh->check = 0;
+		uh->check = ~udp_v4_check(len, saddr, daddr, lco_csum(skb));
+		if (uh->check == 0)
+			uh->check = CSUM_MANGLED_0;
+	} else if (skb_dst(skb) && skb_dst(skb)->dev &&
+		   (skb_dst(skb)->dev->features &
+		    (NETIF_F_IP_CSUM | NETIF_F_HW_CSUM))) {
 		skb->ip_summed = CHECKSUM_PARTIAL;
 		skb->csum_start = skb_transport_header(skb) - skb->head;
 		skb->csum_offset = offsetof(struct udphdr, check);
@@ -784,8 +786,6 @@ void udp_set_csum(bool nocheck, struct sk_buff *skb,
 	} else {
 		__wsum csum;
 
-		BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
-
 		uh->check = 0;
 		csum = skb_checksum(skb, 0, len, 0);
 		uh->check = udp_v4_check(len, saddr, daddr, csum);
diff --git a/net/ipv6/ip6_checksum.c b/net/ipv6/ip6_checksum.c
index 9a4d732..eba525d 100644
--- a/net/ipv6/ip6_checksum.c
+++ b/net/ipv6/ip6_checksum.c
@@ -98,11 +98,13 @@ void udp6_set_csum(bool nocheck, struct sk_buff *skb,
 		uh->check = 0;
 	else if (skb_is_gso(skb))
 		uh->check = ~udp_v6_check(len, saddr, daddr, 0);
-	else if (skb_dst(skb) && skb_dst(skb)->dev &&
-		 (skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM)) {
-
-		BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
-
+	else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+		uh->check = 0;
+		uh->check = ~udp_v6_check(len, saddr, daddr, csum_fold(lco_csum(skb));
+		if (uh->check == 0)
+			uh->check = CSUM_MANGLED_0;
+	} else if (skb_dst(skb) && skb_dst(skb)->dev &&
+		   (skb_dst(skb)->dev->features & NETIF_F_IPV6_CSUM) {
 		skb->ip_summed = CHECKSUM_PARTIAL;
 		skb->csum_start = skb_transport_header(skb) - skb->head;
 		skb->csum_offset = offsetof(struct udphdr, check);
@@ -110,8 +112,6 @@ void udp6_set_csum(bool nocheck, struct sk_buff *skb,
 	} else {
 		__wsum csum;
 
-		BUG_ON(skb->ip_summed == CHECKSUM_PARTIAL);
-
 		uh->check = 0;
 		csum = skb_checksum(skb, 0, len, 0);
 		uh->check = udp_v6_check(len, saddr, daddr, csum);

  reply	other threads:[~2016-01-08 19:45 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-08 19:44 [PATCH v3 net-next 0/8] Local Checksum Offload Edward Cree
2016-01-08 19:45 ` Edward Cree [this message]
2016-01-28  7:04   ` [PATCH net-next 1/8] net: local checksum offload for encapsulation Zang MingJie
2016-01-28  9:00     ` Alexander Duyck
2016-01-28 17:09       ` Tom Herbert
2016-01-08 19:45 ` [PATCH net-next 2/8] net: udp: always set up for CHECKSUM_PARTIAL offload Edward Cree
2016-01-08 19:45 ` [PATCH net-next 3/8] net: enable LCO for udp_tunnel_handle_offloads() users Edward Cree
2016-01-08 19:45 ` [PATCH net-next 4/8] net: vxlan: enable local checksum offload Edward Cree
2016-01-08 19:46 ` [PATCH net-next 5/8] fou: enable LCO in FOU and GUE Edward Cree
2016-01-08 19:47 ` [PATCH net-next 6/8] net: gre: Implement LCO for GRE over IPv4 Edward Cree
2016-01-11 10:09   ` David Laight
2016-01-11 13:21     ` Edward Cree
2016-01-11 18:39       ` Alexander Duyck
2016-01-11 19:02         ` Edward Cree
2016-01-20 19:11         ` Rustad, Mark D
2016-01-20 19:35           ` Alexander Duyck
2016-01-20 19:58             ` Tom Herbert
2016-01-20 21:13               ` Alexander Duyck
2016-01-20 23:34                 ` Rustad, Mark D
2016-01-08 19:47 ` [PATCH net-next 7/8] net: ip_tunnel: remove 'csum_help' argument to iptunnel_handle_offloads Edward Cree
2016-01-09  0:35   ` Alexander Duyck
2016-01-09  0:44     ` Tom Herbert
2016-01-09  2:05       ` Alexander Duyck
2016-01-09  3:00         ` Tom Herbert
2016-01-09  7:59           ` Alexander Duyck
2016-01-11 13:24         ` Edward Cree
2016-01-11 16:39           ` Alexander Duyck
2016-01-11 17:31             ` Edward Cree
2016-01-11 18:15               ` Alexander Duyck
2016-01-11 19:03                 ` Edward Cree
2016-01-11 21:00                   ` Alexander Duyck
2016-01-08 19:47 ` [PATCH net-next 8/8] Documentation/networking: add checksum-offloads.txt to explain LCO Edward Cree
  -- strict thread matches above, loose matches on Subject: below --
2016-02-05 20:39 [PATCH v4 net-next 0/8] Local Checksum Offload Edward Cree
2016-02-05 20:40 ` [PATCH net-next 1/8] net: local checksum offload for encapsulation Edward Cree

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=569011D4.60002@solarflare.com \
    --to=ecree@solarflare.com \
    --cc=alexander.duyck@gmail.com \
    --cc=davem@davemloft.net \
    --cc=linux-net-drivers@solarflare.com \
    --cc=netdev@vger.kernel.org \
    --cc=tom@herbertland.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).