From: Antonio Quartulli <antonio@openvpn.net>
To: Sabrina Dubroca <sd@queasysnail.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 v15 06/22] ovpn: introduce the ovpn_socket object
Date: Thu, 12 Dec 2024 23:46:11 +0100 [thread overview]
Message-ID: <fa19f3a8-c273-4d2c-a10e-e9bda2375365@openvpn.net> (raw)
In-Reply-To: <Z1sNEgQLMzZua3mS@hog>
On 12/12/2024 17:19, Sabrina Dubroca wrote:
> 2024-12-11, 22:15:10 +0100, Antonio Quartulli wrote:
>> +static struct ovpn_socket *ovpn_socket_get(struct socket *sock)
>> +{
>> + struct ovpn_socket *ovpn_sock;
>> +
>> + rcu_read_lock();
>> + ovpn_sock = rcu_dereference_sk_user_data(sock->sk);
>> + if (WARN_ON(!ovpn_socket_hold(ovpn_sock)))
>
> Could we hit this situation when we're removing the last peer (so
> detaching its socket) just as we're adding a new one? ovpn_socket_new
> finds the socket already attached and goes through the EALREADY path,
> but the refcount has already dropped to 0?
>
hm good point.
> Then we'd also return NULL from ovpn_socket_new [1], which I don't
> think is handled well by the caller (at least the netdev_dbg call at
> the end of ovpn_nl_peer_modify, maybe other spots too).
>
> (I guess it's not an issue you would see with the existing userspace
> if it's single-threaded)
The TCP patch 11/22 will convert the socket release routine to a
scheduled worker.
This means we can have the following flow:
1) userspace deletes a peer -> peer drops its reference to the ovpn_socket
2) ovpn_socket refcnt may hit 0 -> cleanup/detach work is scheduled, but
not yet executed
3) userspace adds a new peer -> attach returns -EALREADY but refcnt is 0
So not so impossible, even with a single-threaded userspace software.
>
> [...]
>> +struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
>> +{
>> + struct ovpn_socket *ovpn_sock;
>> + int ret;
>> +
>> + ret = ovpn_socket_attach(sock, peer);
>> + if (ret < 0 && ret != -EALREADY)
>> + return ERR_PTR(ret);
>> +
>> + /* 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);
>> + sockfd_put(sock);
>
> [1] so we would need to add
>
> if (!ovpn_sock)
> return -EAGAIN;
I am not sure returning -EAGAIN is the right move at this point.
We don't know when the scheduled worker will execute, so we don't know
when to try again.
Maybe we should call cancel_sync_work(&ovpn_sock->work) inside
ovpn_socket_get()?
So the latter will return NULL only when it is sure that the socket has
been detached.
At that point we can skip the following return and continue along the
"new socket" path.
What do you think?
However, this makes we wonder: what happens if we have two racing
PEER_NEW with the same non-yet-attached UDP socket?
Maybe we should lock the socket in ovpn_udp_socket_attach() when
checking its user-data and setting it (in order to make the test-and-set
atomic)?
I am specifically talking about this in udp.c:
345 /* make sure no pre-existing encapsulation handler exists */
346 rcu_read_lock();
347 old_data = rcu_dereference_sk_user_data(sock->sk);
348 if (!old_data) {
349 /* socket is currently unused - we can take it */
350 rcu_read_unlock();
351 setup_udp_tunnel_sock(sock_net(sock->sk), sock, &cfg);
352 return 0;
353 }
We will end up returning 0 in both contexts and thus allocate two
ovpn_sockets instead of re-using the first one we allocated.
Does it make sense?
>
>> + return ovpn_sock;
>> + }
>> +
>
> [...]
>> +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
>
> (since I'm commenting on this patch:)
>
> s/Unlikely/Unlike/
ACK
>
> [I have some more nits/typos here and there but I worry the
> maintainers will get "slightly" annoyed if I make you repost 22
> patches once again :) -- if that's all I find in the next few days,
> everyone might be happier if I stash them and we get them fixed after
> merging?]
If we have to rework this socket attaching part, it may be worth
throwing in those typ0 fixes too :)
Thanks a lot.
Regards,
--
Antonio Quartulli
OpenVPN Inc.
next prev parent reply other threads:[~2024-12-12 22:45 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-12-11 21:15 [PATCH net-next v15 00/22] Introducing OpenVPN Data Channel Offload Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 01/22] net: introduce OpenVPN Data Channel Offload (ovpn) Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 02/22] ovpn: add basic netlink support Antonio Quartulli
2024-12-13 16:45 ` Donald Hunter
2024-12-13 17:00 ` Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 03/22] ovpn: add basic interface creation/destruction/management routines Antonio Quartulli
2024-12-13 12:32 ` Donald Hunter
2024-12-13 12:37 ` Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 04/22] ovpn: keep carrier always on for MP interfaces Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 05/22] ovpn: introduce the ovpn_peer object Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 06/22] ovpn: introduce the ovpn_socket object Antonio Quartulli
2024-12-12 16:19 ` Sabrina Dubroca
2024-12-12 22:46 ` Antonio Quartulli [this message]
2024-12-16 11:09 ` Sabrina Dubroca
2024-12-16 11:50 ` Antonio Quartulli
2024-12-17 0:40 ` Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 07/22] ovpn: implement basic TX path (UDP) Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 08/22] ovpn: implement basic RX " Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 09/22] ovpn: implement packet processing Antonio Quartulli
2024-12-16 14:58 ` Sabrina Dubroca
2024-12-11 21:15 ` [PATCH net-next v15 10/22] ovpn: store tunnel and transport statistics Antonio Quartulli
2024-12-16 14:20 ` Sabrina Dubroca
2024-12-11 21:15 ` [PATCH net-next v15 11/22] ovpn: implement TCP transport Antonio Quartulli
2024-12-16 13:59 ` Sabrina Dubroca
2024-12-16 14:09 ` Antonio Quartulli
2024-12-16 14:19 ` Sabrina Dubroca
2024-12-11 21:15 ` [PATCH net-next v15 12/22] ovpn: implement multi-peer support Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 13/22] ovpn: implement peer lookup logic Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 14/22] ovpn: implement keepalive mechanism Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 15/22] ovpn: add support for updating local UDP endpoint Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 16/22] ovpn: add support for peer floating Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 17/22] ovpn: implement peer add/get/dump/delete via netlink Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 18/22] ovpn: implement key add/get/del/swap " Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 19/22] ovpn: kill key and notify userspace in case of IV exhaustion Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 20/22] ovpn: notify userspace when a peer is deleted Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 21/22] ovpn: add basic ethtool support Antonio Quartulli
2024-12-11 21:15 ` [PATCH net-next v15 22/22] testing/selftests: add test tool and scripts for ovpn module 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=fa19f3a8-c273-4d2c-a10e-e9bda2375365@openvpn.net \
--to=antonio@openvpn.net \
--cc=andrew+netdev@lunn.ch \
--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=sd@queasysnail.net \
--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