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

ovpn: introduce the ovpn_peer object

An ovpn_peer object holds the whole status of a remote peer
(regardless whether it is a server or a client).

This includes status for crypto, tx/rx buffers, napi, etc.

Only support for one peer is introduced (P2P mode).
Multi peer support is introduced with a later patch.

Along with the ovpn_peer, also the ovpn_bind object is introcued
as the two are strictly related.
An ovpn_bind object wraps a sockaddr representing the local
coordinates being used to talk to a specific peer.

Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
Link: https://patch.msgid.link/20250415-b4-ovpn-v26-5-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
80747cae 8327a3ba

+670 -1
+1
drivers/net/Kconfig
··· 119 119 tristate "OpenVPN data channel offload" 120 120 depends on NET && INET 121 121 depends on IPV6 || !IPV6 122 + select DST_CACHE 122 123 help 123 124 This module enhances the performance of the OpenVPN userspace software 124 125 by offloading the data channel processing to kernelspace.
+2
drivers/net/ovpn/Makefile
··· 7 7 # Author: Antonio Quartulli <antonio@openvpn.net> 8 8 9 9 obj-$(CONFIG_OVPN) := ovpn.o 10 + ovpn-y += bind.o 10 11 ovpn-y += main.o 11 12 ovpn-y += io.o 12 13 ovpn-y += netlink.o 13 14 ovpn-y += netlink-gen.o 15 + ovpn-y += peer.o
+58
drivers/net/ovpn/bind.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2012-2025 OpenVPN, Inc. 5 + * 6 + * Author: James Yonan <james@openvpn.net> 7 + * Antonio Quartulli <antonio@openvpn.net> 8 + */ 9 + 10 + #include <linux/netdevice.h> 11 + #include <linux/socket.h> 12 + 13 + #include "ovpnpriv.h" 14 + #include "bind.h" 15 + #include "peer.h" 16 + 17 + /** 18 + * ovpn_bind_from_sockaddr - retrieve binding matching sockaddr 19 + * @ss: the sockaddr to match 20 + * 21 + * Return: the bind matching the passed sockaddr if found, NULL otherwise 22 + */ 23 + struct ovpn_bind *ovpn_bind_from_sockaddr(const struct sockaddr_storage *ss) 24 + { 25 + struct ovpn_bind *bind; 26 + size_t sa_len; 27 + 28 + if (ss->ss_family == AF_INET) 29 + sa_len = sizeof(struct sockaddr_in); 30 + else if (ss->ss_family == AF_INET6) 31 + sa_len = sizeof(struct sockaddr_in6); 32 + else 33 + return ERR_PTR(-EAFNOSUPPORT); 34 + 35 + bind = kzalloc(sizeof(*bind), GFP_ATOMIC); 36 + if (unlikely(!bind)) 37 + return ERR_PTR(-ENOMEM); 38 + 39 + memcpy(&bind->remote, ss, sa_len); 40 + 41 + return bind; 42 + } 43 + 44 + /** 45 + * ovpn_bind_reset - assign new binding to peer 46 + * @peer: the peer whose binding has to be replaced 47 + * @new: the new bind to assign 48 + */ 49 + void ovpn_bind_reset(struct ovpn_peer *peer, struct ovpn_bind *new) 50 + { 51 + struct ovpn_bind *old; 52 + 53 + spin_lock_bh(&peer->lock); 54 + old = rcu_replace_pointer(peer->bind, new, true); 55 + spin_unlock_bh(&peer->lock); 56 + 57 + kfree_rcu(old, rcu); 58 + }
+101
drivers/net/ovpn/bind.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2012-2025 OpenVPN, Inc. 5 + * 6 + * Author: James Yonan <james@openvpn.net> 7 + * Antonio Quartulli <antonio@openvpn.net> 8 + */ 9 + 10 + #ifndef _NET_OVPN_OVPNBIND_H_ 11 + #define _NET_OVPN_OVPNBIND_H_ 12 + 13 + #include <net/ip.h> 14 + #include <linux/in.h> 15 + #include <linux/in6.h> 16 + #include <linux/rcupdate.h> 17 + #include <linux/skbuff.h> 18 + #include <linux/spinlock.h> 19 + 20 + struct ovpn_peer; 21 + 22 + /** 23 + * union ovpn_sockaddr - basic transport layer address 24 + * @in4: IPv4 address 25 + * @in6: IPv6 address 26 + */ 27 + union ovpn_sockaddr { 28 + struct sockaddr_in in4; 29 + struct sockaddr_in6 in6; 30 + }; 31 + 32 + /** 33 + * struct ovpn_bind - remote peer binding 34 + * @remote: the remote peer sockaddress 35 + * @local: local endpoint used to talk to the peer 36 + * @local.ipv4: local IPv4 used to talk to the peer 37 + * @local.ipv6: local IPv6 used to talk to the peer 38 + * @rcu: used to schedule RCU cleanup job 39 + */ 40 + struct ovpn_bind { 41 + union ovpn_sockaddr remote; /* remote sockaddr */ 42 + 43 + union { 44 + struct in_addr ipv4; 45 + struct in6_addr ipv6; 46 + } local; 47 + 48 + struct rcu_head rcu; 49 + }; 50 + 51 + /** 52 + * ovpn_bind_skb_src_match - match packet source with binding 53 + * @bind: the binding to match 54 + * @skb: the packet to match 55 + * 56 + * Return: true if the packet source matches the remote peer sockaddr 57 + * in the binding 58 + */ 59 + static inline bool ovpn_bind_skb_src_match(const struct ovpn_bind *bind, 60 + const struct sk_buff *skb) 61 + { 62 + const union ovpn_sockaddr *remote; 63 + 64 + if (unlikely(!bind)) 65 + return false; 66 + 67 + remote = &bind->remote; 68 + 69 + switch (skb->protocol) { 70 + case htons(ETH_P_IP): 71 + if (unlikely(remote->in4.sin_family != AF_INET)) 72 + return false; 73 + 74 + if (unlikely(remote->in4.sin_addr.s_addr != ip_hdr(skb)->saddr)) 75 + return false; 76 + 77 + if (unlikely(remote->in4.sin_port != udp_hdr(skb)->source)) 78 + return false; 79 + break; 80 + case htons(ETH_P_IPV6): 81 + if (unlikely(remote->in6.sin6_family != AF_INET6)) 82 + return false; 83 + 84 + if (unlikely(!ipv6_addr_equal(&remote->in6.sin6_addr, 85 + &ipv6_hdr(skb)->saddr))) 86 + return false; 87 + 88 + if (unlikely(remote->in6.sin6_port != udp_hdr(skb)->source)) 89 + return false; 90 + break; 91 + default: 92 + return false; 93 + } 94 + 95 + return true; 96 + } 97 + 98 + struct ovpn_bind *ovpn_bind_from_sockaddr(const struct sockaddr_storage *sa); 99 + void ovpn_bind_reset(struct ovpn_peer *peer, struct ovpn_bind *bind); 100 + 101 + #endif /* _NET_OVPN_OVPNBIND_H_ */
+13 -1
drivers/net/ovpn/main.c
··· 19 19 #include "main.h" 20 20 #include "netlink.h" 21 21 #include "io.h" 22 + #include "peer.h" 22 23 #include "proto.h" 23 24 24 25 static const struct net_device_ops ovpn_netdev_ops = { ··· 93 92 94 93 ovpn->dev = dev; 95 94 ovpn->mode = mode; 95 + spin_lock_init(&ovpn->lock); 96 96 97 97 /* Set carrier explicitly after registration, this way state is 98 98 * clearly defined. ··· 109 107 netif_carrier_off(dev); 110 108 111 109 return register_netdevice(dev); 110 + } 111 + 112 + static void ovpn_dellink(struct net_device *dev, struct list_head *head) 113 + { 114 + struct ovpn_priv *ovpn = netdev_priv(dev); 115 + 116 + if (ovpn->mode == OVPN_MODE_P2P) 117 + ovpn_peer_release_p2p(ovpn, OVPN_DEL_PEER_REASON_TEARDOWN); 118 + 119 + unregister_netdevice_queue(dev, head); 112 120 } 113 121 114 122 static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev) ··· 139 127 .policy = ovpn_policy, 140 128 .maxtype = IFLA_OVPN_MAX, 141 129 .newlink = ovpn_newlink, 142 - .dellink = unregister_netdevice_queue, 130 + .dellink = ovpn_dellink, 143 131 .fill_info = ovpn_fill_info, 144 132 }; 145 133
+4
drivers/net/ovpn/ovpnpriv.h
··· 17 17 * struct ovpn_priv - per ovpn interface state 18 18 * @dev: the actual netdev representing the tunnel 19 19 * @mode: device operation mode (i.e. p2p, mp, ..) 20 + * @lock: protect this object 21 + * @peer: in P2P mode, this is the only remote peer 20 22 */ 21 23 struct ovpn_priv { 22 24 struct net_device *dev; 23 25 enum ovpn_mode mode; 26 + spinlock_t lock; /* protect writing to the ovpn_priv object */ 27 + struct ovpn_peer __rcu *peer; 24 28 }; 25 29 26 30 #endif /* _NET_OVPN_OVPNSTRUCT_H_ */
+411
drivers/net/ovpn/peer.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/skbuff.h> 11 + #include <linux/list.h> 12 + 13 + #include "ovpnpriv.h" 14 + #include "bind.h" 15 + #include "io.h" 16 + #include "main.h" 17 + #include "netlink.h" 18 + #include "peer.h" 19 + 20 + static void unlock_ovpn(struct ovpn_priv *ovpn, 21 + struct llist_head *release_list) 22 + __releases(&ovpn->lock) 23 + { 24 + struct ovpn_peer *peer; 25 + 26 + spin_unlock_bh(&ovpn->lock); 27 + 28 + llist_for_each_entry(peer, release_list->first, release_entry) 29 + ovpn_peer_put(peer); 30 + } 31 + 32 + /** 33 + * ovpn_peer_new - allocate and initialize a new peer object 34 + * @ovpn: the openvpn instance inside which the peer should be created 35 + * @id: the ID assigned to this peer 36 + * 37 + * Return: a pointer to the new peer on success or an error code otherwise 38 + */ 39 + struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id) 40 + { 41 + struct ovpn_peer *peer; 42 + int ret; 43 + 44 + /* alloc and init peer object */ 45 + peer = kzalloc(sizeof(*peer), GFP_KERNEL); 46 + if (!peer) 47 + return ERR_PTR(-ENOMEM); 48 + 49 + peer->id = id; 50 + peer->ovpn = ovpn; 51 + 52 + peer->vpn_addrs.ipv4.s_addr = htonl(INADDR_ANY); 53 + peer->vpn_addrs.ipv6 = in6addr_any; 54 + 55 + RCU_INIT_POINTER(peer->bind, NULL); 56 + spin_lock_init(&peer->lock); 57 + kref_init(&peer->refcount); 58 + 59 + ret = dst_cache_init(&peer->dst_cache, GFP_KERNEL); 60 + if (ret < 0) { 61 + netdev_err(ovpn->dev, 62 + "cannot initialize dst cache for peer %u\n", 63 + peer->id); 64 + kfree(peer); 65 + return ERR_PTR(ret); 66 + } 67 + 68 + netdev_hold(ovpn->dev, &peer->dev_tracker, GFP_KERNEL); 69 + 70 + return peer; 71 + } 72 + 73 + /** 74 + * ovpn_peer_release_rcu - RCU callback performing last peer release steps 75 + * @head: RCU member of the ovpn_peer 76 + */ 77 + static void ovpn_peer_release_rcu(struct rcu_head *head) 78 + { 79 + struct ovpn_peer *peer = container_of(head, struct ovpn_peer, rcu); 80 + 81 + /* this call will immediately free the dst_cache, therefore we 82 + * perform it in the RCU callback, when all contexts are done 83 + */ 84 + dst_cache_destroy(&peer->dst_cache); 85 + kfree(peer); 86 + } 87 + 88 + /** 89 + * ovpn_peer_release - release peer private members 90 + * @peer: the peer to release 91 + */ 92 + static void ovpn_peer_release(struct ovpn_peer *peer) 93 + { 94 + ovpn_bind_reset(peer, NULL); 95 + call_rcu(&peer->rcu, ovpn_peer_release_rcu); 96 + netdev_put(peer->ovpn->dev, &peer->dev_tracker); 97 + } 98 + 99 + /** 100 + * ovpn_peer_release_kref - callback for kref_put 101 + * @kref: the kref object belonging to the peer 102 + */ 103 + void ovpn_peer_release_kref(struct kref *kref) 104 + { 105 + struct ovpn_peer *peer = container_of(kref, struct ovpn_peer, refcount); 106 + 107 + ovpn_peer_release(peer); 108 + } 109 + 110 + /** 111 + * ovpn_peer_skb_to_sockaddr - fill sockaddr with skb source address 112 + * @skb: the packet to extract data from 113 + * @ss: the sockaddr to fill 114 + * 115 + * Return: sockaddr length on success or -1 otherwise 116 + */ 117 + static int ovpn_peer_skb_to_sockaddr(struct sk_buff *skb, 118 + struct sockaddr_storage *ss) 119 + { 120 + struct sockaddr_in6 *sa6; 121 + struct sockaddr_in *sa4; 122 + 123 + switch (skb->protocol) { 124 + case htons(ETH_P_IP): 125 + sa4 = (struct sockaddr_in *)ss; 126 + sa4->sin_family = AF_INET; 127 + sa4->sin_addr.s_addr = ip_hdr(skb)->saddr; 128 + sa4->sin_port = udp_hdr(skb)->source; 129 + return sizeof(*sa4); 130 + case htons(ETH_P_IPV6): 131 + sa6 = (struct sockaddr_in6 *)ss; 132 + sa6->sin6_family = AF_INET6; 133 + sa6->sin6_addr = ipv6_hdr(skb)->saddr; 134 + sa6->sin6_port = udp_hdr(skb)->source; 135 + return sizeof(*sa6); 136 + } 137 + 138 + return -1; 139 + } 140 + 141 + /** 142 + * ovpn_peer_transp_match - check if sockaddr and peer binding match 143 + * @peer: the peer to get the binding from 144 + * @ss: the sockaddr to match 145 + * 146 + * Return: true if sockaddr and binding match or false otherwise 147 + */ 148 + static bool ovpn_peer_transp_match(const struct ovpn_peer *peer, 149 + const struct sockaddr_storage *ss) 150 + { 151 + struct ovpn_bind *bind = rcu_dereference(peer->bind); 152 + struct sockaddr_in6 *sa6; 153 + struct sockaddr_in *sa4; 154 + 155 + if (unlikely(!bind)) 156 + return false; 157 + 158 + if (ss->ss_family != bind->remote.in4.sin_family) 159 + return false; 160 + 161 + switch (ss->ss_family) { 162 + case AF_INET: 163 + sa4 = (struct sockaddr_in *)ss; 164 + if (sa4->sin_addr.s_addr != bind->remote.in4.sin_addr.s_addr) 165 + return false; 166 + if (sa4->sin_port != bind->remote.in4.sin_port) 167 + return false; 168 + break; 169 + case AF_INET6: 170 + sa6 = (struct sockaddr_in6 *)ss; 171 + if (!ipv6_addr_equal(&sa6->sin6_addr, 172 + &bind->remote.in6.sin6_addr)) 173 + return false; 174 + if (sa6->sin6_port != bind->remote.in6.sin6_port) 175 + return false; 176 + break; 177 + default: 178 + return false; 179 + } 180 + 181 + return true; 182 + } 183 + 184 + /** 185 + * ovpn_peer_get_by_transp_addr_p2p - get peer by transport address in a P2P 186 + * instance 187 + * @ovpn: the openvpn instance to search 188 + * @ss: the transport socket address 189 + * 190 + * Return: the peer if found or NULL otherwise 191 + */ 192 + static struct ovpn_peer * 193 + ovpn_peer_get_by_transp_addr_p2p(struct ovpn_priv *ovpn, 194 + struct sockaddr_storage *ss) 195 + { 196 + struct ovpn_peer *tmp, *peer = NULL; 197 + 198 + rcu_read_lock(); 199 + tmp = rcu_dereference(ovpn->peer); 200 + if (likely(tmp && ovpn_peer_transp_match(tmp, ss) && 201 + ovpn_peer_hold(tmp))) 202 + peer = tmp; 203 + rcu_read_unlock(); 204 + 205 + return peer; 206 + } 207 + 208 + /** 209 + * ovpn_peer_get_by_transp_addr - retrieve peer by transport address 210 + * @ovpn: the openvpn instance to search 211 + * @skb: the skb to retrieve the source transport address from 212 + * 213 + * Return: a pointer to the peer if found or NULL otherwise 214 + */ 215 + struct ovpn_peer *ovpn_peer_get_by_transp_addr(struct ovpn_priv *ovpn, 216 + struct sk_buff *skb) 217 + { 218 + struct ovpn_peer *peer = NULL; 219 + struct sockaddr_storage ss = { 0 }; 220 + 221 + if (unlikely(!ovpn_peer_skb_to_sockaddr(skb, &ss))) 222 + return NULL; 223 + 224 + if (ovpn->mode == OVPN_MODE_P2P) 225 + peer = ovpn_peer_get_by_transp_addr_p2p(ovpn, &ss); 226 + 227 + return peer; 228 + } 229 + 230 + /** 231 + * ovpn_peer_get_by_id_p2p - get peer by ID in a P2P instance 232 + * @ovpn: the openvpn instance to search 233 + * @peer_id: the ID of the peer to find 234 + * 235 + * Return: the peer if found or NULL otherwise 236 + */ 237 + static struct ovpn_peer *ovpn_peer_get_by_id_p2p(struct ovpn_priv *ovpn, 238 + u32 peer_id) 239 + { 240 + struct ovpn_peer *tmp, *peer = NULL; 241 + 242 + rcu_read_lock(); 243 + tmp = rcu_dereference(ovpn->peer); 244 + if (likely(tmp && tmp->id == peer_id && ovpn_peer_hold(tmp))) 245 + peer = tmp; 246 + rcu_read_unlock(); 247 + 248 + return peer; 249 + } 250 + 251 + /** 252 + * ovpn_peer_get_by_id - retrieve peer by ID 253 + * @ovpn: the openvpn instance to search 254 + * @peer_id: the unique peer identifier to match 255 + * 256 + * Return: a pointer to the peer if found or NULL otherwise 257 + */ 258 + struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id) 259 + { 260 + struct ovpn_peer *peer = NULL; 261 + 262 + if (ovpn->mode == OVPN_MODE_P2P) 263 + peer = ovpn_peer_get_by_id_p2p(ovpn, peer_id); 264 + 265 + return peer; 266 + } 267 + 268 + static void ovpn_peer_remove(struct ovpn_peer *peer, 269 + enum ovpn_del_peer_reason reason, 270 + struct llist_head *release_list) 271 + { 272 + switch (peer->ovpn->mode) { 273 + case OVPN_MODE_P2P: 274 + /* prevent double remove */ 275 + if (peer != rcu_access_pointer(peer->ovpn->peer)) 276 + return; 277 + 278 + RCU_INIT_POINTER(peer->ovpn->peer, NULL); 279 + /* in P2P mode the carrier is switched off when the peer is 280 + * deleted so that third party protocols can react accordingly 281 + */ 282 + netif_carrier_off(peer->ovpn->dev); 283 + break; 284 + default: 285 + return; 286 + } 287 + 288 + peer->delete_reason = reason; 289 + 290 + /* append to provided list for later socket release and ref drop */ 291 + llist_add(&peer->release_entry, release_list); 292 + } 293 + 294 + /** 295 + * ovpn_peer_add_p2p - add peer to related tables in a P2P instance 296 + * @ovpn: the instance to add the peer to 297 + * @peer: the peer to add 298 + * 299 + * Return: 0 on success or a negative error code otherwise 300 + */ 301 + static int ovpn_peer_add_p2p(struct ovpn_priv *ovpn, struct ovpn_peer *peer) 302 + { 303 + LLIST_HEAD(release_list); 304 + struct ovpn_peer *tmp; 305 + 306 + spin_lock_bh(&ovpn->lock); 307 + /* in p2p mode it is possible to have a single peer only, therefore the 308 + * old one is released and substituted by the new one 309 + */ 310 + tmp = rcu_dereference_protected(ovpn->peer, 311 + lockdep_is_held(&ovpn->lock)); 312 + if (tmp) 313 + ovpn_peer_remove(tmp, OVPN_DEL_PEER_REASON_TEARDOWN, 314 + &release_list); 315 + 316 + rcu_assign_pointer(ovpn->peer, peer); 317 + /* in P2P mode the carrier is switched on when the peer is added */ 318 + netif_carrier_on(ovpn->dev); 319 + unlock_ovpn(ovpn, &release_list); 320 + 321 + return 0; 322 + } 323 + 324 + /** 325 + * ovpn_peer_add - add peer to the related tables 326 + * @ovpn: the openvpn instance the peer belongs to 327 + * @peer: the peer object to add 328 + * 329 + * Assume refcounter was increased by caller 330 + * 331 + * Return: 0 on success or a negative error code otherwise 332 + */ 333 + int ovpn_peer_add(struct ovpn_priv *ovpn, struct ovpn_peer *peer) 334 + { 335 + switch (ovpn->mode) { 336 + case OVPN_MODE_P2P: 337 + return ovpn_peer_add_p2p(ovpn, peer); 338 + default: 339 + return -EOPNOTSUPP; 340 + } 341 + } 342 + 343 + /** 344 + * ovpn_peer_del_p2p - delete peer from related tables in a P2P instance 345 + * @peer: the peer to delete 346 + * @reason: reason why the peer was deleted (sent to userspace) 347 + * @release_list: list where delete peer should be appended 348 + * 349 + * Return: 0 on success or a negative error code otherwise 350 + */ 351 + static int ovpn_peer_del_p2p(struct ovpn_peer *peer, 352 + enum ovpn_del_peer_reason reason, 353 + struct llist_head *release_list) 354 + { 355 + struct ovpn_peer *tmp; 356 + 357 + lockdep_assert_held(&peer->ovpn->lock); 358 + 359 + tmp = rcu_dereference_protected(peer->ovpn->peer, 360 + lockdep_is_held(&peer->ovpn->lock)); 361 + if (tmp != peer) 362 + return -ENOENT; 363 + 364 + ovpn_peer_remove(peer, reason, release_list); 365 + 366 + return 0; 367 + } 368 + 369 + /** 370 + * ovpn_peer_del - delete peer from related tables 371 + * @peer: the peer object to delete 372 + * @reason: reason for deleting peer (will be sent to userspace) 373 + * 374 + * Return: 0 on success or a negative error code otherwise 375 + */ 376 + int ovpn_peer_del(struct ovpn_peer *peer, enum ovpn_del_peer_reason reason) 377 + { 378 + LLIST_HEAD(release_list); 379 + int ret = -EOPNOTSUPP; 380 + 381 + spin_lock_bh(&peer->ovpn->lock); 382 + switch (peer->ovpn->mode) { 383 + case OVPN_MODE_P2P: 384 + ret = ovpn_peer_del_p2p(peer, reason, &release_list); 385 + break; 386 + default: 387 + break; 388 + } 389 + unlock_ovpn(peer->ovpn, &release_list); 390 + 391 + return ret; 392 + } 393 + 394 + /** 395 + * ovpn_peer_release_p2p - release peer upon P2P device teardown 396 + * @ovpn: the instance being torn down 397 + * @reason: the reason for releasing the peer 398 + */ 399 + void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, 400 + enum ovpn_del_peer_reason reason) 401 + { 402 + LLIST_HEAD(release_list); 403 + struct ovpn_peer *peer; 404 + 405 + spin_lock_bh(&ovpn->lock); 406 + peer = rcu_dereference_protected(ovpn->peer, 407 + lockdep_is_held(&ovpn->lock)); 408 + if (peer) 409 + ovpn_peer_remove(peer, reason, &release_list); 410 + unlock_ovpn(ovpn, &release_list); 411 + }
+80
drivers/net/ovpn/peer.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_OVPNPEER_H_ 11 + #define _NET_OVPN_OVPNPEER_H_ 12 + 13 + #include <net/dst_cache.h> 14 + 15 + /** 16 + * struct ovpn_peer - the main remote peer object 17 + * @ovpn: main openvpn instance this peer belongs to 18 + * @dev_tracker: reference tracker for associated dev 19 + * @id: unique identifier 20 + * @vpn_addrs: IP addresses assigned over the tunnel 21 + * @vpn_addrs.ipv4: IPv4 assigned to peer on the tunnel 22 + * @vpn_addrs.ipv6: IPv6 assigned to peer on the tunnel 23 + * @dst_cache: cache for dst_entry used to send to peer 24 + * @bind: remote peer binding 25 + * @delete_reason: why peer was deleted (i.e. timeout, transport error, ..) 26 + * @lock: protects binding to peer (bind) 27 + * @refcount: reference counter 28 + * @rcu: used to free peer in an RCU safe way 29 + * @release_entry: entry for the socket release list 30 + */ 31 + struct ovpn_peer { 32 + struct ovpn_priv *ovpn; 33 + netdevice_tracker dev_tracker; 34 + u32 id; 35 + struct { 36 + struct in_addr ipv4; 37 + struct in6_addr ipv6; 38 + } vpn_addrs; 39 + struct dst_cache dst_cache; 40 + struct ovpn_bind __rcu *bind; 41 + enum ovpn_del_peer_reason delete_reason; 42 + spinlock_t lock; /* protects bind */ 43 + struct kref refcount; 44 + struct rcu_head rcu; 45 + struct llist_node release_entry; 46 + }; 47 + 48 + /** 49 + * ovpn_peer_hold - increase reference counter 50 + * @peer: the peer whose counter should be increased 51 + * 52 + * Return: true if the counter was increased or false if it was zero already 53 + */ 54 + static inline bool ovpn_peer_hold(struct ovpn_peer *peer) 55 + { 56 + return kref_get_unless_zero(&peer->refcount); 57 + } 58 + 59 + void ovpn_peer_release_kref(struct kref *kref); 60 + 61 + /** 62 + * ovpn_peer_put - decrease reference counter 63 + * @peer: the peer whose counter should be decreased 64 + */ 65 + static inline void ovpn_peer_put(struct ovpn_peer *peer) 66 + { 67 + kref_put(&peer->refcount, ovpn_peer_release_kref); 68 + } 69 + 70 + struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id); 71 + int ovpn_peer_add(struct ovpn_priv *ovpn, struct ovpn_peer *peer); 72 + int ovpn_peer_del(struct ovpn_peer *peer, enum ovpn_del_peer_reason reason); 73 + void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, 74 + enum ovpn_del_peer_reason reason); 75 + 76 + struct ovpn_peer *ovpn_peer_get_by_transp_addr(struct ovpn_priv *ovpn, 77 + struct sk_buff *skb); 78 + struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id); 79 + 80 + #endif /* _NET_OVPN_OVPNPEER_H_ */