netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Sabrina Dubroca <sd@queasysnail.net>
To: Antonio Quartulli <antonio@openvpn.net>
Cc: netdev@vger.kernel.org, Eric Dumazet <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com>,
	Donald Hunter <donald.hunter@gmail.com>,
	Shuah Khan <shuah@kernel.org>,
	ryazanov.s.a@gmail.com, Andrew Lunn <andrew+netdev@lunn.ch>,
	Simon Horman <horms@kernel.org>,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	Xiao Liang <shaw.leon@gmail.com>,
	willemdebruijn.kernel@gmail.com
Subject: Re: [PATCH net-next v16 07/26] ovpn: introduce the ovpn_socket object
Date: Fri, 3 Jan 2025 18:00:35 +0100	[thread overview]
Message-ID: <Z3gXs65jjYc-g2iw@hog> (raw)
In-Reply-To: <20241219-b4-ovpn-v16-7-3e3001153683@openvpn.net>

Hello Antonio,

2024-12-19, 02:42:01 +0100, Antonio Quartulli wrote:
> +static void ovpn_socket_release_kref(struct kref *kref)
> +	__releases(sock->sock->sk)
> +{
> +	struct ovpn_socket *sock = container_of(kref, struct ovpn_socket,
> +						refcount);
> +

[extend with bits of patch 9]
>	/* UDP sockets are detached in this kref callback because
>	 * we now know for sure that all concurrent users have
>	 * finally gone (refcounter dropped to 0).
>	 *
>	 * Moreover, detachment is performed under lock to prevent
>	 * a concurrent ovpn_socket_new() call with the same socket
>	 * to find the socket still attached but with refcounter 0.

I'm not convinced this really works, because ovpn_socket_new() doesn't
use the same lock. lock_sock and bh_lock_sock both "lock the socket"
in some sense, but they're not mutually exclusive (we talked about
that around the TCP patch).

Are you fundamentally opposed to making attach permanent? ie, once
a UDP or TCP socket is assigned to an ovpn instance, it can't be
detached and reused. I think it would be safer, simpler, and likely
sufficient (I don't know openvpn much, but I don't see a use case for
moving a socket from one ovpn instance to another, or using it without
encap).

Rough idea:
 - ovpn_socket_new is pretty much unchanged (locking still needed to
   protect against another simultaneous attach attempt, EALREADY case
   becomes a bit easier)
 - ovpn_peer_remove doesn't do anything socket-related
 - use ->encap_destroy/ovpn_tcp_close() to clean up sk_user_data
 - no more refcounting on ovpn_socket (since the encap can't be
   removed, the lifetime to ovpn_socket is tied to its socket)

What do you think?

I'm trying to poke holes into this idea now. close() vs attach worries
me a bit.


>	 */
>	if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
>		ovpn_udp_socket_detach(sock->sock);


> +	bh_unlock_sock(sock->sock->sk);
> +	sockfd_put(sock->sock);
> +	kfree_rcu(sock, rcu);
> +}

[...]
> +struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
> +{
> +	struct ovpn_socket *ovpn_sock;
> +	int ret;
> +
> +	lock_sock(sock->sk);
> +
> +	ret = ovpn_socket_attach(sock, peer);
> +	if (ret < 0 && ret != -EALREADY)
> +		goto err_release;
> +
> +	/* if this socket is already owned by this interface, just increase the
> +	 * refcounter and use it as expected.
> +	 *
> +	 * Since UDP sockets can be used to talk to multiple remote endpoints,
> +	 * openvpn normally instantiates only one socket and shares it among all
> +	 * its peers. For this reason, when we find out that a socket is already
> +	 * used for some other peer in *this* instance, we can happily increase
> +	 * its refcounter and use it normally.
> +	 */
> +	if (ret == -EALREADY) {
> +		/* caller is expected to increase the sock refcounter before
> +		 * passing it to this function. For this reason we drop it if
> +		 * not needed, like when this socket is already owned.
> +		 */
> +		ovpn_sock = ovpn_socket_get(sock);
> +		release_sock(sock->sk);
> +		sockfd_put(sock);
> +		return ovpn_sock;
> +	}
> +
> +	ovpn_sock = kzalloc(sizeof(*ovpn_sock), GFP_KERNEL);
> +	if (!ovpn_sock) {
> +		ret = -ENOMEM;
> +		goto err_detach;
> +	}
> +
> +	ovpn_sock->ovpn = peer->ovpn;
> +	ovpn_sock->sock = sock;
> +	kref_init(&ovpn_sock->refcount);
> +
> +	rcu_assign_sk_user_data(sock->sk, ovpn_sock);
> +	release_sock(sock->sk);
> +
> +	return ovpn_sock;
> +err_detach:
> +	if (sock->sk->sk_protocol == IPPROTO_UDP)
> +		ovpn_udp_socket_detach(sock);

This would leave the TCP socket half-attached, and if userspace tries
to attach the same socket again (I don't think the ovpn module would
prevent that since sk_user_data is still unset), both ->sk_data_ready
and tcp.sk_cb.sk_data_ready will be set to ovpn's (same for
sk_write_space with ovpn_tcp_write_space which will recurse into
itself when called).

I think it'd be easier to do the alloc first, then attach. Handling a
failure to attach would be a simple kfree, while handling a failure to
alloc is a detach (or part of a detach) which is not as easy.



> +int ovpn_udp_socket_attach(struct socket *sock, struct ovpn_priv *ovpn)
> +{
> +	struct ovpn_socket *old_data;
> +	int ret = 0;
> +
> +	/* make sure no pre-existing encapsulation handler exists */
> +	rcu_read_lock();
> +	old_data = rcu_dereference_sk_user_data(sock->sk);
> +	if (!old_data) {
> +		/* socket is currently unused - we can take it */
> +		rcu_read_unlock();
> +		return 0;
> +	}
> +
> +	/* socket is in use. We need to understand if it's owned by this ovpn
> +	 * instance or by something else.
> +	 * In the former case, we can increase the refcounter and happily
> +	 * use it, because the same UDP socket is expected to be shared among
> +	 * different peers.
> +	 *
> +	 * Unlikely TCP, a single UDP socket can be used to talk to many remote

nit: s/Unlikely/Unlike/

> +	 * hosts and therefore openvpn instantiates one only for all its peers
> +	 */

-- 
Sabrina

  reply	other threads:[~2025-01-03 17:00 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-19  1:41 [PATCH net-next v16 00/26] Introducing OpenVPN Data Channel Offload Antonio Quartulli
2024-12-19  1:41 ` [PATCH net-next v16 01/26] net: introduce OpenVPN Data Channel Offload (ovpn) Antonio Quartulli
2024-12-19  1:41 ` [PATCH net-next v16 02/26] ovpn: add basic netlink support Antonio Quartulli
2024-12-20 11:00   ` Donald Hunter
2024-12-19  1:41 ` [PATCH net-next v16 03/26] ovpn: add basic interface creation/destruction/management routines Antonio Quartulli
2024-12-20 11:06   ` Donald Hunter
2024-12-19  1:41 ` [PATCH net-next v16 04/26] ovpn: keep carrier always on for MP interfaces Antonio Quartulli
2024-12-19  1:41 ` [PATCH net-next v16 05/26] ovpn: introduce the ovpn_peer object Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 06/26] kref/refcount: implement kref_put_sock() Antonio Quartulli
2024-12-19 17:20   ` Will Deacon
2024-12-31  7:31     ` Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 07/26] ovpn: introduce the ovpn_socket object Antonio Quartulli
2025-01-03 17:00   ` Sabrina Dubroca [this message]
2025-01-05 23:27     ` Antonio Quartulli
2025-01-08 10:55       ` Antonio Quartulli
2025-01-09 11:28       ` Sabrina Dubroca
2024-12-19  1:42 ` [PATCH net-next v16 08/26] ovpn: implement basic TX path (UDP) Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 09/26] ovpn: implement basic RX " Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 10/26] ovpn: implement packet processing Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 11/26] ovpn: store tunnel and transport statistics Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 12/26] ipv6: export inet6_stream_ops via EXPORT_SYMBOL_GPL Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 13/26] ovpn: implement TCP transport Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 14/26] skb: implement skb_send_sock_locked_with_flags() Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 15/26] ovpn: add support for MSG_NOSIGNAL in tcp_sendmsg Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 16/26] ovpn: implement multi-peer support Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 17/26] ovpn: implement peer lookup logic Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 18/26] ovpn: implement keepalive mechanism Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 19/26] ovpn: add support for updating local UDP endpoint Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 20/26] ovpn: add support for peer floating Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 21/26] ovpn: implement peer add/get/dump/delete via netlink Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 22/26] ovpn: implement key add/get/del/swap " Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 23/26] ovpn: kill key and notify userspace in case of IV exhaustion Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 24/26] ovpn: notify userspace when a peer is deleted Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 25/26] ovpn: add basic ethtool support Antonio Quartulli
2024-12-19  1:42 ` [PATCH net-next v16 26/26] testing/selftests: add test tool and scripts for ovpn module Antonio Quartulli
2024-12-20  4:02   ` Jakub Kicinski
2024-12-31  7:42     ` 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=Z3gXs65jjYc-g2iw@hog \
    --to=sd@queasysnail.net \
    --cc=andrew+netdev@lunn.ch \
    --cc=antonio@openvpn.net \
    --cc=donald.hunter@gmail.com \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=ryazanov.s.a@gmail.com \
    --cc=shaw.leon@gmail.com \
    --cc=shuah@kernel.org \
    --cc=willemdebruijn.kernel@gmail.com \
    /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;
as well as URLs for NNTP newsgroup(s).