[Openvpn-devel,ovpn-net-next] ovpn: reset GSO metadata after decapsulation

Message ID 20250701124744.259472-1-ralf@mandelbit.com
State New
Headers show
Series [Openvpn-devel,ovpn-net-next] ovpn: reset GSO metadata after decapsulation | expand

Commit Message

Ralf Lici July 1, 2025, 12:47 p.m. UTC
The ovpn_netdev_write() function is responsible for injecting
decapsulated and decrypted packets back into the local network stack.
Prior to this change, the skb could retain GSO metadata from the outer,
encrypted tunnel packet. This original GSO metadata, relevant to the
sender's context for the tunnel, becomes invalid and misleading for the
local receive path once the inner packet is exposed.

Leaving this stale metadata intact causes internal GSO validation checks
further down the kernel's network stack (validate_xmit_skb()) to fail,
leading to packet drops. The reasons for these failures vary by
protocol, for example:
- for ICMP, no offload handler is registered;
- for TCP and UDP, the respective offload handlers return errors when
  comparing skb->len to the outdated skb_shinfo(skb)->gso_size.

By calling skb_gso_reset(skb) we ensure the inner packet is presented to
gro_cells_receive() with a clean slate, correctly indicating it is an
individual packet from the perspective of the local stack.

This change eliminates the "Driver has suspect GRO implementation, TCP
performance may be compromised" warning and improves overall TCP
performance by allowing GSO/GRO to function as intended on the
decapsulated traffic. (Note: UDP GSO is not currently supported in ovpn)

Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
 drivers/net/ovpn/io.c | 7 +++++++
 1 file changed, 7 insertions(+)

Comments

Gert Doering July 1, 2025, 1:51 p.m. UTC | #1
Hi

On Tue, Jul 01, 2025 at 02:47:44PM +0200, Ralf Lici wrote:
> By calling skb_gso_reset(skb) we ensure the inner packet is presented to
> gro_cells_receive() with a clean slate, correctly indicating it is an
> individual packet from the perspective of the local stack.

Amazing find.

I have tested this on my ubuntu 20.04 (backports) testbed that had the
"large ping tcp instance -> udp instance fail", and now everything succeeds
(this patch applied to "DCO version: ovpn-net-next/net-6.15.0-8f0bda6").

Tested-By: Gert Doering <gert@greenie.muc.de>

gert

Patch

diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index ebf1e849506b..3e9e7f8444b3 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -62,6 +62,13 @@  static void ovpn_netdev_write(struct ovpn_peer *peer, struct sk_buff *skb)
 	unsigned int pkt_len;
 	int ret;
 
+	/*
+	 * GSO state from the transport layer is not valid for the tunnel/data
+	 * path. Reset all GSO fields to prevent any further GSO processing
+	 * from entering an inconsistent state.
+	 */
+	skb_gso_reset(skb);
+
 	/* we can't guarantee the packet wasn't corrupted before entering the
 	 * VPN, therefore we give other layers a chance to check that
 	 */