Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ovpn: introduce the ovpn_socket object

This specific structure is used in the ovpn kernel module
to wrap and carry around a standard kernel socket.

ovpn takes ownership of passed sockets and therefore an ovpn
specific objects is attached to them for status tracking
purposes.

Initially only UDP support is introduced. TCP will come in a later
patch.

Cc: willemdebruijn.kernel@gmail.com
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
Link: https://patch.msgid.link/20250415-b4-ovpn-v26-6-577f6097b964@openvpn.net
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Antonio Quartulli and committed by
Paolo Abeni
f6226ae7 80747cae

+362 -7
+2
drivers/net/ovpn/Makefile
··· 13 13 ovpn-y += netlink.o 14 14 ovpn-y += netlink-gen.o 15 15 ovpn-y += peer.o 16 + ovpn-y += socket.o 17 + ovpn-y += udp.o
+2 -1
drivers/net/ovpn/main.c
··· 116 116 struct ovpn_priv *ovpn = netdev_priv(dev); 117 117 118 118 if (ovpn->mode == OVPN_MODE_P2P) 119 - ovpn_peer_release_p2p(ovpn, OVPN_DEL_PEER_REASON_TEARDOWN); 119 + ovpn_peer_release_p2p(ovpn, NULL, 120 + OVPN_DEL_PEER_REASON_TEARDOWN); 120 121 121 122 unregister_netdevice_queue(dev, head); 122 123 }
+23 -5
drivers/net/ovpn/peer.c
··· 16 16 #include "main.h" 17 17 #include "netlink.h" 18 18 #include "peer.h" 19 + #include "socket.h" 19 20 20 21 static void unlock_ovpn(struct ovpn_priv *ovpn, 21 - struct llist_head *release_list) 22 + struct llist_head *release_list) 22 23 __releases(&ovpn->lock) 23 24 { 24 25 struct ovpn_peer *peer; 25 26 26 27 spin_unlock_bh(&ovpn->lock); 27 28 28 - llist_for_each_entry(peer, release_list->first, release_entry) 29 + llist_for_each_entry(peer, release_list->first, release_entry) { 30 + ovpn_socket_release(peer); 29 31 ovpn_peer_put(peer); 32 + } 30 33 } 31 34 32 35 /** ··· 397 394 /** 398 395 * ovpn_peer_release_p2p - release peer upon P2P device teardown 399 396 * @ovpn: the instance being torn down 397 + * @sk: if not NULL, release peer only if it's using this specific socket 400 398 * @reason: the reason for releasing the peer 401 399 */ 402 - void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, 400 + void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk, 403 401 enum ovpn_del_peer_reason reason) 404 402 { 403 + struct ovpn_socket *ovpn_sock; 405 404 LLIST_HEAD(release_list); 406 405 struct ovpn_peer *peer; 407 406 408 407 spin_lock_bh(&ovpn->lock); 409 408 peer = rcu_dereference_protected(ovpn->peer, 410 409 lockdep_is_held(&ovpn->lock)); 411 - if (peer) 412 - ovpn_peer_remove(peer, reason, &release_list); 410 + if (!peer) { 411 + spin_unlock_bh(&ovpn->lock); 412 + return; 413 + } 414 + 415 + if (sk) { 416 + ovpn_sock = rcu_access_pointer(peer->sock); 417 + if (!ovpn_sock || ovpn_sock->sock->sk != sk) { 418 + spin_unlock_bh(&ovpn->lock); 419 + ovpn_peer_put(peer); 420 + return; 421 + } 422 + } 423 + 424 + ovpn_peer_remove(peer, reason, &release_list); 413 425 unlock_ovpn(ovpn, &release_list); 414 426 }
+5 -1
drivers/net/ovpn/peer.h
··· 12 12 13 13 #include <net/dst_cache.h> 14 14 15 + #include "socket.h" 16 + 15 17 /** 16 18 * struct ovpn_peer - the main remote peer object 17 19 * @ovpn: main openvpn instance this peer belongs to ··· 22 20 * @vpn_addrs: IP addresses assigned over the tunnel 23 21 * @vpn_addrs.ipv4: IPv4 assigned to peer on the tunnel 24 22 * @vpn_addrs.ipv6: IPv6 assigned to peer on the tunnel 23 + * @sock: the socket being used to talk to this peer 25 24 * @dst_cache: cache for dst_entry used to send to peer 26 25 * @bind: remote peer binding 27 26 * @delete_reason: why peer was deleted (i.e. timeout, transport error, ..) ··· 39 36 struct in_addr ipv4; 40 37 struct in6_addr ipv6; 41 38 } vpn_addrs; 39 + struct ovpn_socket __rcu *sock; 42 40 struct dst_cache dst_cache; 43 41 struct ovpn_bind __rcu *bind; 44 42 enum ovpn_del_peer_reason delete_reason; ··· 74 70 struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id); 75 71 int ovpn_peer_add(struct ovpn_priv *ovpn, struct ovpn_peer *peer); 76 72 int ovpn_peer_del(struct ovpn_peer *peer, enum ovpn_del_peer_reason reason); 77 - void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, 73 + void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct sock *sk, 78 74 enum ovpn_del_peer_reason reason); 79 75 80 76 struct ovpn_peer *ovpn_peer_get_by_transp_addr(struct ovpn_priv *ovpn,
+197
drivers/net/ovpn/socket.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2020-2025 OpenVPN, Inc. 5 + * 6 + * Author: James Yonan <james@openvpn.net> 7 + * Antonio Quartulli <antonio@openvpn.net> 8 + */ 9 + 10 + #include <linux/net.h> 11 + #include <linux/netdevice.h> 12 + #include <linux/udp.h> 13 + 14 + #include "ovpnpriv.h" 15 + #include "main.h" 16 + #include "io.h" 17 + #include "peer.h" 18 + #include "socket.h" 19 + #include "udp.h" 20 + 21 + static void ovpn_socket_release_kref(struct kref *kref) 22 + { 23 + struct ovpn_socket *sock = container_of(kref, struct ovpn_socket, 24 + refcount); 25 + 26 + if (sock->sock->sk->sk_protocol == IPPROTO_UDP) 27 + ovpn_udp_socket_detach(sock); 28 + 29 + kfree_rcu(sock, rcu); 30 + } 31 + 32 + /** 33 + * ovpn_socket_put - decrease reference counter 34 + * @peer: peer whose socket reference counter should be decreased 35 + * @sock: the RCU protected peer socket 36 + * 37 + * This function is only used internally. Users willing to release 38 + * references to the ovpn_socket should use ovpn_socket_release() 39 + */ 40 + static void ovpn_socket_put(struct ovpn_peer *peer, struct ovpn_socket *sock) 41 + { 42 + kref_put(&sock->refcount, ovpn_socket_release_kref); 43 + } 44 + 45 + /** 46 + * ovpn_socket_release - release resources owned by socket user 47 + * @peer: peer whose socket should be released 48 + * 49 + * This function should be invoked when the user is shutting 50 + * down and wants to drop its link to the socket. 51 + * 52 + * In case of UDP, the detach routine will drop a reference to the 53 + * ovpn netdev, pointed by the ovpn_socket. 54 + * 55 + * In case of TCP, releasing the socket will cause dropping 56 + * the refcounter for the peer it is linked to, thus allowing the peer 57 + * disappear as well. 58 + * 59 + * This function is expected to be invoked exactly once per peer 60 + * 61 + * NOTE: this function may sleep 62 + */ 63 + void ovpn_socket_release(struct ovpn_peer *peer) 64 + { 65 + struct ovpn_socket *sock; 66 + 67 + might_sleep(); 68 + 69 + sock = rcu_replace_pointer(peer->sock, NULL, true); 70 + /* release may be invoked after socket was detached */ 71 + if (!sock) 72 + return; 73 + 74 + /* sanity check: we should not end up here if the socket 75 + * was already closed 76 + */ 77 + if (!sock->sock->sk) { 78 + DEBUG_NET_WARN_ON_ONCE(1); 79 + return; 80 + } 81 + 82 + /* Drop the reference while holding the sock lock to avoid 83 + * concurrent ovpn_socket_new call to mess up with a partially 84 + * detached socket. 85 + * 86 + * Holding the lock ensures that a socket with refcnt 0 is fully 87 + * detached before it can be picked by a concurrent reader. 88 + */ 89 + lock_sock(sock->sock->sk); 90 + ovpn_socket_put(peer, sock); 91 + release_sock(sock->sock->sk); 92 + 93 + /* align all readers with sk_user_data being NULL */ 94 + synchronize_rcu(); 95 + } 96 + 97 + static bool ovpn_socket_hold(struct ovpn_socket *sock) 98 + { 99 + return kref_get_unless_zero(&sock->refcount); 100 + } 101 + 102 + static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer) 103 + { 104 + if (sock->sock->sk->sk_protocol == IPPROTO_UDP) 105 + return ovpn_udp_socket_attach(sock, peer->ovpn); 106 + 107 + return -EOPNOTSUPP; 108 + } 109 + 110 + /** 111 + * ovpn_socket_new - create a new socket and initialize it 112 + * @sock: the kernel socket to embed 113 + * @peer: the peer reachable via this socket 114 + * 115 + * Return: an openvpn socket on success or a negative error code otherwise 116 + */ 117 + struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer) 118 + { 119 + struct ovpn_socket *ovpn_sock; 120 + int ret; 121 + 122 + lock_sock(sock->sk); 123 + 124 + /* a TCP socket can only be owned by a single peer, therefore there 125 + * can't be any other user 126 + */ 127 + if (sock->sk->sk_protocol == IPPROTO_TCP && sock->sk->sk_user_data) { 128 + ovpn_sock = ERR_PTR(-EBUSY); 129 + goto sock_release; 130 + } 131 + 132 + /* a UDP socket can be shared across multiple peers, but we must make 133 + * sure it is not owned by something else 134 + */ 135 + if (sock->sk->sk_protocol == IPPROTO_UDP) { 136 + u8 type = READ_ONCE(udp_sk(sock->sk)->encap_type); 137 + 138 + /* socket owned by other encapsulation module */ 139 + if (type && type != UDP_ENCAP_OVPNINUDP) { 140 + ovpn_sock = ERR_PTR(-EBUSY); 141 + goto sock_release; 142 + } 143 + 144 + rcu_read_lock(); 145 + ovpn_sock = rcu_dereference_sk_user_data(sock->sk); 146 + if (ovpn_sock) { 147 + /* socket owned by another ovpn instance, we can't use it */ 148 + if (ovpn_sock->ovpn != peer->ovpn) { 149 + ovpn_sock = ERR_PTR(-EBUSY); 150 + rcu_read_unlock(); 151 + goto sock_release; 152 + } 153 + 154 + /* this socket is already owned by this instance, 155 + * therefore we can increase the refcounter and 156 + * use it as expected 157 + */ 158 + if (WARN_ON(!ovpn_socket_hold(ovpn_sock))) { 159 + /* this should never happen because setting 160 + * the refcnt to 0 and detaching the socket 161 + * is expected to be atomic 162 + */ 163 + ovpn_sock = ERR_PTR(-EAGAIN); 164 + rcu_read_unlock(); 165 + goto sock_release; 166 + } 167 + 168 + rcu_read_unlock(); 169 + goto sock_release; 170 + } 171 + rcu_read_unlock(); 172 + } 173 + 174 + /* socket is not owned: attach to this ovpn instance */ 175 + 176 + ovpn_sock = kzalloc(sizeof(*ovpn_sock), GFP_KERNEL); 177 + if (!ovpn_sock) { 178 + ovpn_sock = ERR_PTR(-ENOMEM); 179 + goto sock_release; 180 + } 181 + 182 + ovpn_sock->ovpn = peer->ovpn; 183 + ovpn_sock->sock = sock; 184 + kref_init(&ovpn_sock->refcount); 185 + 186 + ret = ovpn_socket_attach(ovpn_sock, peer); 187 + if (ret < 0) { 188 + kfree(ovpn_sock); 189 + ovpn_sock = ERR_PTR(ret); 190 + goto sock_release; 191 + } 192 + 193 + rcu_assign_sk_user_data(sock->sk, ovpn_sock); 194 + sock_release: 195 + release_sock(sock->sk); 196 + return ovpn_sock; 197 + }
+38
drivers/net/ovpn/socket.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2020-2025 OpenVPN, Inc. 5 + * 6 + * Author: James Yonan <james@openvpn.net> 7 + * Antonio Quartulli <antonio@openvpn.net> 8 + */ 9 + 10 + #ifndef _NET_OVPN_SOCK_H_ 11 + #define _NET_OVPN_SOCK_H_ 12 + 13 + #include <linux/net.h> 14 + #include <linux/kref.h> 15 + #include <net/sock.h> 16 + 17 + struct ovpn_priv; 18 + struct ovpn_peer; 19 + 20 + /** 21 + * struct ovpn_socket - a kernel socket referenced in the ovpn code 22 + * @ovpn: ovpn instance owning this socket (UDP only) 23 + * @sock: the low level sock object 24 + * @refcount: amount of contexts currently referencing this object 25 + * @rcu: member used to schedule RCU destructor callback 26 + */ 27 + struct ovpn_socket { 28 + struct ovpn_priv *ovpn; 29 + struct socket *sock; 30 + struct kref refcount; 31 + struct rcu_head rcu; 32 + }; 33 + 34 + struct ovpn_socket *ovpn_socket_new(struct socket *sock, 35 + struct ovpn_peer *peer); 36 + void ovpn_socket_release(struct ovpn_peer *peer); 37 + 38 + #endif /* _NET_OVPN_SOCK_H_ */
+75
drivers/net/ovpn/udp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2019-2025 OpenVPN, Inc. 5 + * 6 + * Author: Antonio Quartulli <antonio@openvpn.net> 7 + */ 8 + 9 + #include <linux/netdevice.h> 10 + #include <linux/socket.h> 11 + #include <linux/udp.h> 12 + #include <net/udp.h> 13 + 14 + #include "ovpnpriv.h" 15 + #include "main.h" 16 + #include "socket.h" 17 + #include "udp.h" 18 + 19 + /** 20 + * ovpn_udp_socket_attach - set udp-tunnel CBs on socket and link it to ovpn 21 + * @ovpn_sock: socket to configure 22 + * @ovpn: the openvp instance to link 23 + * 24 + * After invoking this function, the sock will be controlled by ovpn so that 25 + * any incoming packet may be processed by ovpn first. 26 + * 27 + * Return: 0 on success or a negative error code otherwise 28 + */ 29 + int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, 30 + struct ovpn_priv *ovpn) 31 + { 32 + struct socket *sock = ovpn_sock->sock; 33 + struct ovpn_socket *old_data; 34 + int ret = 0; 35 + 36 + /* make sure no pre-existing encapsulation handler exists */ 37 + rcu_read_lock(); 38 + old_data = rcu_dereference_sk_user_data(sock->sk); 39 + if (!old_data) { 40 + /* socket is currently unused - we can take it */ 41 + rcu_read_unlock(); 42 + return 0; 43 + } 44 + 45 + /* socket is in use. We need to understand if it's owned by this ovpn 46 + * instance or by something else. 47 + * In the former case, we can increase the refcounter and happily 48 + * use it, because the same UDP socket is expected to be shared among 49 + * different peers. 50 + * 51 + * Unlikely TCP, a single UDP socket can be used to talk to many remote 52 + * hosts and therefore openvpn instantiates one only for all its peers 53 + */ 54 + if ((READ_ONCE(udp_sk(sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) && 55 + old_data->ovpn == ovpn) { 56 + netdev_dbg(ovpn->dev, 57 + "provided socket already owned by this interface\n"); 58 + ret = -EALREADY; 59 + } else { 60 + netdev_dbg(ovpn->dev, 61 + "provided socket already taken by other user\n"); 62 + ret = -EBUSY; 63 + } 64 + rcu_read_unlock(); 65 + 66 + return ret; 67 + } 68 + 69 + /** 70 + * ovpn_udp_socket_detach - clean udp-tunnel status for this socket 71 + * @ovpn_sock: the socket to clean 72 + */ 73 + void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock) 74 + { 75 + }
+19
drivers/net/ovpn/udp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2019-2025 OpenVPN, Inc. 5 + * 6 + * Author: Antonio Quartulli <antonio@openvpn.net> 7 + */ 8 + 9 + #ifndef _NET_OVPN_UDP_H_ 10 + #define _NET_OVPN_UDP_H_ 11 + 12 + struct ovpn_priv; 13 + struct socket; 14 + 15 + int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, 16 + struct ovpn_priv *ovpn); 17 + void ovpn_udp_socket_detach(struct ovpn_socket *ovpn_sock); 18 + 19 + #endif /* _NET_OVPN_UDP_H_ */
+1
include/uapi/linux/udp.h
··· 43 43 #define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */ 44 44 #define UDP_ENCAP_RXRPC 6 45 45 #define TCP_ENCAP_ESPINTCP 7 /* Yikes, this is really xfrm encap types. */ 46 + #define UDP_ENCAP_OVPNINUDP 8 /* OpenVPN traffic */ 46 47 47 48 #endif /* _UAPI_LINUX_UDP_H */