From patchwork Tue May 12 14:43:58 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 4928 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:a719:b0:84a:48f:a1fd with SMTP id hl25csp2520245mab; Tue, 12 May 2026 07:45:10 -0700 (PDT) X-Forwarded-Encrypted: i=2; AFNElJ++3acXLzE2FAn3hDlMSVgMFS7VJYVLKps64nf8Q1EKqLjMjbcdxbt8MMYrrjUwKbBFyFPBwONZHlE=@openvpn.net X-Received: by 2002:a05:6871:729c:b0:422:efca:98d7 with SMTP id 586e51a60fabf-434f673f71dmr17017847fac.36.1778597110694; Tue, 12 May 2026 07:45:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1778597110; cv=none; d=google.com; s=arc-20240605; b=H9G1lrCIykB4NOBZaMoxg4sY+oZpj048djnoRei5NBt9yAGKtJvej0vGNgCNT7fge+ OD5srtQBvZk7q2GTvpW2Pc75Xf4oSjqG36UGJy6mGIBKESWvpEKOXmXDlhYKej5BLZ4w XfgXgEgiAQaz28Xp96O4H2yXQOE+eBP2hKfsOlk3iArZuRvpGVMizuRucbnh6mHc8HwS k8CuJaVmaYj2I45ZZbZYZAccAfmt6xa1UnLfshT2z31NHFoSqaqUKifgx/hD4FaMMbm7 E5gkiFZaPp9AZoCd9/VKL47Anl/terijPL3AhUgUg8X+cKdhLoa2WffcmxS4sM/6fPaU h0UQ== 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=g+9DvfloI70B8yB89kzSEYPzDvnntSBvKeFXNUSqmTE=; fh=BsMg/B0Yb/hS/rzP5Npz4luh0IleZm8REk1XWiWRt2A=; b=f019FnveMA7XkZv8F5FZbqlWMw7E1lJfGaHVj0i0hOBfKVSWjc/pN+cw+HPaVEyanV /6qtNvzau27glj+8hFzqpzGL/5TvXDI3suKoZJ/icts0YO838qZlIIXpN4kWaeTc9p0q 53w5AkjK7JJlCNidX/ApTcTQCNep9tbJstT+WP919XzbVgdAEmnzuAI/isC3cCYb0tgX gxLHeAOQjHNus9dySjd3vw0bwVU0wWXRa8cXnYe0GUKCZ2D0MD24dkbZMlO211B6fY2k qUBoe3vbjxA6CU3jK/wEFtH+YdiZb2/LOkpW4qSEkOWNX8ENvNouE1BrftfshULP/XJt s1YA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=OR409V5m; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=BsXKe+OS; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=DCzQZSrF; dkim=neutral (body hash did not verify) header.i=@unstable.cc header.s=MBO0001 header.b=0Rghiitf; 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 Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 586e51a60fabf-435574ab0c7si10306263fac.257.2026.05.12.07.45.10 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 12 May 2026 07:45:10 -0700 (PDT) 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=OR409V5m; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=BsXKe+OS; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=DCzQZSrF; dkim=neutral (body hash did not verify) header.i=@unstable.cc header.s=MBO0001 header.b=0Rghiitf; 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 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=g+9DvfloI70B8yB89kzSEYPzDvnntSBvKeFXNUSqmTE=; b=OR409V5maOrc78OkOei/H+54aL n8NXu8smhyeVlWd+OKZzV4IUW59owEORN2qIGpNeNpODyauULHl6E9MgXU6Ug3tjAPFGwiDSYSxek vd6BS7GxQmF7m8mLjedT0T2jemTQEjUm2VYCNF8fu1702DXo1Ft5usSRgZlT3zvveVow=; Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1wMoM6-0003hA-DH; Tue, 12 May 2026 14:45:06 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1wMoM3-0003h1-T9 for openvpn-devel@lists.sourceforge.net; Tue, 12 May 2026 14:45:04 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:Content-Type:MIME-Version :References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: 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=k6biFGtziJaxYwx43ol988YPakFnFkOnBdhJWbeuAVU=; b=BsXKe+OSgX8GC2r+qJF08udUVK zMki6nKBC/PRC3s1X8FPQYtiyA/ykypSWOwEuANK1bxuDOKpHqncbPKV9ZK+jv7lvcsSMpjghsWEf o7093cyvg66V4enVu39xle3lH6y2eqFctQKB9nMfu/UmYCiyoaMRrugROvPXv//Y53zM=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:Content-Type:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To: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=k6biFGtziJaxYwx43ol988YPakFnFkOnBdhJWbeuAVU=; b=DCzQZSrFiVfYU+hu1xSC/hfl95 2u+ssAkqM/Y0zb+bCps2GV/RsICge6c0WbpRBJXwHPV6DummZYkz07DCxLncvXkI4NbMfmIYTd9p9 xgrC78l09GvCmpF+NU91wGQqspEJKegOzme5z/auz9gBseQlI16QzJRqUHktbYt96cIQ=; Received: from mout-p-103.mailbox.org ([80.241.56.161]) by sfi-mx-2.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1wMoM2-0007IU-7i for openvpn-devel@lists.sourceforge.net; Tue, 12 May 2026 14:45:03 +0000 Received: from smtp102.mailbox.org (smtp102.mailbox.org [10.196.197.102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-103.mailbox.org (Postfix) with ESMTPS id 4gFKBH2T3kz9tyS; Tue, 12 May 2026 16:44:55 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=unstable.cc; s=MBO0001; t=1778597095; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=k6biFGtziJaxYwx43ol988YPakFnFkOnBdhJWbeuAVU=; b=0Rghiitf8Rh2auTrkp5PuYWoNAllvc279DTlYwTu9J5vAWipOsmKBwZ5irwfOKdL3T7G99 MwqNP/WL8SMdsElpERTnGxTKAkNQu1A/YGDl7bIuraC2U5/E2BXKyNsPtcanvJVmhxrcvd 1Lt2RdP7swmWU6QxG7ySuBKcysViQPVnKIJcADOEG+1lplyVYiwg4wTrDkI8n042h9ZTM9 X9mZneTAeRl9RZ+vwUoxQiX6uWKogK7kIdQ7qJ3WTvCzzMgfkKzby9inAbj09soCCWvO+O cFBz3a44c+09hM7jmkrDdyoVfq+FcpHHoO94b1GQ4rEOB/Vgbr6ivjI6zqiKbA== From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Tue, 12 May 2026 16:43:58 +0200 Message-ID: <20260512144358.419599-5-a@unstable.cc> In-Reply-To: <20260512144358.419599-1-a@unstable.cc> References: <20260512144358.419599-1-a@unstable.cc> 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: From: Ralf Lici Currently ovpn processes received packets in the same softirq context that delivers the skb. If the packet is valid and decapsulated, it is reinjected via a single per-interface gro_cells instance. Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1wMoM2-0007IU-7i Subject: [Openvpn-devel] [PATCH ovpn net-next 5/5] ovpn: add per-peer NAPI for RX decap and reinject X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: =?utf-8?q?1864994243792983481?= X-GMAIL-MSGID: =?utf-8?q?1864994243792983481?= From: Ralf Lici Currently ovpn processes received packets in the same softirq context that delivers the skb. If the packet is valid and decapsulated, it is reinjected via a single per-interface gro_cells instance. To improve parallelism and scaling, add a per-peer NAPI and skb queue for reception and reinjection. On receive, the skb is enqueued to the peer’s queue and the peer NAPI is scheduled. The poll function drains the queue, processes the packet, and reinjects the decapsulated skb into the stack through that peer NAPI. This is the first patch introducing a more elaborated packet processing pipeline aimed at improving parallelism and scalability. Signed-off-by: Ralf Lici Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/io.c | 20 +++++-------- drivers/net/ovpn/main.c | 20 +------------ drivers/net/ovpn/ovpnpriv.h | 2 -- drivers/net/ovpn/peer.c | 60 +++++++++++++++++++++++++++++++++++++ drivers/net/ovpn/peer.h | 6 ++++ drivers/net/ovpn/tcp.c | 5 +++- drivers/net/ovpn/udp.c | 5 +++- 7 files changed, 82 insertions(+), 36 deletions(-) diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index 22c555dd962e..3e6c06b9a5ae 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -59,9 +59,6 @@ static bool ovpn_is_keepalive(struct sk_buff *skb) */ 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 @@ -89,20 +86,17 @@ static void ovpn_netdev_write(struct ovpn_peer *peer, struct sk_buff *skb) skb_reset_transport_header(skb); skb_reset_inner_headers(skb); - /* cause packet to be "received" by the interface */ - pkt_len = skb->len; + /* update RX stats with the size of decrypted packet */ + ovpn_peer_stats_increment_rx(&peer->vpn_stats, skb->len); /* we may get here in process context in case of TCP connections, - * therefore we have to disable BHs to ensure gro_cells_receive() - * and dev_dstats_rx_add() do not get corrupted or enter deadlock + * therefore we have to disable BHs to ensure dev_dstats_rx_add() + * does not get corrupted */ local_bh_disable(); - ret = gro_cells_receive(&peer->ovpn->gro_cells, skb); - if (likely(ret == NET_RX_SUCCESS)) { - /* update RX stats with the size of decrypted packet */ - ovpn_peer_stats_increment_rx(&peer->vpn_stats, pkt_len); - dev_dstats_rx_add(peer->ovpn->dev, pkt_len); - } + dev_dstats_rx_add(peer->ovpn->dev, skb->len); local_bh_enable(); + + napi_gro_receive(&peer->napi, skb); } void ovpn_decrypt_post(void *data, int ret) diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 2e0420febda0..57b743cebc79 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -74,30 +74,12 @@ static int ovpn_mp_alloc(struct ovpn_priv *ovpn) static int ovpn_net_init(struct net_device *dev) { struct ovpn_priv *ovpn = netdev_priv(dev); - int err = gro_cells_init(&ovpn->gro_cells, dev); - if (err < 0) - return err; - - err = ovpn_mp_alloc(ovpn); - if (err < 0) { - gro_cells_destroy(&ovpn->gro_cells); - return err; - } - - return 0; -} - -static void ovpn_net_uninit(struct net_device *dev) -{ - struct ovpn_priv *ovpn = netdev_priv(dev); - - gro_cells_destroy(&ovpn->gro_cells); + return ovpn_mp_alloc(ovpn); } static const struct net_device_ops ovpn_netdev_ops = { .ndo_init = ovpn_net_init, - .ndo_uninit = ovpn_net_uninit, .ndo_start_xmit = ovpn_net_xmit, }; diff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h index 5898f6adada7..703e90d1dafc 100644 --- a/drivers/net/ovpn/ovpnpriv.h +++ b/drivers/net/ovpn/ovpnpriv.h @@ -39,7 +39,6 @@ struct ovpn_peer_collection { * @lock: protect this object * @peers: data structures holding multi-peer references * @peer: in P2P mode, this is the only remote peer - * @gro_cells: pointer to the Generic Receive Offload cell * @keepalive_work: struct used to schedule keepalive periodic job */ struct ovpn_priv { @@ -48,7 +47,6 @@ struct ovpn_priv { spinlock_t lock; /* protect writing to the ovpn_priv object */ struct ovpn_peer_collection *peers; struct ovpn_peer __rcu *peer; - struct gro_cells gro_cells; struct delayed_work keepalive_work; }; diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index c02dfab51a6e..bb23dc4e4721 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "ovpnpriv.h" @@ -82,6 +83,53 @@ static void ovpn_peer_keepalive_send(struct work_struct *work) local_bh_enable(); } +bool ovpn_enqueue_encap(struct ovpn_peer *peer, struct sk_buff *skb) +{ + if (skb_queue_len(&peer->encap_q) >= + READ_ONCE(net_hotdata.max_backlog)) + return false; + + skb_queue_tail(&peer->encap_q, skb); + napi_schedule(&peer->napi); + return true; +} + +static int ovpn_peer_encap_poll(struct napi_struct *napi, int budget) +{ + struct ovpn_peer *peer = container_of(napi, struct ovpn_peer, napi); + struct sk_buff *skb; + int work = 0; + + while (work < budget && (skb = skb_dequeue(&peer->encap_q))) { + ovpn_recv(peer, skb); + ++work; + } + + if (work < budget) + napi_complete_done(napi, work); + + return work; +} + +static int ovpn_peer_napi_init(struct ovpn_peer *peer, struct net_device *dev) +{ + skb_queue_head_init(&peer->encap_q); + + set_bit(NAPI_STATE_NO_BUSY_POLL, &peer->napi.state); + netif_napi_add(dev, &peer->napi, ovpn_peer_encap_poll); + napi_enable(&peer->napi); + + return 0; +} + +static void ovpn_peer_napi_uninit(struct ovpn_peer *peer) +{ + napi_disable(&peer->napi); + netif_napi_del(&peer->napi); + + __skb_queue_purge(&peer->encap_q); +} + /** * ovpn_peer_new - allocate and initialize a new peer object * @ovpn: the openvpn instance inside which the peer should be created @@ -126,6 +174,17 @@ struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id) return ERR_PTR(ret); } + ret = ovpn_peer_napi_init(peer, ovpn->dev); + if (ret < 0) { + netdev_err(ovpn->dev, + "cannot initialize NAPI for peer %u\n", + peer->id); + ovpn_peer_napi_uninit(peer); + dst_cache_destroy(&peer->dst_cache); + kfree(peer); + return ERR_PTR(ret); + } + netdev_hold(ovpn->dev, &peer->dev_tracker, GFP_KERNEL); return peer; @@ -356,6 +415,7 @@ static void ovpn_peer_release_rcu(struct rcu_head *head) */ void ovpn_peer_release(struct ovpn_peer *peer) { + ovpn_peer_napi_uninit(peer); ovpn_crypto_state_release(&peer->crypto); spin_lock_bh(&peer->lock); ovpn_bind_reset(peer, NULL); diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index 328401570cba..eb0ec9605ced 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -46,6 +46,8 @@ * @crypto: the crypto configuration (ciphers, keys, etc..) * @dst_cache: cache for dst_entry used to send to peer * @bind: remote peer binding + * @encap_q: queue of encapsulated packets awaiting processing/decapsulation + * @napi: NAPI context for handling packet reception * @keepalive_interval: seconds after which a new keepalive should be sent * @keepalive_xmit_exp: future timestamp when next keepalive should be sent * @last_sent: timestamp of the last successfully sent packet @@ -100,6 +102,8 @@ struct ovpn_peer { struct ovpn_crypto_state crypto; struct dst_cache dst_cache; struct ovpn_bind __rcu *bind; + struct sk_buff_head encap_q; + struct napi_struct napi; unsigned long keepalive_interval; unsigned long keepalive_xmit_exp; time64_t last_sent; @@ -154,6 +158,8 @@ void ovpn_peer_hash_vpn_ip(struct ovpn_peer *peer); bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb, struct ovpn_peer *peer); +bool ovpn_enqueue_encap(struct ovpn_peer *peer, struct sk_buff *skb); + void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout); void ovpn_peer_keepalive_work(struct work_struct *work); diff --git a/drivers/net/ovpn/tcp.c b/drivers/net/ovpn/tcp.c index 65054cc84be5..87f9d785f44c 100644 --- a/drivers/net/ovpn/tcp.c +++ b/drivers/net/ovpn/tcp.c @@ -145,13 +145,16 @@ static void ovpn_tcp_rcv(struct strparser *strp, struct sk_buff *skb) if (WARN_ON(!ovpn_peer_hold(peer))) goto err_nopeer; - ovpn_recv(peer, skb); + if (unlikely(!ovpn_enqueue_encap(peer, skb))) + goto drop; + return; err: /* take reference for deferred peer deletion. should never fail */ if (WARN_ON(!ovpn_peer_hold(peer))) goto err_nopeer; schedule_work(&peer->tcp.defer_del_work); +drop: dev_dstats_rx_dropped(peer->ovpn->dev); err_nopeer: kfree_skb(skb); diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index b5d1ca014732..8adff0b90430 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -121,7 +121,10 @@ static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb) /* pop off outer UDP header */ __skb_pull(skb, sizeof(struct udphdr)); - ovpn_recv(peer, skb); + + if (unlikely(!ovpn_enqueue_encap(peer, skb))) + goto drop; + return 0; drop: