[PATCH net-next 0/4] CHECKSUM_COMPLETE in IPSec

STALE3403d

5 messages, 1 author, 2017-06-22 · open the first message on its own page

[PATCH net-next 0/4] CHECKSUM_COMPLETE in IPSec

From: <hidden>
Date: 2017-06-22 12:32:18

From: Ilan Tayari <redacted>

This patchset adds support for RX checksum offload in IPSec.

When crypto is performed in the host, the checksum needs to
be recalculated over all the payload.

However, when crypto is performed in the NIC, the NIC may
provide useful CHECKSUM_COMPLETE value, which then only needs
to be updated to account for decapsulation.

Note: This patchset is on top of the recent two IPv6 xfrm
patches which were submitted to 'net'.

Ilan Tayari (2):
  esp4: Support RX checksum with crypto offload
  esp6: Support RX checksum with crypto offload

Yossi Kuperman (2):
  xfrm6: Fix CHECKSUM_COMPLETE after IPv6 header push
  esp6: Fix RX checksum after header pull

 net/ipv4/esp4.c         | 13 +++++++++++--
 net/ipv4/esp4_offload.c |  4 +++-
 net/ipv6/esp6.c         | 15 +++++++++++++--
 net/ipv6/esp6_offload.c |  4 +++-
 net/ipv6/xfrm6_input.c  |  4 +++-
 5 files changed, 33 insertions(+), 7 deletions(-)

-- 
2.11.0

[PATCH net-next 1/4] esp4: Support RX checksum with crypto offload

From: <hidden>
Date: 2017-06-22 12:32:20

From: Ilan Tayari <redacted>

Keep the device's reported ip_summed indication in case crypto
was offloaded by the device. Subtract the csum values of the
stripped parts (esp header+iv, esp trailer+auth_data) to keep
value correct.

Note: CHECKSUM_COMPLETE should be indicated only if skb->csum
has the post-decryption offload csum value.

Signed-off-by: Ariel Levkovich <redacted>
Signed-off-by: Ilan Tayari <redacted>
---
 net/ipv4/esp4.c         | 13 +++++++++++--
 net/ipv4/esp4_offload.c |  4 +++-
 2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 1f18b4650253..2eab0992b127 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -510,7 +510,8 @@ int esp_input_done2(struct sk_buff *skb, int err)
 	int elen = skb->len - hlen;
 	int ihl;
 	u8 nexthdr[2];
-	int padlen;
+	int padlen, trimlen;
+	__wsum csumdiff;
 
 	if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
 		kfree(ESP_SKB_CB(skb)->tmp);
@@ -568,7 +569,15 @@ int esp_input_done2(struct sk_buff *skb, int err)
 			skb->ip_summed = CHECKSUM_UNNECESSARY;
 	}
 
-	pskb_trim(skb, skb->len - alen - padlen - 2);
+	trimlen = alen + padlen + 2;
+	if (skb->ip_summed == CHECKSUM_COMPLETE) {
+		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
+		skb->csum = csum_block_sub(skb->csum, csumdiff,
+					   skb->len - trimlen);
+		skb_postpull_rcsum(skb, skb->data, hlen);
+	}
+
+	pskb_trim(skb, skb->len - trimlen);
 	__skb_pull(skb, hlen);
 	if (x->props.mode == XFRM_MODE_TUNNEL)
 		skb_reset_transport_header(skb);
diff --git a/net/ipv4/esp4_offload.c b/net/ipv4/esp4_offload.c
index e0666016a764..05831dea00f4 100644
--- a/net/ipv4/esp4_offload.c
+++ b/net/ipv4/esp4_offload.c
@@ -182,11 +182,13 @@ static struct sk_buff *esp4_gso_segment(struct sk_buff *skb,
 static int esp_input_tail(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct crypto_aead *aead = x->data;
+	struct xfrm_offload *xo = xfrm_offload(skb);
 
 	if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead)))
 		return -EINVAL;
 
-	skb->ip_summed = CHECKSUM_NONE;
+	if (!(xo->flags & CRYPTO_DONE))
+		skb->ip_summed = CHECKSUM_NONE;
 
 	return esp_input_done2(skb, 0);
 }
-- 
2.11.0

[PATCH net-next 2/4] esp6: Support RX checksum with crypto offload

From: <hidden>
Date: 2017-06-22 12:32:23

From: Ilan Tayari <redacted>

Keep the device's reported ip_summed indication in case crypto
was offloaded by the device. Subtract the csum values of the
stripped parts (esp header+iv, esp trailer+auth_data) to keep
value correct.

Note: CHECKSUM_COMPLETE should be indicated only if skb->csum
has the post-decryption offload csum value.

Signed-off-by: Ariel Levkovich <redacted>
Signed-off-by: Ilan Tayari <redacted>
---
 net/ipv6/esp6.c         | 13 +++++++++++--
 net/ipv6/esp6_offload.c |  4 +++-
 2 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index d8b40ff4b2e6..f872bb16cc9d 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -475,7 +475,8 @@ int esp6_input_done2(struct sk_buff *skb, int err)
 	int hlen = sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead);
 	int elen = skb->len - hlen;
 	int hdr_len = skb_network_header_len(skb);
-	int padlen;
+	int padlen, trimlen;
+	__wsum csumdiff;
 	u8 nexthdr[2];
 
 	if (!xo || (xo && !(xo->flags & CRYPTO_DONE)))
@@ -497,7 +498,15 @@ int esp6_input_done2(struct sk_buff *skb, int err)
 
 	/* ... check padding bits here. Silly. :-) */
 
-	pskb_trim(skb, skb->len - alen - padlen - 2);
+	trimlen = alen + padlen + 2;
+	if (skb->ip_summed == CHECKSUM_COMPLETE) {
+		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
+		skb->csum = csum_block_sub(skb->csum, csumdiff,
+					   skb->len - trimlen);
+		skb_postpull_rcsum(skb, skb->data, hlen);
+	}
+
+	pskb_trim(skb, skb->len - trimlen);
 	__skb_pull(skb, hlen);
 	if (x->props.mode == XFRM_MODE_TUNNEL)
 		skb_reset_transport_header(skb);
diff --git a/net/ipv6/esp6_offload.c b/net/ipv6/esp6_offload.c
index f02f131f6435..eec3add177fe 100644
--- a/net/ipv6/esp6_offload.c
+++ b/net/ipv6/esp6_offload.c
@@ -209,11 +209,13 @@ static struct sk_buff *esp6_gso_segment(struct sk_buff *skb,
 static int esp6_input_tail(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct crypto_aead *aead = x->data;
+	struct xfrm_offload *xo = xfrm_offload(skb);
 
 	if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr) + crypto_aead_ivsize(aead)))
 		return -EINVAL;
 
-	skb->ip_summed = CHECKSUM_NONE;
+	if (!(xo->flags & CRYPTO_DONE))
+		skb->ip_summed = CHECKSUM_NONE;
 
 	return esp6_input_done2(skb, 0);
 }
-- 
2.11.0

[PATCH net-next 3/4] xfrm6: Fix CHECKSUM_COMPLETE after IPv6 header push

From: <hidden>
Date: 2017-06-22 12:32:26

From: Yossi Kuperman <redacted>

xfrm6_transport_finish rebuilds the IPv6 header based on the
original one and pushes it back without fixing skb->csum.
Therefore, CHECKSUM_COMPLETE is no longer valid and the packet
gets dropped.

Fix skb->csum by calling skb_postpush_rcsum.

Note: A valid IPv4 header has checksum 0, unlike IPv6. Thus,
the change is not needed in the sibling xfrm4_transport_finish
function.

Signed-off-by: Yossi Kuperman <redacted>
---
 net/ipv6/xfrm6_input.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index 3ef5d913e7a3..f95943a13abc 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -34,6 +34,7 @@ EXPORT_SYMBOL(xfrm6_rcv_spi);
 int xfrm6_transport_finish(struct sk_buff *skb, int async)
 {
 	struct xfrm_offload *xo = xfrm_offload(skb);
+	int nhlen = skb->data - skb_network_header(skb);
 
 	skb_network_header(skb)[IP6CB(skb)->nhoff] =
 		XFRM_MODE_SKB_CB(skb)->protocol;
@@ -43,8 +44,9 @@ int xfrm6_transport_finish(struct sk_buff *skb, int async)
 		return 1;
 #endif
 
-	__skb_push(skb, skb->data - skb_network_header(skb));
+	__skb_push(skb, nhlen);
 	ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+	skb_postpush_rcsum(skb, skb_network_header(skb), nhlen);
 
 	if (xo && (xo->flags & XFRM_GRO)) {
 		skb_mac_header_rebuild(skb);
-- 
2.11.0

[PATCH net-next 4/4] esp6: Fix RX checksum after header pull

From: <hidden>
Date: 2017-06-22 12:32:28

From: Yossi Kuperman <redacted>

Both ip6_input_finish (non-GRO) and esp6_gro_receive (GRO) strip
the IPv6 header without adjusting skb->csum accordingly. As a
result CHECKSUM_COMPLETE breaks and "hw csum failure" is written
to the kernel log by netdev_rx_csum_fault (dev.c).

Fix skb->csum by substracting the checksum value of the pulled IPv6
header using a call to skb_postpull_rcsum.

This affects both transport and tunnel modes.

Note that the fix occurs far from the place that the header was
pulled. This is based on existing code, see:
ipv6_srh_rcv() in exthdrs.c and rawv6_rcv() in raw.c

Signed-off-by: Yossi Kuperman <redacted>
---
 net/ipv6/esp6.c | 2 ++
 1 file changed, 2 insertions(+)
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index f872bb16cc9d..3fed3947acf9 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -500,6 +500,8 @@ int esp6_input_done2(struct sk_buff *skb, int err)
 
 	trimlen = alen + padlen + 2;
 	if (skb->ip_summed == CHECKSUM_COMPLETE) {
+		skb_postpull_rcsum(skb, skb_network_header(skb),
+				   skb_network_header_len(skb));
 		csumdiff = skb_checksum(skb, skb->len - trimlen, trimlen, 0);
 		skb->csum = csum_block_sub(skb->csum, csumdiff,
 					   skb->len - trimlen);
-- 
2.11.0
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help