| Message ID | 20260119131400.424161-3-ralf@mandelbit.com |
|---|---|
| State | Awaiting Upstream |
| Headers |
Return-Path: <openvpn-devel-bounces@lists.sourceforge.net>
Delivered-To: patchwork@openvpn.net
Received: by 2002:a05:7000:9186:b0:80a:3855:ce6a with SMTP id j6csp3199284maf;
Mon, 19 Jan 2026 05:48:08 -0800 (PST)
X-Forwarded-Encrypted: i=2;
AJvYcCUEaFmzTIEBJSx65CxGYvFozLPSXjqgI6/1a6z5N935Z3k8qaJRy0HWYtoHGZxXMcztzO59vPY1xdo=@openvpn.net
X-Received: by 2002:a05:6808:5381:b0:44d:bf83:d7f8 with SMTP id
5614622812f47-45c9d70a42cmr4528914b6e.4.1768830488515;
Mon, 19 Jan 2026 05:48:08 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1768830488; cv=none;
d=google.com; s=arc-20240605;
b=FaaCLcOGsdCaAULcQg7yBkDbGwkEIjX7IuI9TdFj3L+vmu5AoN7rXGzrdGWRYO1oF+
c79B36ACF/Gtz/pkJ2Do0sbThoyV4SNF5Qee1Haz0G56XaGerRk8YQ9Wzok7qgk2zEFQ
bKoGS7VJtwvKWygSq+hj8R6wuPwYACDtm0+K489nau7vYyShe19+oSfR7sfmCNMFaD50
xXnHq0n3D2MEYzQNve9v64G98tNJGGWWoN1J3Pq0RCbaFq3t4J/oqkWprtTt21EBetKw
XzOM01irLsYtsarjVtHKQut52Cf83bpHgtwzPMNU8ro/HviYTvrSt4bTYG8katOifsuE
/VNg==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;
s=arc-20240605;
h=errors-to:content-transfer-encoding:cc:list-subscribe:list-help
:list-post:list-archive:list-unsubscribe:list-id:precedence:subject
:mime-version:references:in-reply-to:message-id:date:to:from
:dkim-signature:dkim-signature:dkim-signature:dkim-signature;
bh=zdfgRp44nf7U+KZ7+1x0TTfSZ71QhEtR6Ud2z4EX4W8=;
fh=bDmbXayvKcQuWZaaz4JM7kgnS3MJBk3QUq2ehqNuBVc=;
b=XiZqd3r2A+O7pwj7oOXsJpjeW0yDJGlPWA6g2lf/jEBkTnOauFcSyidP1tt89nP1qE
2djQ1UILdy404y15AGbVSFJ5GTH/flj12ZXDa0TVwgts91HtKGH7z/jpg6Mbv2W7AEsJ
jy226JWm+X8Y04zMTq3UJBb+PX9aAGGzNHbFuMWJ2eLdYfhw8ko4zZQ+9OqR96gWi68p
iCYHU9BLN7/ilnrqBHoev94JeRcP1C7j4KzQdnHHFmPqKMxmDqwujkLq6v0wGOKoW/QB
G/8dPz3ue0+rObIt2v8ik68ZGZavUy8wVs8D+TPW+9CJezOMrhB98BvLw6BUbK7FYzOi
jGfw==;
dara=google.com
ARC-Authentication-Results: i=1; mx.google.com;
dkim=pass header.i=@lists.sourceforge.net header.s=beta
header.b=AV5ukTa5;
dkim=neutral (body hash did not verify) header.i=@sourceforge.net
header.s=x header.b=lNpVZtxv;
dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x
header.b=NLOcgL+m;
dkim=neutral (body hash did not verify) header.i=@mandelbit.com
header.s=google header.b=mk8ojGxf;
spf=pass (google.com: domain of
openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as
permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net;
dara=neutral header.i=@openvpn.net
Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7])
by mx.google.com with ESMTPS id
5614622812f47-45c9dfd8f30si5825290b6e.60.2026.01.19.05.48.08
(version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128);
Mon, 19 Jan 2026 05:48:08 -0800 (PST)
Received-SPF: pass (google.com: domain of
openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as
permitted sender) client-ip=216.105.38.7;
Authentication-Results: mx.google.com;
dkim=pass header.i=@lists.sourceforge.net header.s=beta
header.b=AV5ukTa5;
dkim=neutral (body hash did not verify) header.i=@sourceforge.net
header.s=x header.b=lNpVZtxv;
dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x
header.b=NLOcgL+m;
dkim=neutral (body hash did not verify) header.i=@mandelbit.com
header.s=google header.b=mk8ojGxf;
spf=pass (google.com: domain of
openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as
permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net;
dara=neutral header.i=@openvpn.net
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type:Cc:
List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:
Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender:
Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender
:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner;
bh=zdfgRp44nf7U+KZ7+1x0TTfSZ71QhEtR6Ud2z4EX4W8=; b=AV5ukTa55Cu2rBdZkyvSBi8n7x
mZFvb5khShyVVtMtkb5dIbvjim9/lfMUlG5sLgeNWQoDaraZRlhQk5JDS8mWrXoLESpXJUF+O8y30
6HwD4zrWujEJkygNXTJqRhS7/GQ3ShupiqpPrM588jJ4USo5mOWYKT33tj/HRwf/lui0=;
Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com)
by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.95)
(envelope-from <openvpn-devel-bounces@lists.sourceforge.net>)
id 1vhpbt-0000vp-C5;
Mon, 19 Jan 2026 13:48:02 +0000
Received: from [172.30.29.66] (helo=mx.sourceforge.net)
by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLS1.2) tls
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95)
(envelope-from <ralf@mandelbit.com>) id 1vhpbr-0000vU-9b
for openvpn-devel@lists.sourceforge.net;
Mon, 19 Jan 2026 13:48:00 +0000
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed;
d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References:
In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:
Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:
Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:
List-Subscribe:List-Post:List-Owner:List-Archive;
bh=z1lqwdBZJ0sTD4rZ46ZjbWOscPtZ2EPKZGsp06jLE0w=; b=lNpVZtxvdeF/IKQz788TRSgky6
TtXzyIVsiTpAFzPTDxuju3VbLBdLhaMBM5LHYzNsKeVgvEdvQ/pr0uHBprWEwiEqNKokmQbR2oBk9
mNgHHt+WKHXrTnhwJZzBU4K3jOHMYJPnq3hgvsJIcpv3DgZs4qO3atVXGPWFEYMTNsL8=;
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x
;
h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:
Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID:
Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc
:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe:
List-Post:List-Owner:List-Archive;
bh=z1lqwdBZJ0sTD4rZ46ZjbWOscPtZ2EPKZGsp06jLE0w=; b=NLOcgL+mus7Skaa9PIWT7gktgs
MhAZGbCVf9Pm0Vw/7z8+ZpN0fAKJHBwEZsaFjTvkqYy7mNK737jaUTjrHteq20gUuIelA/oa3j7k2
eafhKko9YsFofe6AE5XalUAw6oNFB/r1wYLkiNiIjjjh+QUtq5TvuBwZf+0caB3yNCTs=;
Received: from mail-ed1-f48.google.com ([209.85.208.48])
by sfi-mx-2.v28.lw.sourceforge.com with esmtps
(TLS1.2:ECDHE-RSA-AES128-GCM-SHA256:128) (Exim 4.95)
id 1vhpbr-0005d1-Gp for openvpn-devel@lists.sourceforge.net;
Mon, 19 Jan 2026 13:48:00 +0000
Received: by mail-ed1-f48.google.com with SMTP id
4fb4d7f45d1cf-64baaa754c6so6573837a12.3
for <openvpn-devel@lists.sourceforge.net>;
Mon, 19 Jan 2026 05:47:59 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=mandelbit.com; s=google; t=1768830468; x=1769435268;
darn=lists.sourceforge.net;
h=content-transfer-encoding:mime-version:references:in-reply-to
:message-id:date:subject:cc:to:from:from:to:cc:subject:date
:message-id:reply-to;
bh=z1lqwdBZJ0sTD4rZ46ZjbWOscPtZ2EPKZGsp06jLE0w=;
b=mk8ojGxfO1I3k0r6KGD1uAF2Q2rMezn+Sknmf11JS3j1TCoDMw1nw/J89hOmTLTUWc
0uWlTpQHIW1I4m1n2aehFa8V4lyGeTHLW1I1hcsm4KpeFX0QvIgZbBIkwToqOxZI7XC+
AW8pLsOOevtKXxCoUrIqO80o6OQScjNmYgSktVuy+61eb8prdvjLToCDTFmj5/db9QiG
8qBTlwLZeHV1pcQj5omS6WOF6ZBxcaw+uECE1WN+NTHI4A8FCe2TZ2nCVnxOX+KZZoWm
NgNwDZVE5ZSmHukUyemfZzflvLIX9THId5/FtfoIbG7OnF7sRM7Lp0ouV/c8YQjsAaqY
Uusw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20230601; t=1768830468; x=1769435268;
h=content-transfer-encoding:mime-version:references:in-reply-to
:message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from
:to:cc:subject:date:message-id:reply-to;
bh=z1lqwdBZJ0sTD4rZ46ZjbWOscPtZ2EPKZGsp06jLE0w=;
b=NGcjmh+5LZ1tWlj73VZAOB0PEfoL1JsONQhIjLZBOM7AnHqWDmTD0Fkedx5Fd+LSxc
iHdYH0AwFHTjktkyLR+RSYBpDdWnH9LbMuxaolJtz2PDNnF2WNX25/XHUbpoZwCEEyxJ
J2NIxzTWjJPTSzJmMQoIKbGnzvdYtSbliGKNkj8Ms3JCOVVIVA+/dEvvpu03J6LEtrM2
OaFs29AcOPGWGLLbstvYawEbv/93WsCckULSm2oBBpiuSMYOpk+uMzpXnDIRn0zs9WSa
07G6xqQWPdYMrPL0/jVK/zWNzb3SYRr1cJ5HsHBpZdZGGrG9gTMhL9hRkVHS/TKLmfbI
hBlg==
X-Gm-Message-State: AOJu0Yzgmndo7GtqljNdQwPaSv2jK7/6w9xg6JHd0VSomZBjfiw1qNLo
d4iajd1Umb+roYj8MomoqeQLr1odcpgilKWC7aPk2hO7Ae/yVx6IBWC06EbUc5to3q9BmUmkGCZ
3aBmV
X-Gm-Gg: AY/fxX6wKvva5v7ENgJ+MNw8AL14PSECVb3SToSuz760roNyfZwT4f6loiVhiCKsmt8
11CrE4orN+x/bHSU8u5mvNPKvdu1AEqkNAWAtc6MqBXzY7gpQmf7FyWDua9QWl3P8oDfS5t1zSN
MHBV12+l1cQhJ3tnO/NcWwJPgA4f+HiGEoB/Jmz6geEn8aAk/+Xa9aCEgsQ7luiC7hqRklcDs3f
1SY7c9NzqmLY+staJkeJkQFMkf/gCv0Fp0oIl2eqDdIxSmKqPhgVkWo4n0LtmD/REf5+xzOCRL0
y+Nj5SaOY1KdF/h2D8ypxxrrksc/ID9YDq1k9cIUTCUfN19J83wmvWLx9u/hwkRVSMFL7U21fqi
acY/94mjtBGErirA7AxX0aXyBkSw5xfuxLCdNthVho7sUxeOkQG4i4sY0isqmzc8Y+u8Ag8SETu
qkiY8IQQ==
X-Received: by 2002:a17:907:3c84:b0:b73:6b24:14ba with SMTP id
a640c23a62f3a-b8792d489e8mr913133266b.8.1768828483547;
Mon, 19 Jan 2026 05:14:43 -0800 (PST)
Received: from fedora ([2a01:e11:600c:d1a0:3dc8:57d2:efb7:51a8])
by smtp.gmail.com with ESMTPSA id
a640c23a62f3a-b87959fbd23sm1099805066b.51.2026.01.19.05.14.43
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Mon, 19 Jan 2026 05:14:43 -0800 (PST)
From: Ralf Lici <ralf@mandelbit.com>
To: openvpn-devel@lists.sourceforge.net
Date: Mon, 19 Jan 2026 14:14:00 +0100
Message-ID: <20260119131400.424161-3-ralf@mandelbit.com>
X-Mailer: git-send-email 2.52.0
In-Reply-To: <20260119131400.424161-1-ralf@mandelbit.com>
References: <20260119131400.424161-1-ralf@mandelbit.com>
MIME-Version: 1.0
X-Spam-Score: -0.2 (/)
X-Spam-Report: Spam detection software,
running on the system "sfi-spamd-2.hosts.colo.sdot.me",
has NOT identified this incoming email as spam. The original
message has been attached to this so you can view it or label
similar future email. If you have any questions, see
the administrator of that system for details.
Content preview: The current code builds an sk_buff_head after GSO
segmentation
but then treats it as a raw skb list: accessing elements via skb_list.next
and breaking the list circularity by setting skb_list.prev->ne [...]
Content analysis details: (-0.2 points, 5.0 required)
pts rule name description
---- ----------------------
--------------------------------------------------
0.1 DKIM_SIGNED Message has a DKIM or DK signature,
not necessarily valid
-0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from
envelope-from domain
-0.1 DKIM_VALID Message has at least one valid DKIM or DK signature
-0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's
domain 0.0 RCVD_IN_MSPIKE_H2 RBL: Average reputation (+2)
[209.85.208.48 listed in wl.mailspike.net]
X-Headers-End: 1vhpbr-0005d1-Gp
Subject: [Openvpn-devel] [PATCH ovpn net 3/3] ovpn: use sk_buff_head
properly in ovpn_net_xmit
X-BeenThere: openvpn-devel@lists.sourceforge.net
X-Mailman-Version: 2.1.21
Precedence: list
List-Id: <openvpn-devel.lists.sourceforge.net>
List-Unsubscribe: <https://lists.sourceforge.net/lists/options/openvpn-devel>,
<mailto:openvpn-devel-request@lists.sourceforge.net?subject=unsubscribe>
List-Archive:
<http://sourceforge.net/mailarchive/forum.php?forum_name=openvpn-devel>
List-Post: <mailto:openvpn-devel@lists.sourceforge.net>
List-Help: <mailto:openvpn-devel-request@lists.sourceforge.net?subject=help>
List-Subscribe: <https://lists.sourceforge.net/lists/listinfo/openvpn-devel>,
<mailto:openvpn-devel-request@lists.sourceforge.net?subject=subscribe>
Cc: Sabrina Dubroca <sd@queasysnail.net>
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: openvpn-devel-bounces@lists.sourceforge.net
X-getmail-retrieved-from-mailbox: Inbox
X-GMAIL-THRID: =?utf-8?q?1854753197889923042?=
X-GMAIL-MSGID: =?utf-8?q?1854753197889923042?=
|
| Series |
[Openvpn-devel,ovpn,net,1/3] ovpn: set sk_user_data before overriding callbacks
|
|
Commit Message
Ralf Lici
Jan. 19, 2026, 1:14 p.m. UTC
The current code builds an sk_buff_head after GSO segmentation but then
treats it as a raw skb list: accessing elements via skb_list.next and
breaking the list circularity by setting skb_list.prev->next to NULL.
Clean this up by changing ovpn_send to take an sk_buff_head parameter
and use standard sk_buff_head APIs. Introduce ovpn_send_one helper to
wrap single skbs in an sk_buff_head for ovpn_xmit_special.
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
---
drivers/net/ovpn/io.c | 74 +++++++++++++++++++++++++++----------------
1 file changed, 46 insertions(+), 28 deletions(-)
Comments
You're submitting this for "net" but this looks more like a clean up that should be sent to net-next. I don't know how Antonio will handle this, but for netdev submissions this distinction matters, see https://docs.kernel.org/process/maintainer-netdev.html 2026-01-19, 14:14:00 +0100, Ralf Lici wrote: > The current code builds an sk_buff_head after GSO segmentation but then > treats it as a raw skb list: accessing elements via skb_list.next and > breaking the list circularity by setting skb_list.prev->next to NULL. > > Clean this up by changing ovpn_send to take an sk_buff_head parameter > and use standard sk_buff_head APIs. Introduce ovpn_send_one helper to > wrap single skbs in an sk_buff_head for ovpn_xmit_special. Not a strong objection, but I'm not so convinced by this clean up. Using a sk_buff_head is maybe a little bit nicer conceptually, but it doesn't result in a code improvement, especially since you have to add ovpn_send_one(). A few small comments on the implementation: > Signed-off-by: Ralf Lici <ralf@mandelbit.com> > --- > drivers/net/ovpn/io.c | 74 +++++++++++++++++++++++++++---------------- > 1 file changed, 46 insertions(+), 28 deletions(-) > > diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c > index c59501344d97..249751cd630b 100644 > --- a/drivers/net/ovpn/io.c > +++ b/drivers/net/ovpn/io.c > @@ -329,8 +329,8 @@ static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) > return true; > } > > -/* send skb to connected peer, if any */ > -static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, > +/* send skb_list to connected peer, if any */ > +static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff_head *skb_list, > struct ovpn_peer *peer) > { > struct sk_buff *curr, *next; > @@ -338,7 +338,8 @@ static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, > /* this might be a GSO-segmented skb list: process each skb > * independently > */ > - skb_list_walk_safe(skb, curr, next) { > + skb_queue_walk_safe(skb_list, curr, next) { > + __skb_unlink(curr, skb_list); Why is this needed now but wasn't before? > if (unlikely(!ovpn_encrypt_one(peer, curr))) { > dev_dstats_tx_dropped(ovpn->dev); > kfree_skb(curr); > @@ -368,6 +369,26 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) > if (unlikely(!proto || skb->protocol != proto)) > goto drop; > > + /* retrieve peer serving the destination IP of this packet */ > + peer = ovpn_peer_get_by_dst(ovpn, skb); > + if (unlikely(!peer)) { > + switch (skb->protocol) { > + case htons(ETH_P_IP): > + net_dbg_ratelimited("%s: no peer to send data to dst=%pI4\n", > + netdev_name(ovpn->dev), > + &ip_hdr(skb)->daddr); > + break; > + case htons(ETH_P_IPV6): > + net_dbg_ratelimited("%s: no peer to send data to dst=%pI6c\n", > + netdev_name(ovpn->dev), > + &ipv6_hdr(skb)->daddr); > + break; > + } > + goto drop; > + } > + /* dst was needed for peer selection - it can now be dropped */ > + skb_dst_drop(skb); Moving this code looks like a separate clean up? Or is this needed for the conversion to sk_buff_head?
On Wed, 2026-01-21 at 17:53 +0100, Sabrina Dubroca wrote: > You're submitting this for "net" but this looks more like a clean up > that should be sent to net-next. I don't know how Antonio will handle > this, but for netdev submissions this distinction matters, see > https://docs.kernel.org/process/maintainer-netdev.html I think you are right. I initially considered this a fix, but I agree it's more appropriate for net-next. I'll leave it to Antonio to place it in the right PR. > 2026-01-19, 14:14:00 +0100, Ralf Lici wrote: > > The current code builds an sk_buff_head after GSO segmentation but > > then > > treats it as a raw skb list: accessing elements via skb_list.next > > and > > breaking the list circularity by setting skb_list.prev->next to > > NULL. > > > > Clean this up by changing ovpn_send to take an sk_buff_head > > parameter > > and use standard sk_buff_head APIs. Introduce ovpn_send_one helper > > to > > wrap single skbs in an sk_buff_head for ovpn_xmit_special. > > Not a strong objection, but I'm not so convinced by this clean > up. Using a sk_buff_head is maybe a little bit nicer conceptually, but > it doesn't result in a code improvement, especially since you have to > add ovpn_send_one(). > I agree this adds a small helper, but what motivated this change is that the current usage of sk_buff_head in ovpn_net_xmit looks a bit like a hack or an API violation. In the current code, we build an sk_buff_head but then manually break the ring (skb_list.prev->next = NULL) to treat it as a raw singly linked chain. This relies on implementation details rather than the API. Even though we do not (and likely will not) need the circularity, staying within the API feels safer and more maintainable. Also, the overhead added by ovpn_send_one should be negligible, since it is only used for keepalives. Hopefully that makes sense. > A few small comments on the implementation: > > > Signed-off-by: Ralf Lici <ralf@mandelbit.com> > > --- > > drivers/net/ovpn/io.c | 74 +++++++++++++++++++++++++++------------- > > --- > > 1 file changed, 46 insertions(+), 28 deletions(-) > > > > diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c > > index c59501344d97..249751cd630b 100644 > > --- a/drivers/net/ovpn/io.c > > +++ b/drivers/net/ovpn/io.c > > @@ -329,8 +329,8 @@ static bool ovpn_encrypt_one(struct ovpn_peer > > *peer, struct sk_buff *skb) > > return true; > > } > > > > -/* send skb to connected peer, if any */ > > -static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, > > +/* send skb_list to connected peer, if any */ > > +static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff_head > > *skb_list, > > struct ovpn_peer *peer) > > { > > struct sk_buff *curr, *next; > > @@ -338,7 +338,8 @@ static void ovpn_send(struct ovpn_priv *ovpn, > > struct sk_buff *skb, > > /* this might be a GSO-segmented skb list: process each skb > > * independently > > */ > > - skb_list_walk_safe(skb, curr, next) { > > + skb_queue_walk_safe(skb_list, curr, next) { > > + __skb_unlink(curr, skb_list); > > Why is this needed now but wasn't before? Since the new code aims to use skb_list as a proper circular doubly linked list and to comply with the sk_buff_head API, the unlinking is necessary to maintain a valid skb_list while processing each of its elements. This also seems to be a common pattern throughout the kernel. It is true, though, that after ovpn_send we do not use skb_list anymore, so this is not strictly necessary. Let me know if you think I should remove it. > > if (unlikely(!ovpn_encrypt_one(peer, curr))) { > > dev_dstats_tx_dropped(ovpn->dev); > > kfree_skb(curr); > > @@ -368,6 +369,26 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, > > struct net_device *dev) > > if (unlikely(!proto || skb->protocol != proto)) > > goto drop; > > > > + /* retrieve peer serving the destination IP of this packet > > */ > > + peer = ovpn_peer_get_by_dst(ovpn, skb); > > + if (unlikely(!peer)) { > > + switch (skb->protocol) { > > + case htons(ETH_P_IP): > > + net_dbg_ratelimited("%s: no peer to send > > data to dst=%pI4\n", > > + netdev_name(ovpn->dev), > > + &ip_hdr(skb)->daddr); > > + break; > > + case htons(ETH_P_IPV6): > > + net_dbg_ratelimited("%s: no peer to send > > data to dst=%pI6c\n", > > + netdev_name(ovpn->dev), > > + &ipv6_hdr(skb)->daddr); > > + break; > > + } > > + goto drop; > > + } > > + /* dst was needed for peer selection - it can now be > > dropped */ > > + skb_dst_drop(skb); > > Moving this code looks like a separate clean up? Or is this needed for > the conversion to sk_buff_head? While this could technically be a separate cleanup, I included it here because it reorganizes the function to accommodate the new lifecycle of the skb variable. Once we commit to populating the sk_buff_head and nullifying the original skb, the peer lookup logically has to happen earlier. Grouping these changes keeps the function coherent throughout the refactoring. Otherwise we would have had to pass skb_list.next to ovpn_peer_get_by_dst, which would have defeated the purpose of the patch. That said, I recognize it could also be viewed as a standalone patch. If you prefer a 2-step cleanup for better atomicity, I am happy to split this into two commits: one for the peer retrieval move and another for the sk_buff_head API transition. Please let me know your preference.
2026-01-22, 13:48:11 +0100, Ralf Lici wrote: > On Wed, 2026-01-21 at 17:53 +0100, Sabrina Dubroca wrote: > > You're submitting this for "net" but this looks more like a clean up > > that should be sent to net-next. I don't know how Antonio will handle > > this, but for netdev submissions this distinction matters, see > > https://docs.kernel.org/process/maintainer-netdev.html > > I think you are right. I initially considered this a fix, but I agree > it's more appropriate for net-next. I'll leave it to Antonio to place it > in the right PR. > > > 2026-01-19, 14:14:00 +0100, Ralf Lici wrote: > > > The current code builds an sk_buff_head after GSO segmentation but > > > then > > > treats it as a raw skb list: accessing elements via skb_list.next > > > and > > > breaking the list circularity by setting skb_list.prev->next to > > > NULL. > > > > > > Clean this up by changing ovpn_send to take an sk_buff_head > > > parameter > > > and use standard sk_buff_head APIs. Introduce ovpn_send_one helper > > > to > > > wrap single skbs in an sk_buff_head for ovpn_xmit_special. > > > > Not a strong objection, but I'm not so convinced by this clean > > up. Using a sk_buff_head is maybe a little bit nicer conceptually, but > > it doesn't result in a code improvement, especially since you have to > > add ovpn_send_one(). > > > > I agree this adds a small helper, but what motivated this change is that > the current usage of sk_buff_head in ovpn_net_xmit looks a bit like a > hack or an API violation. In the current code, we build an sk_buff_head > but then manually break the ring (skb_list.prev->next = NULL) to treat > it as a raw singly linked chain. I'd say we're building a skb list and happen to use an sk_buff_head to make it easier. So I'm not really convinced by the benefit of this patch. > This relies on implementation details > rather than the API. Even though we do not (and likely will not) need > the circularity, staying within the API feels safer and more > maintainable. > > Also, the overhead added by ovpn_send_one should be negligible, since it > is only used for keepalives. Sure, my comment was more about code simplicity than runtime overhead. > Hopefully that makes sense. > > > > A few small comments on the implementation: > > > > > Signed-off-by: Ralf Lici <ralf@mandelbit.com> > > > --- > > > drivers/net/ovpn/io.c | 74 +++++++++++++++++++++++++++------------- > > > --- > > > 1 file changed, 46 insertions(+), 28 deletions(-) > > > > > > diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c > > > index c59501344d97..249751cd630b 100644 > > > --- a/drivers/net/ovpn/io.c > > > +++ b/drivers/net/ovpn/io.c > > > @@ -329,8 +329,8 @@ static bool ovpn_encrypt_one(struct ovpn_peer > > > *peer, struct sk_buff *skb) > > > return true; > > > } > > > > > > -/* send skb to connected peer, if any */ > > > -static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, > > > +/* send skb_list to connected peer, if any */ > > > +static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff_head > > > *skb_list, > > > struct ovpn_peer *peer) > > > { > > > struct sk_buff *curr, *next; > > > @@ -338,7 +338,8 @@ static void ovpn_send(struct ovpn_priv *ovpn, > > > struct sk_buff *skb, > > > /* this might be a GSO-segmented skb list: process each skb > > > * independently > > > */ > > > - skb_list_walk_safe(skb, curr, next) { > > > + skb_queue_walk_safe(skb_list, curr, next) { > > > + __skb_unlink(curr, skb_list); > > > > Why is this needed now but wasn't before? > > Since the new code aims to use skb_list as a proper circular doubly > linked list and to comply with the sk_buff_head API, the unlinking is > necessary to maintain a valid skb_list while processing each of its > elements. This also seems to be a common pattern throughout the kernel. > > It is true, though, that after ovpn_send we do not use skb_list anymore, > so this is not strictly necessary. Let me know if you think I should > remove it. If the aim is to properly use the sk_buff_head API, then I guess it makes sense. The skb_mark_not_on_list() call in ovpn_encrypt_post is not needed anymore. > > > if (unlikely(!ovpn_encrypt_one(peer, curr))) { > > > dev_dstats_tx_dropped(ovpn->dev); > > > kfree_skb(curr); > > > @@ -368,6 +369,26 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, > > > struct net_device *dev) > > > if (unlikely(!proto || skb->protocol != proto)) > > > goto drop; > > > > > > + /* retrieve peer serving the destination IP of this packet > > > */ > > > + peer = ovpn_peer_get_by_dst(ovpn, skb); > > > + if (unlikely(!peer)) { > > > + switch (skb->protocol) { > > > + case htons(ETH_P_IP): > > > + net_dbg_ratelimited("%s: no peer to send > > > data to dst=%pI4\n", > > > + netdev_name(ovpn->dev), > > > + &ip_hdr(skb)->daddr); > > > + break; > > > + case htons(ETH_P_IPV6): > > > + net_dbg_ratelimited("%s: no peer to send > > > data to dst=%pI6c\n", > > > + netdev_name(ovpn->dev), > > > + &ipv6_hdr(skb)->daddr); > > > + break; > > > + } > > > + goto drop; > > > + } > > > + /* dst was needed for peer selection - it can now be > > > dropped */ > > > + skb_dst_drop(skb); > > > > Moving this code looks like a separate clean up? Or is this needed for > > the conversion to sk_buff_head? > > While this could technically be a separate cleanup, I included it here > because it reorganizes the function to accommodate the new lifecycle of > the skb variable. Once we commit to populating the sk_buff_head and > nullifying the original skb, the peer lookup logically has to happen > earlier. Grouping these changes keeps the function coherent throughout > the refactoring. Otherwise we would have had to pass skb_list.next to > ovpn_peer_get_by_dst, which would have defeated the purpose of the > patch. > > That said, I recognize it could also be viewed as a standalone patch. If > you prefer a 2-step cleanup for better atomicity, I am happy to split > this into two commits: one for the peer retrieval move and another for > the sk_buff_head API transition. Please let me know your preference. Maybe. Either way, I think you're missing a call to ovpn_peer_put() in the error cases that happen after fetching the peer. Before this patch there was no possible failure once we'd grabbed the peer. One more semi-nitpicky comment: > + if (unlikely(skb_queue_empty(&skb_list))) > goto drop; Is this needed? If the queue is empty we've already counted one drop for each segment during the list-to-sk_buff_head loop, and ovpn_send should handle an empty queue without problem?
On Mon, 2026-01-26 at 16:48 +0100, Sabrina Dubroca wrote: > 2026-01-22, 13:48:11 +0100, Ralf Lici wrote: > > On Wed, 2026-01-21 at 17:53 +0100, Sabrina Dubroca wrote: > > > You're submitting this for "net" but this looks more like a clean > > > up > > > that should be sent to net-next. I don't know how Antonio will > > > handle > > > this, but for netdev submissions this distinction matters, see > > > https://docs.kernel.org/process/maintainer-netdev.html > > > > I think you are right. I initially considered this a fix, but I > > agree > > it's more appropriate for net-next. I'll leave it to Antonio to > > place it > > in the right PR. > > > > > 2026-01-19, 14:14:00 +0100, Ralf Lici wrote: > > > > The current code builds an sk_buff_head after GSO segmentation > > > > but > > > > then > > > > treats it as a raw skb list: accessing elements via > > > > skb_list.next > > > > and > > > > breaking the list circularity by setting skb_list.prev->next to > > > > NULL. > > > > > > > > Clean this up by changing ovpn_send to take an sk_buff_head > > > > parameter > > > > and use standard sk_buff_head APIs. Introduce ovpn_send_one > > > > helper > > > > to > > > > wrap single skbs in an sk_buff_head for ovpn_xmit_special. > > > > > > Not a strong objection, but I'm not so convinced by this clean > > > up. Using a sk_buff_head is maybe a little bit nicer conceptually, > > > but > > > it doesn't result in a code improvement, especially since you have > > > to > > > add ovpn_send_one(). > > > > > > > I agree this adds a small helper, but what motivated this change is > > that > > the current usage of sk_buff_head in ovpn_net_xmit looks a bit like > > a > > hack or an API violation. In the current code, we build an > > sk_buff_head > > but then manually break the ring (skb_list.prev->next = NULL) to > > treat > > it as a raw singly linked chain. > > I'd say we're building a skb list and happen to use an sk_buff_head to > make it easier. So I'm not really convinced by the benefit of this > patch. I understand your point regarding the simplicity and convenience of the original implementation. After discussing this further with Antonio, we have decided to drop this change and maintain the current structure and sequence of operations in ovpn_net_xmit. Anyway, since there's currently a risk of UAF when using the 'skb' variable after calling skb_share_check, I'll add a patch to address that specific issue maintaining the current pattern. Thank you for the feedback. > > > This relies on implementation details > > rather than the API. Even though we do not (and likely will not) > > need > > the circularity, staying within the API feels safer and more > > maintainable. > > > > Also, the overhead added by ovpn_send_one should be negligible, > > since it > > is only used for keepalives. > > Sure, my comment was more about code simplicity than runtime overhead. > > > Hopefully that makes sense. > > > > > > > A few small comments on the implementation: > > > > > > > Signed-off-by: Ralf Lici <ralf@mandelbit.com> > > > > --- > > > > drivers/net/ovpn/io.c | 74 +++++++++++++++++++++++++++--------- > > > > ---- > > > > --- > > > > 1 file changed, 46 insertions(+), 28 deletions(-) > > > > > > > > diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c > > > > index c59501344d97..249751cd630b 100644 > > > > --- a/drivers/net/ovpn/io.c > > > > +++ b/drivers/net/ovpn/io.c > > > > @@ -329,8 +329,8 @@ static bool ovpn_encrypt_one(struct > > > > ovpn_peer > > > > *peer, struct sk_buff *skb) > > > > return true; > > > > } > > > > > > > > -/* send skb to connected peer, if any */ > > > > -static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff > > > > *skb, > > > > +/* send skb_list to connected peer, if any */ > > > > +static void ovpn_send(struct ovpn_priv *ovpn, struct > > > > sk_buff_head > > > > *skb_list, > > > > struct ovpn_peer *peer) > > > > { > > > > struct sk_buff *curr, *next; > > > > @@ -338,7 +338,8 @@ static void ovpn_send(struct ovpn_priv > > > > *ovpn, > > > > struct sk_buff *skb, > > > > /* this might be a GSO-segmented skb list: process each > > > > skb > > > > * independently > > > > */ > > > > - skb_list_walk_safe(skb, curr, next) { > > > > + skb_queue_walk_safe(skb_list, curr, next) { > > > > + __skb_unlink(curr, skb_list); > > > > > > Why is this needed now but wasn't before? > > > > Since the new code aims to use skb_list as a proper circular doubly > > linked list and to comply with the sk_buff_head API, the unlinking > > is > > necessary to maintain a valid skb_list while processing each of its > > elements. This also seems to be a common pattern throughout the > > kernel. > > > > It is true, though, that after ovpn_send we do not use skb_list > > anymore, > > so this is not strictly necessary. Let me know if you think I should > > remove it. > > If the aim is to properly use the sk_buff_head API, then I guess it > makes sense. > > The skb_mark_not_on_list() call in ovpn_encrypt_post is not needed > anymore. > > > > > if (unlikely(!ovpn_encrypt_one(peer, curr))) { > > > > dev_dstats_tx_dropped(ovpn->dev); > > > > kfree_skb(curr); > > > > @@ -368,6 +369,26 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff > > > > *skb, > > > > struct net_device *dev) > > > > if (unlikely(!proto || skb->protocol != proto)) > > > > goto drop; > > > > > > > > + /* retrieve peer serving the destination IP of this > > > > packet > > > > */ > > > > + peer = ovpn_peer_get_by_dst(ovpn, skb); > > > > + if (unlikely(!peer)) { > > > > + switch (skb->protocol) { > > > > + case htons(ETH_P_IP): > > > > + net_dbg_ratelimited("%s: no peer to > > > > send > > > > data to dst=%pI4\n", > > > > + netdev_name(ovpn- > > > > >dev), > > > > + &ip_hdr(skb)- > > > > >daddr); > > > > + break; > > > > + case htons(ETH_P_IPV6): > > > > + net_dbg_ratelimited("%s: no peer to > > > > send > > > > data to dst=%pI6c\n", > > > > + netdev_name(ovpn- > > > > >dev), > > > > + &ipv6_hdr(skb)- > > > > >daddr); > > > > + break; > > > > + } > > > > + goto drop; > > > > + } > > > > + /* dst was needed for peer selection - it can now be > > > > dropped */ > > > > + skb_dst_drop(skb); > > > > > > Moving this code looks like a separate clean up? Or is this needed > > > for > > > the conversion to sk_buff_head? > > > > While this could technically be a separate cleanup, I included it > > here > > because it reorganizes the function to accommodate the new lifecycle > > of > > the skb variable. Once we commit to populating the sk_buff_head and > > nullifying the original skb, the peer lookup logically has to happen > > earlier. Grouping these changes keeps the function coherent > > throughout > > the refactoring. Otherwise we would have had to pass skb_list.next > > to > > ovpn_peer_get_by_dst, which would have defeated the purpose of the > > patch. > > > > That said, I recognize it could also be viewed as a standalone > > patch. If > > you prefer a 2-step cleanup for better atomicity, I am happy to > > split > > this into two commits: one for the peer retrieval move and another > > for > > the sk_buff_head API transition. Please let me know your preference. > > Maybe. Either way, I think you're missing a call to ovpn_peer_put() in > the error cases that happen after fetching the peer. Before this patch > there was no possible failure once we'd grabbed the peer. > > > One more semi-nitpicky comment: > > > + if (unlikely(skb_queue_empty(&skb_list))) > > goto drop; > > Is this needed? If the queue is empty we've already counted one drop > for each segment during the list-to-sk_buff_head loop, and ovpn_send > should handle an empty queue without problem?
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index c59501344d97..249751cd630b 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -329,8 +329,8 @@ static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) return true; } -/* send skb to connected peer, if any */ -static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, +/* send skb_list to connected peer, if any */ +static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff_head *skb_list, struct ovpn_peer *peer) { struct sk_buff *curr, *next; @@ -338,7 +338,8 @@ static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, /* this might be a GSO-segmented skb list: process each skb * independently */ - skb_list_walk_safe(skb, curr, next) { + skb_queue_walk_safe(skb_list, curr, next) { + __skb_unlink(curr, skb_list); if (unlikely(!ovpn_encrypt_one(peer, curr))) { dev_dstats_tx_dropped(ovpn->dev); kfree_skb(curr); @@ -368,6 +369,26 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(!proto || skb->protocol != proto)) goto drop; + /* retrieve peer serving the destination IP of this packet */ + peer = ovpn_peer_get_by_dst(ovpn, skb); + if (unlikely(!peer)) { + switch (skb->protocol) { + case htons(ETH_P_IP): + net_dbg_ratelimited("%s: no peer to send data to dst=%pI4\n", + netdev_name(ovpn->dev), + &ip_hdr(skb)->daddr); + break; + case htons(ETH_P_IPV6): + net_dbg_ratelimited("%s: no peer to send data to dst=%pI6c\n", + netdev_name(ovpn->dev), + &ipv6_hdr(skb)->daddr); + break; + } + goto drop; + } + /* dst was needed for peer selection - it can now be dropped */ + skb_dst_drop(skb); + if (skb_is_gso(skb)) { segments = skb_gso_segment(skb, 0); if (IS_ERR(segments)) { @@ -381,8 +402,9 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) skb = segments; } - /* from this moment on, "skb" might be a list */ - + /* "skb" might be a raw list of skbs, transform it into a proper + * sk_buff_head list + */ __skb_queue_head_init(&skb_list); skb_list_walk_safe(skb, curr, next) { skb_mark_not_on_list(curr); @@ -399,40 +421,36 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) tx_bytes += curr->len; __skb_queue_tail(&skb_list, curr); } - skb_list.prev->next = NULL; + skb = NULL; - /* retrieve peer serving the destination IP of this packet */ - peer = ovpn_peer_get_by_dst(ovpn, skb); - if (unlikely(!peer)) { - switch (skb->protocol) { - case htons(ETH_P_IP): - net_dbg_ratelimited("%s: no peer to send data to dst=%pI4\n", - netdev_name(ovpn->dev), - &ip_hdr(skb)->daddr); - break; - case htons(ETH_P_IPV6): - net_dbg_ratelimited("%s: no peer to send data to dst=%pI6c\n", - netdev_name(ovpn->dev), - &ipv6_hdr(skb)->daddr); - break; - } + if (unlikely(skb_queue_empty(&skb_list))) goto drop; - } - /* dst was needed for peer selection - it can now be dropped */ - skb_dst_drop(skb); ovpn_peer_stats_increment_tx(&peer->vpn_stats, tx_bytes); - ovpn_send(ovpn, skb_list.next, peer); + ovpn_send(ovpn, &skb_list, peer); return NETDEV_TX_OK; drop: dev_dstats_tx_dropped(ovpn->dev); - skb_tx_error(skb); - kfree_skb_list(skb); + if (skb) { + skb_tx_error(skb); + kfree_skb_list(skb); + } return NETDEV_TX_OK; } +/* wrap a single skb in a list in order to pass it to ovpn_send */ +static void ovpn_send_one(struct ovpn_priv *ovpn, struct sk_buff *skb, + struct ovpn_peer *peer) +{ + struct sk_buff_head list; + + __skb_queue_head_init(&list); + __skb_queue_tail(&list, skb); + ovpn_send(ovpn, &list, peer); +} + /** * ovpn_xmit_special - encrypt and transmit an out-of-band message to peer * @peer: peer to send the message to @@ -464,5 +482,5 @@ void ovpn_xmit_special(struct ovpn_peer *peer, const void *data, skb->priority = TC_PRIO_BESTEFFORT; __skb_put_data(skb, data, len); - ovpn_send(ovpn, skb, peer); + ovpn_send_one(ovpn, skb, peer); }