From: Sabrina Dubroca <sd@queasysnail.net>
To: Antonio Quartulli <antonio@openvpn.net>
Cc: netdev@vger.kernel.org, Jakub Kicinski <kuba@kernel.org>,
Sergey Ryazanov <ryazanov.s.a@gmail.com>,
Paolo Abeni <pabeni@redhat.com>,
Eric Dumazet <edumazet@google.com>, Andrew Lunn <andrew@lunn.ch>,
Esben Haabendal <esben@geanix.com>
Subject: Re: [PATCH net-next v3 07/24] ovpn: introduce the ovpn_peer object
Date: Wed, 8 May 2024 18:06:55 +0200 [thread overview]
Message-ID: <ZjujHw6eglLEIbxA@hog> (raw)
In-Reply-To: <20240506011637.27272-8-antonio@openvpn.net>
2024-05-06, 03:16:20 +0200, Antonio Quartulli wrote:
> 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
^
typo: "introduced"
> 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.
> diff --git a/drivers/net/ovpn/bind.c b/drivers/net/ovpn/bind.c
> new file mode 100644
> index 000000000000..c1f842c06e32
> --- /dev/null
> +++ b/drivers/net/ovpn/bind.c
> +static void ovpn_bind_release_rcu(struct rcu_head *head)
> +{
> + struct ovpn_bind *bind = container_of(head, struct ovpn_bind, rcu);
> +
> + kfree(bind);
> +}
> +
> +void ovpn_bind_reset(struct ovpn_peer *peer, struct ovpn_bind *new)
> +{
> + struct ovpn_bind *old;
> +
> + spin_lock_bh(&peer->lock);
> + old = rcu_replace_pointer(peer->bind, new, true);
> + spin_unlock_bh(&peer->lock);
> +
> + if (old)
> + call_rcu(&old->rcu, ovpn_bind_release_rcu);
Isn't that just kfree_rcu? (note kfree_rcu doesn't need the NULL check)
> +}
> diff --git a/drivers/net/ovpn/bind.h b/drivers/net/ovpn/bind.h
> new file mode 100644
> index 000000000000..61433550a961
> --- /dev/null
> +++ b/drivers/net/ovpn/bind.h
[...]
> +static inline bool ovpn_bind_skb_src_match(const struct ovpn_bind *bind,
> + struct sk_buff *skb)
nit: I think skb can also be const here
> diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
> index 338e99dfe886..a420bb45f25f 100644
> --- a/drivers/net/ovpn/io.c
> +++ b/drivers/net/ovpn/io.c
> @@ -13,6 +13,7 @@
> #include "io.h"
> #include "ovpnstruct.h"
> #include "netlink.h"
> +#include "peer.h"
>
> int ovpn_struct_init(struct net_device *dev)
> {
> @@ -25,6 +26,13 @@ int ovpn_struct_init(struct net_device *dev)
> if (err < 0)
> return err;
>
> + spin_lock_init(&ovpn->lock);
> +
> + ovpn->events_wq = alloc_workqueue("ovpn-events-wq-%s", WQ_MEM_RECLAIM,
> + 0, dev->name);
I'm not convinced this will get freed consistently if
register_netdevice fails early (before ndo_init). After talking to
Paolo, it seems this should be moved into a new ->ndo_init instead.
> + if (!ovpn->events_wq)
> + return -ENOMEM;
> +
> dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
> if (!dev->tstats)
> return -ENOMEM;
> diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
> index cc8a97a1a189..dba35ecb236b 100644
> --- a/drivers/net/ovpn/main.c
> +++ b/drivers/net/ovpn/main.c
> @@ -37,6 +39,9 @@ static void ovpn_struct_free(struct net_device *net)
> rtnl_unlock();
>
> free_percpu(net->tstats);
> + flush_workqueue(ovpn->events_wq);
> + destroy_workqueue(ovpn->events_wq);
Is the flush needed? I'm not an expert on workqueues, but from a quick
look at destroy_workqueue it calls drain_workqueue, which would take
care of flushing the queue?
> + rcu_barrier();
> }
>
[...]
> diff --git a/drivers/net/ovpn/ovpnstruct.h b/drivers/net/ovpn/ovpnstruct.h
> index ee05b8a2c61d..b79d4f0474b0 100644
> --- a/drivers/net/ovpn/ovpnstruct.h
> +++ b/drivers/net/ovpn/ovpnstruct.h
> @@ -17,12 +17,19 @@
> * @dev: the actual netdev representing the tunnel
> * @registered: whether dev is still registered with netdev or not
> * @mode: device operation mode (i.e. p2p, mp, ..)
> + * @lock: protect this object
> + * @event_wq: used to schedule generic events that may sleep and that need to be
> + * performed outside of softirq context
> + * @peer: in P2P mode, this is the only remote peer
> * @dev_list: entry for the module wide device list
> */
> struct ovpn_struct {
> struct net_device *dev;
> bool registered;
> enum ovpn_mode mode;
> + spinlock_t lock; /* protect writing to the ovpn_struct object */
nit: the comment isn't really needed since you have kdoc saying the same thing
> + struct workqueue_struct *events_wq;
> + struct ovpn_peer __rcu *peer;
> struct list_head dev_list;
> };
>
> diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c
> new file mode 100644
> index 000000000000..2948b7320d47
> --- /dev/null
> +++ b/drivers/net/ovpn/peer.c
[...]
> +/**
> + * ovpn_peer_free - release private members and free peer object
> + * @peer: the peer to free
> + */
> +static void ovpn_peer_free(struct ovpn_peer *peer)
> +{
> + ovpn_bind_reset(peer, NULL);
> +
> + WARN_ON(!__ptr_ring_empty(&peer->tx_ring));
Could you pass a destructor to ptr_ring_cleanup instead of all these WARNs?
> + ptr_ring_cleanup(&peer->tx_ring, NULL);
> + WARN_ON(!__ptr_ring_empty(&peer->rx_ring));
> + ptr_ring_cleanup(&peer->rx_ring, NULL);
> + WARN_ON(!__ptr_ring_empty(&peer->netif_rx_ring));
> + ptr_ring_cleanup(&peer->netif_rx_ring, NULL);
> +
> + dst_cache_destroy(&peer->dst_cache);
> +
> + dev_put(peer->ovpn->dev);
> +
> + kfree(peer);
> +}
[...]
> +void ovpn_peer_release(struct ovpn_peer *peer)
> +{
> + call_rcu(&peer->rcu, ovpn_peer_release_rcu);
> +}
> +
> +/**
> + * ovpn_peer_delete_work - work scheduled to release peer in process context
> + * @work: the work object
> + */
> +static void ovpn_peer_delete_work(struct work_struct *work)
> +{
> + struct ovpn_peer *peer = container_of(work, struct ovpn_peer,
> + delete_work);
> + ovpn_peer_release(peer);
Does call_rcu really need to run in process context?
> +}
[...]
> +/**
> + * ovpn_peer_transp_match - check if sockaddr and peer binding match
> + * @peer: the peer to get the binding from
> + * @ss: the sockaddr to match
> + *
> + * Return: true if sockaddr and binding match or false otherwise
> + */
> +static bool ovpn_peer_transp_match(struct ovpn_peer *peer,
> + struct sockaddr_storage *ss)
> +{
[...]
> + case AF_INET6:
> + sa6 = (struct sockaddr_in6 *)ss;
> + if (memcmp(&sa6->sin6_addr, &bind->sa.in6.sin6_addr,
> + sizeof(struct in6_addr)))
ipv6_addr_equal?
> + return false;
> + if (sa6->sin6_port != bind->sa.in6.sin6_port)
> + return false;
> + break;
[...]
> +struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_struct *ovpn, u32 peer_id)
> +{
> + struct ovpn_peer *peer = NULL;
> +
> + if (ovpn->mode == OVPN_MODE_P2P)
> + peer = ovpn_peer_get_by_id_p2p(ovpn, peer_id);
> +
> + return peer;
> +}
> +
> +/**
> + * ovpn_peer_add_p2p - add per to related tables in a P2P instance
^
typo: peer?
[...]
> +/**
> + * ovpn_peer_del_p2p - delete peer from related tables in a P2P instance
> + * @peer: the peer to delete
> + * @reason: reason why the peer was deleted (sent to userspace)
> + *
> + * Return: 0 on success or a negative error code otherwise
> + */
> +static int ovpn_peer_del_p2p(struct ovpn_peer *peer,
> + enum ovpn_del_peer_reason reason)
> +{
> + struct ovpn_peer *tmp;
> + int ret = -ENOENT;
> +
> + spin_lock_bh(&peer->ovpn->lock);
> + tmp = rcu_dereference(peer->ovpn->peer);
> + if (tmp != peer)
> + goto unlock;
How do we recover if all those objects got out of sync? Are we stuck
with a broken peer?
And if this happens during interface deletion, aren't we leaking the
peer memory here?
> + ovpn_peer_put(tmp);
> + tmp->delete_reason = reason;
> + RCU_INIT_POINTER(peer->ovpn->peer, NULL);
> + ret = 0;
> +
> +unlock:
> + spin_unlock_bh(&peer->ovpn->lock);
> +
> + return ret;
> +}
[...]
> diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h
> new file mode 100644
> index 000000000000..659df320525c
> --- /dev/null
> +++ b/drivers/net/ovpn/peer.h
[...]
> +/**
> + * struct ovpn_peer - the main remote peer object
> + * @ovpn: main openvpn instance this peer belongs to
> + * @id: unique identifier
> + * @vpn_addrs.ipv4: IPv4 assigned to peer on the tunnel
> + * @vpn_addrs.ipv6: IPv6 assigned to peer on the tunnel
> + * @tx_ring: queue of outgoing poackets to this peer
> + * @rx_ring: queue of incoming packets from this peer
> + * @netif_rx_ring: queue of packets to be sent to the netdevice via NAPI
> + * @dst_cache: cache for dst_entry used to send to peer
> + * @bind: remote peer binding
> + * @halt: true if ovpn_peer_mark_delete was called
> + * @delete_reason: why peer was deleted (i.e. timeout, transport error, ..)
> + * @lock: protects binding to peer (bind)
> + * @refcount: reference counter
> + * @rcu: used to free peer in an RCU safe way
> + * @delete_work: deferred cleanup work, used to notify userspace
> + */
> +struct ovpn_peer {
> + struct ovpn_struct *ovpn;
> + u32 id;
> + struct {
> + struct in_addr ipv4;
> + struct in6_addr ipv6;
> + } vpn_addrs;
> + struct ptr_ring tx_ring;
> + struct ptr_ring rx_ring;
> + struct ptr_ring netif_rx_ring;
> + struct dst_cache dst_cache;
> + struct ovpn_bind __rcu *bind;
> + bool halt;
> + enum ovpn_del_peer_reason delete_reason;
> + spinlock_t lock; /* protects bind */
nit: the comment isn't really needed, it's redundant with kdoc.
> + struct kref refcount;
> + struct rcu_head rcu;
> + struct work_struct delete_work;
> +};
--
Sabrina
next prev parent reply other threads:[~2024-05-08 16:07 UTC|newest]
Thread overview: 117+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-05-06 1:16 [PATCH net-next v3 00/24] Introducing OpenVPN Data Channel Offload Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 01/24] netlink: add NLA_POLICY_MAX_LEN macro Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 02/24] net: introduce OpenVPN Data Channel Offload (ovpn) Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 03/24] ovpn: add basic netlink support Antonio Quartulli
2024-05-08 0:10 ` Jakub Kicinski
2024-05-08 7:42 ` Antonio Quartulli
2024-05-08 14:42 ` Sabrina Dubroca
2024-05-08 14:51 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 04/24] ovpn: add basic interface creation/destruction/management routines Antonio Quartulli
2024-05-08 0:18 ` Jakub Kicinski
2024-05-08 7:53 ` Antonio Quartulli
2024-05-08 14:52 ` Sabrina Dubroca
2024-05-09 1:06 ` Jakub Kicinski
2024-05-09 8:25 ` Antonio Quartulli
2024-05-09 10:09 ` Sabrina Dubroca
2024-05-09 10:35 ` Antonio Quartulli
2024-05-09 12:16 ` Sabrina Dubroca
2024-05-09 13:25 ` Antonio Quartulli
2024-05-09 13:52 ` Sabrina Dubroca
2024-05-06 1:16 ` [PATCH net-next v3 05/24] ovpn: implement interface creation/destruction via netlink Antonio Quartulli
2024-05-08 0:21 ` Jakub Kicinski
2024-05-08 9:49 ` Antonio Quartulli
2024-05-09 1:09 ` Jakub Kicinski
2024-05-09 8:30 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 06/24] ovpn: keep carrier always on Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 07/24] ovpn: introduce the ovpn_peer object Antonio Quartulli
2024-05-08 16:06 ` Sabrina Dubroca [this message]
2024-05-08 20:31 ` Antonio Quartulli
2024-05-09 13:04 ` Sabrina Dubroca
2024-05-09 13:24 ` Andrew Lunn
2024-05-10 18:57 ` Antonio Quartulli
2024-05-11 0:28 ` Jakub Kicinski
2024-05-09 13:44 ` Antonio Quartulli
2024-05-09 13:55 ` Andrew Lunn
2024-05-09 14:17 ` Sabrina Dubroca
2024-05-09 14:36 ` Antonio Quartulli
2024-05-09 14:53 ` Antonio Quartulli
2024-05-10 10:30 ` Sabrina Dubroca
2024-05-10 12:34 ` Antonio Quartulli
2024-05-10 14:11 ` Sabrina Dubroca
2024-05-13 10:09 ` Simon Horman
2024-05-13 10:53 ` Antonio Quartulli
2024-05-13 15:04 ` Simon Horman
2024-05-06 1:16 ` [PATCH net-next v3 08/24] ovpn: introduce the ovpn_socket object Antonio Quartulli
2024-05-08 17:10 ` Sabrina Dubroca
2024-05-08 20:38 ` Antonio Quartulli
2024-05-09 13:32 ` Sabrina Dubroca
2024-05-09 13:46 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 09/24] ovpn: implement basic TX path (UDP) Antonio Quartulli
2024-05-10 13:01 ` Sabrina Dubroca
2024-05-10 13:39 ` Antonio Quartulli
2024-05-12 21:35 ` Sabrina Dubroca
2024-05-13 7:37 ` Antonio Quartulli
2024-05-13 9:36 ` Sabrina Dubroca
2024-05-13 9:47 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 10/24] ovpn: implement basic RX " Antonio Quartulli
2024-05-10 13:45 ` Sabrina Dubroca
2024-05-10 14:41 ` Antonio Quartulli
2024-07-18 10:46 ` Sabrina Dubroca
2024-07-18 13:06 ` Antonio Quartulli
2024-07-18 13:11 ` Sabrina Dubroca
2024-07-18 13:27 ` Antonio Quartulli
2024-07-18 13:40 ` Sabrina Dubroca
2024-07-18 14:15 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 11/24] ovpn: implement packet processing Antonio Quartulli
2024-05-12 8:46 ` Sabrina Dubroca
2024-05-13 7:14 ` Antonio Quartulli
2024-05-13 9:24 ` Sabrina Dubroca
2024-05-13 9:31 ` Antonio Quartulli
2024-05-22 14:08 ` Antonio Quartulli
2024-05-22 14:28 ` Andrew Lunn
2024-05-06 1:16 ` [PATCH net-next v3 12/24] ovpn: store tunnel and transport statistics Antonio Quartulli
2024-05-12 8:47 ` Sabrina Dubroca
2024-05-13 7:25 ` Antonio Quartulli
2024-05-13 9:19 ` Sabrina Dubroca
2024-05-13 9:33 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 13/24] ovpn: implement TCP transport Antonio Quartulli
2024-05-13 13:37 ` Antonio Quartulli
2024-05-13 15:34 ` Jakub Kicinski
2024-05-13 14:50 ` Sabrina Dubroca
2024-05-13 22:20 ` Antonio Quartulli
2024-05-14 8:58 ` Sabrina Dubroca
2024-05-14 22:11 ` Antonio Quartulli
2024-05-15 10:19 ` Sabrina Dubroca
2024-05-15 12:54 ` Antonio Quartulli
2024-05-15 14:55 ` Sabrina Dubroca
2024-05-15 19:44 ` Antonio Quartulli
2024-05-15 20:35 ` Sabrina Dubroca
2024-05-15 20:39 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 14/24] ovpn: implement multi-peer support Antonio Quartulli
2024-05-28 14:44 ` Sabrina Dubroca
2024-05-28 19:41 ` Antonio Quartulli
2024-05-29 15:16 ` Sabrina Dubroca
2024-05-29 20:15 ` Antonio Quartulli
2024-05-29 20:45 ` Sabrina Dubroca
2024-05-06 1:16 ` [PATCH net-next v3 15/24] ovpn: implement peer lookup logic Antonio Quartulli
2024-05-28 16:42 ` Sabrina Dubroca
2024-05-28 20:09 ` Antonio Quartulli
2024-05-29 16:42 ` Sabrina Dubroca
2024-05-29 20:19 ` Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 16/24] ovpn: implement keepalive mechanism Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 17/24] ovpn: add support for updating local UDP endpoint Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 18/24] ovpn: add support for peer floating Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 19/24] ovpn: implement peer add/dump/delete via netlink Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 20/24] ovpn: implement key add/del/swap " Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 21/24] ovpn: kill key and notify userspace in case of IV exhaustion Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 22/24] ovpn: notify userspace when a peer is deleted Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 23/24] ovpn: add basic ethtool support Antonio Quartulli
2024-05-06 1:16 ` [PATCH net-next v3 24/24] testing/selftest: add test tool and scripts for ovpn module Antonio Quartulli
2024-05-07 23:55 ` Jakub Kicinski
2024-05-08 9:51 ` Antonio Quartulli
2024-05-09 0:50 ` Jakub Kicinski
2024-05-09 8:40 ` Antonio Quartulli
2024-05-07 23:48 ` [PATCH net-next v3 00/24] Introducing OpenVPN Data Channel Offload Jakub Kicinski
2024-05-08 9:56 ` Antonio Quartulli
2024-05-09 0:53 ` Jakub Kicinski
2024-05-09 8:41 ` 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=ZjujHw6eglLEIbxA@hog \
--to=sd@queasysnail.net \
--cc=andrew@lunn.ch \
--cc=antonio@openvpn.net \
--cc=edumazet@google.com \
--cc=esben@geanix.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ryazanov.s.a@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.