From: Antonio Quartulli <antonio@openvpn.net>
To: netdev@vger.kernel.org
Cc: Antonio Quartulli <antonio@openvpn.net>,
Sabrina Dubroca <sd@queasysnail.net>,
Ralf Lici <ralf@mandelbit.com>, Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>,
Andrew Lunn <andrew+netdev@lunn.ch>,
"David S. Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>
Subject: [PATCH net 08/10] ovpn: disable IPv4 redirects on MP interfaces
Date: Thu, 30 Jul 2026 11:46:19 +0200 [thread overview]
Message-ID: <20260730094624.4102963-9-antonio@openvpn.net> (raw)
In-Reply-To: <20260730094624.4102963-1-antonio@openvpn.net>
ovpn_mp_alloc() tried to disable SEND_REDIRECTS on a multipeer
interface, but it runs from ovpn_net_init() (->ndo_init), which
register_netdevice() invokes before the NETDEV_REGISTER notifier
chain. The IPv4 in_device is only created when that notifier reaches
inetdev_event() -> inetdev_init(), so __in_dev_get_rtnl() always
returned NULL at ndo_init time and the whole redirect-disabling block
(both the per-device and the per-netns IPV4_DEVCONF_ALL write) was
dead. MP interfaces therefore kept emitting ICMP redirects.
Disabling redirects only once is not enough either: the IPv4
in_device is destroyed and recreated when the interface is moved to a
different network namespace (NETDEV_UNREGISTER/NETDEV_REGISTER), and
the newly created in_device inherits the destination namespace
defaults, silently re-enabling SEND_REDIRECTS.
Disable redirects from ovpn_net_open() (->ndo_open) instead: it runs
every time the interface is brought up, including after the in_device
has been recreated, so the setting is always re-applied. This mirrors
what wireguard does in wg_open(). RTNL is held on the ndo_open() path,
so __in_dev_get_rtnl() is safe.
Fixes: 05003b408c20 ("ovpn: implement multi-peer support")
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
drivers/net/ovpn/main.c | 50 ++++++++++++++++++++++++++++-------------
1 file changed, 35 insertions(+), 15 deletions(-)
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
index 9d9a0ff690d6..3a04757d5c31 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -35,25 +35,11 @@ static void ovpn_priv_free(struct net_device *net)
static int ovpn_mp_alloc(struct ovpn_priv *ovpn)
{
- struct in_device *dev_v4;
int i;
if (ovpn->mode != OVPN_MODE_MP)
return 0;
- dev_v4 = __in_dev_get_rtnl(ovpn->dev);
- if (dev_v4) {
- /* disable redirects as Linux gets confused by ovpn
- * handling same-LAN routing.
- * This happens because a multipeer interface is used as
- * relay point between hosts in the same subnet, while
- * in a classic LAN this would not be needed because the
- * two hosts would be able to talk directly.
- */
- IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
- IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false;
- }
-
/* the peer container is fairly large, therefore we allocate it only in
* MP mode
*/
@@ -97,9 +83,38 @@ static void ovpn_net_uninit(struct net_device *dev)
gro_cells_destroy(&ovpn->gro_cells);
}
+static int ovpn_net_open(struct net_device *dev)
+{
+ struct ovpn_priv *ovpn = netdev_priv(dev);
+ struct in_device *dev_v4;
+
+ /* the IPv4 in_device (and thus its config) is recreated whenever the
+ * interface is moved to a new netns, so redirects must be disabled on
+ * every bring-up rather than once at creation time, otherwise the
+ * setting is silently lost after such a move
+ */
+ if (ovpn->mode == OVPN_MODE_MP) {
+ dev_v4 = __in_dev_get_rtnl(dev);
+ if (dev_v4) {
+ /* disable redirects as Linux gets confused by ovpn
+ * handling same-LAN routing.
+ * This happens because a multipeer interface is used as
+ * relay point between hosts in the same subnet, while
+ * in a classic LAN this would not be needed because the
+ * two hosts would be able to talk directly.
+ */
+ IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false);
+ IPV4_DEVCONF_ALL(dev_net(dev), SEND_REDIRECTS) = false;
+ }
+ }
+
+ return 0;
+}
+
static const struct net_device_ops ovpn_netdev_ops = {
.ndo_init = ovpn_net_init,
.ndo_uninit = ovpn_net_uninit,
+ .ndo_open = ovpn_net_open,
.ndo_start_xmit = ovpn_net_xmit,
};
@@ -183,6 +198,7 @@ static int ovpn_newlink(struct net_device *dev,
struct ovpn_priv *ovpn = netdev_priv(dev);
struct nlattr **data = params->data;
enum ovpn_mode mode = OVPN_MODE_P2P;
+ int ret;
if (data && data[IFLA_OVPN_MODE]) {
mode = nla_get_u8(data[IFLA_OVPN_MODE]);
@@ -207,7 +223,11 @@ static int ovpn_newlink(struct net_device *dev,
else
netif_carrier_off(dev);
- return register_netdevice(dev);
+ ret = register_netdevice(dev);
+ if (ret < 0)
+ return ret;
+
+ return 0;
}
static size_t ovpn_get_size(const struct net_device *dev)
--
2.54.0
next prev parent reply other threads:[~2026-07-30 9:46 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-30 9:46 [PATCH net 00/10] pull request: fixes for ovpn 2026-07-30 Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 01/10] ovpn: add missing rtnl_link_ops->get_size callback Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 02/10] ovpn: limit keepalive values to one day Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 03/10] ovpn: skip rehash for peers already removed from by_id Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 04/10] ovpn: rehash peer in by_transp_addr table on CMD_PEER_SET Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 05/10] ovpn: ensure socket is owned by ovpn before deref sk_user_data Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 06/10] ovpn: zero-initialize sockaddr before learning a floated endpoint Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 07/10] ovpn: hash floated peer by transport identity only Antonio Quartulli
2026-07-30 9:46 ` Antonio Quartulli [this message]
2026-07-30 9:46 ` [PATCH net 09/10] ovpn: ensure TCP vars are initialized first Antonio Quartulli
2026-07-30 9:46 ` [PATCH net 10/10] ovpn: fix incorrect use of rcu_access_pointer() Antonio Quartulli
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=20260730094624.4102963-9-antonio@openvpn.net \
--to=antonio@openvpn.net \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ralf@mandelbit.com \
--cc=sd@queasysnail.net \
/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