[Openvpn-devel] [PATCH ovpn net-next v3 2/4] ovpn: include target netns ID in notifications

Marco Baffo <[email protected]> Wed, 29 Jul 2026 17:38:13 +0200
Newsgroups net.sourceforge.lists.openvpn-devel
Message-ID <[email protected]>
ovpn notifications are multicast in the network namespace of the peer
transport socket, but carry an ifindex from the ovpn device namespace.
If these namespaces differ, the ifindex alone is ambiguous to listeners.

Include the device namespace ID relative to the receiving namespace when
the two namespaces differ.

Notifications may be generated from softirq context, so use peernet2id()
without allocating a namespace ID. When the Netlink control and transport
sockets share a namespace, the mapping normally already exists because it
was needed to address the foreign interface. Otherwise, report
NETNSA_NSID_NOT_ASSIGNED unless userspace established the mapping
beforehand.

Fixes: 89d3c0e4612a ("ovpn: kill key and notify userspace in case of IV exhaustion")
Fixes: a215d253c17a ("ovpn: notify userspace when a peer is deleted")
Fixes: c841b676da98 ("ovpn: notify userspace on client float event")
Signed-off-by: Marco Baffo <[email protected]>
---
Changes in v3:
- Removed changes in the ovpn.yaml .
- Changed peernet2id_alloc() to peernet2id() to avoid potential
  deadlock when the notication is send from softirq context
  (peer-float, key-swap).

Changes in v2:
- This is a new patch.

 drivers/net/ovpn/netlink.c | 90 +++++++++++++++++++++-----------------
 1 file changed, 50 insertions(+), 40 deletions(-)

diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c
index b70ecfaf46c8..81953467e6fb 100644
--- a/drivers/net/ovpn/netlink.c
+++ b/drivers/net/ovpn/netlink.c
@@ -1167,6 +1167,47 @@ int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info)
 	return 0;
 }
 
+static int ovpn_nl_send_notify(struct ovpn_peer *peer, struct sk_buff *msg,
+			       void *hdr)
+{
+	struct ovpn_socket *sock;
+	struct net *net_sock, *net_dev;
+	int netnsid, ret = 0;
+
+	rcu_read_lock();
+	sock = rcu_dereference(peer->sock);
+	if (!sock) {
+		ret = -EINVAL;
+		goto unlock;
+	}
+
+	net_sock = sock_net(sock->sk);
+	net_dev = dev_net(peer->ovpn->dev);
+
+	/* The notification is delivered in the transport socket's netns. If the
+	 * ovpn device is elsewhere, report its netns ID relative to that netns.
+	 */
+	if (!net_eq(net_sock, net_dev)) {
+		/* Peer-float and key-swap notifications may be generated from
+		 * softirq context, so do not allocate an NSID here. If none
+		 * exists, peernet2id() returns NETNSA_NSID_NOT_ASSIGNED.
+		 */
+		netnsid = peernet2id(net_sock, net_dev);
+		if (nla_put_s32(msg, OVPN_A_TARGET_NETNSID, netnsid)) {
+			ret = -EMSGSIZE;
+			goto unlock;
+		}
+	}
+
+	genlmsg_end(msg, hdr);
+	genlmsg_multicast_netns(&ovpn_nl_family, net_sock, msg, 0,
+				OVPN_NLGRP_PEERS, GFP_ATOMIC);
+unlock:
+	rcu_read_unlock();
+
+	return ret;
+}
+
 /**
  * ovpn_nl_peer_del_notify - notify userspace about peer being deleted
  * @peer: the peer being deleted
@@ -1175,7 +1216,6 @@ int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info)
  */
 int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
 {
-	struct ovpn_socket *sock;
 	struct sk_buff *msg;
 	struct nlattr *attr;
 	int ret = -EMSGSIZE;
@@ -1209,22 +1249,12 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
 
 	nla_nest_end(msg, attr);
 
-	genlmsg_end(msg, hdr);
-
-	rcu_read_lock();
-	sock = rcu_dereference(peer->sock);
-	if (!sock) {
-		ret = -EINVAL;
-		goto err_unlock;
-	}
-	genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
-				OVPN_NLGRP_PEERS, GFP_ATOMIC);
-	rcu_read_unlock();
+	ret = ovpn_nl_send_notify(peer, msg, hdr);
+	if (ret < 0)
+		goto err_cancel_msg;
 
 	return 0;
 
-err_unlock:
-	rcu_read_unlock();
 err_cancel_msg:
 	genlmsg_cancel(msg, hdr);
 err_free_msg:
@@ -1242,7 +1272,6 @@ int ovpn_nl_peer_del_notify(struct ovpn_peer *peer)
 int ovpn_nl_peer_float_notify(struct ovpn_peer *peer,
 			      const struct sockaddr_storage *ss)
 {
-	struct ovpn_socket *sock;
 	struct sockaddr_in6 *sa6;
 	struct sockaddr_in *sa;
 	struct sk_buff *msg;
@@ -1291,22 +1320,13 @@ int ovpn_nl_peer_float_notify(struct ovpn_peer *peer,
 	}
 
 	nla_nest_end(msg, attr);
-	genlmsg_end(msg, hdr);
 
-	rcu_read_lock();
-	sock = rcu_dereference(peer->sock);
-	if (!sock) {
-		ret = -EINVAL;
-		goto err_unlock;
-	}
-	genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg,
-				0, OVPN_NLGRP_PEERS, GFP_ATOMIC);
-	rcu_read_unlock();
+	ret = ovpn_nl_send_notify(peer, msg, hdr);
+	if (ret < 0)
+		goto err_cancel_msg;
 
 	return 0;
 
-err_unlock:
-	rcu_read_unlock();
 err_cancel_msg:
 	genlmsg_cancel(msg, hdr);
 err_free_msg:
@@ -1323,7 +1343,6 @@ int ovpn_nl_peer_float_notify(struct ovpn_peer *peer,
  */
 int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id)
 {
-	struct ovpn_socket *sock;
 	struct nlattr *k_attr;
 	struct sk_buff *msg;
 	int ret = -EMSGSIZE;
@@ -1356,21 +1375,12 @@ int ovpn_nl_key_swap_notify(struct ovpn_peer *peer, u8 key_id)
 		goto err_cancel_msg;
 
 	nla_nest_end(msg, k_attr);
-	genlmsg_end(msg, hdr);
 
-	rcu_read_lock();
-	sock = rcu_dereference(peer->sock);
-	if (!sock) {
-		ret = -EINVAL;
-		goto err_unlock;
-	}
-	genlmsg_multicast_netns(&ovpn_nl_family, sock_net(sock->sk), msg, 0,
-				OVPN_NLGRP_PEERS, GFP_ATOMIC);
-	rcu_read_unlock();
+	ret = ovpn_nl_send_notify(peer, msg, hdr);
+	if (ret < 0)
+		goto err_cancel_msg;
 
 	return 0;
-err_unlock:
-	rcu_read_unlock();
 err_cancel_msg:
 	genlmsg_cancel(msg, hdr);
 err_free_msg:
-- 
2.43.0



_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel