From patchwork Mon May 6 01:16:21 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 13654789 X-Patchwork-Delegate: kuba@kernel.org Received: from mail-wm1-f48.google.com (mail-wm1-f48.google.com [209.85.128.48]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6510342065 for ; Mon, 6 May 2024 01:15:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714958143; cv=none; b=iBrbCi4o6Bpv0aCABytlmnT74DVfJwXbsrRB9nB1NyaFraj5ZCwFbn+qJ+F5DucNOfNk3hQ8S5sTYa5w0Fz1umeGkv5ZQlcjThNG4HkMemoyGoZhzyyH4MUm+BKZLKXj5/gunuLwtgBYK+Dh9Q4cWW4YUjjXDtmW5wkE2M/wrA8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1714958143; c=relaxed/simple; bh=YEwWQakEfeXj6ULZ9aMLHfQwFbXVQaCYj+5CI9aO7jc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q0cLXFkU1JtCDltqQUpOX1YdGcwqpfHvSQWZs7Lks0Y2GW7kppuGK78vGfCW5HPCHkXvTMwmrEPgxWQ1aR6Qs2dEf9k6oYm/rJo97U3TInFcQQht6NF8lfTgKExLupAesrNx/llPhy0s7qmmfoTC2OebwuomjVMuhRwB1Bq2c/k= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=openvpn.net; spf=pass smtp.mailfrom=openvpn.com; dkim=pass (2048-bit key) header.d=openvpn.net header.i=@openvpn.net header.b=hVkfPcup; arc=none smtp.client-ip=209.85.128.48 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=openvpn.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=openvpn.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=openvpn.net header.i=@openvpn.net header.b="hVkfPcup" Received: by mail-wm1-f48.google.com with SMTP id 5b1f17b1804b1-41c7ac73fddso15096565e9.3 for ; Sun, 05 May 2024 18:15:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1714958139; x=1715562939; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=WKfIhA6bpp3hO0CML8NG/WxVGChrHvCA/VAig1QYNsU=; b=hVkfPcupzHVe4FXWqgbL783dWh7XYpAmw+QqxgvoPNfWVFuFMWBiXXZ2K+RORH9i1P eAlP/6j2yksoGSY+cSGDHxYzhtEcOhMGf19GOLdipJWS+8H7EU7qfnNJoRjy90INwyzW 52yzZjuB39C3OWilINFJ2XoqCRoPNG06mDgSOLoShDZjZlLlxsPpMiSb/X0TjSE/y1IW e2KCk0w1EVEsjF8gRUnvwDDW18bkKM1ZvpEeG5htA/xEZOpylgy0DZczux+n6ktqtdhL sfag9OIwn37QZWa17tGi8IQImDRy97YoAAKS1cGfoXQqQQYAJ9CrvV4hVs1aj8i7Bn6/ t5Sw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1714958139; x=1715562939; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=WKfIhA6bpp3hO0CML8NG/WxVGChrHvCA/VAig1QYNsU=; b=iKDdHPd9ghpMfstRUKnVgzM5f9UsjlwITaYWIWnwkFRlWC4/zZT/XyJ3GNibdnUGcK 3vSXOBxPlbY2hRxWZCNyAGa3IxZ+Cga2+tSZ0QMiXh2JDq8QRSXeafwLSFkd22Z9ulHM ALaFdFTEt1VO1sREZwdRRwFsjVCNofLrvZOPOLABrtMgNsE81/BV58AfUvgh6jWWx3Y+ ZIfyu+BwtdFi65ZK/jheLNBGrHk5+VM6pZY9KrOMyRLIvcc3RYy6VhsXBaqBtQiShgzX ZjMTOR+mk9w1EXsvU5xYm4FT4ho7MggbJjnW01B7X58krn0jpdfsf0r6+OGEnb8lHUJZ V3gw== X-Gm-Message-State: AOJu0Yy1NTZLjMprWg6XMjp5wWyx0O3XCreY09SKdScZ5qXVIyljtsk0 jha6sEwRHhNCH6zTD5W+asgVU2Xb/jC9KU/x5bmiyRVF+Z4A3xx4PVD77MCcE6rKY1o74JHSXs7 k X-Google-Smtp-Source: AGHT+IEZTty3wFg6L9RH/rpRNBddC3cMRWV7fvrvrFH2ZqCbX0pFfyY/mWcxqeyXvz5ZphvGb+gF7A== X-Received: by 2002:a05:600c:1990:b0:41d:803c:b945 with SMTP id t16-20020a05600c199000b0041d803cb945mr8348973wmq.10.1714958139684; Sun, 05 May 2024 18:15:39 -0700 (PDT) Received: from serenity.homelan.mandelbit.com ([2001:67c:2fbc:0:fbf:f0c4:769e:3936]) by smtp.gmail.com with ESMTPSA id n8-20020adffe08000000b0034df2d0bd71sm9363621wrr.12.2024.05.05.18.15.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 05 May 2024 18:15:39 -0700 (PDT) From: Antonio Quartulli To: netdev@vger.kernel.org Cc: Jakub Kicinski , Sergey Ryazanov , Paolo Abeni , Eric Dumazet , Andrew Lunn , Esben Haabendal , Antonio Quartulli Subject: [PATCH net-next v3 08/24] ovpn: introduce the ovpn_socket object Date: Mon, 6 May 2024 03:16:21 +0200 Message-ID: <20240506011637.27272-9-antonio@openvpn.net> X-Mailer: git-send-email 2.43.2 In-Reply-To: <20240506011637.27272-1-antonio@openvpn.net> References: <20240506011637.27272-1-antonio@openvpn.net> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org 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 attathced to them for status tracking purposes. Initially only UDP support is introduced. TCP will come in a later patch. Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/Makefile | 2 + drivers/net/ovpn/socket.c | 105 ++++++++++++++++++++++++++++++++++++++ drivers/net/ovpn/socket.h | 68 ++++++++++++++++++++++++ drivers/net/ovpn/udp.c | 45 ++++++++++++++++ drivers/net/ovpn/udp.h | 27 ++++++++++ 5 files changed, 247 insertions(+) create mode 100644 drivers/net/ovpn/socket.c create mode 100644 drivers/net/ovpn/socket.h create mode 100644 drivers/net/ovpn/udp.c create mode 100644 drivers/net/ovpn/udp.h diff --git a/drivers/net/ovpn/Makefile b/drivers/net/ovpn/Makefile index ce13499b3e17..56bddc9bef83 100644 --- a/drivers/net/ovpn/Makefile +++ b/drivers/net/ovpn/Makefile @@ -13,3 +13,5 @@ ovpn-y += io.o ovpn-y += netlink.o ovpn-y += netlink-gen.o ovpn-y += peer.o +ovpn-y += socket.o +ovpn-y += udp.o diff --git a/drivers/net/ovpn/socket.c b/drivers/net/ovpn/socket.c new file mode 100644 index 000000000000..a4a4d69162f0 --- /dev/null +++ b/drivers/net/ovpn/socket.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: James Yonan + * Antonio Quartulli + */ + +#include +#include + +#include "ovpnstruct.h" +#include "main.h" +#include "io.h" +#include "peer.h" +#include "socket.h" +#include "udp.h" + +/* Finalize release of socket, called after RCU grace period */ +static void ovpn_socket_detach(struct socket *sock) +{ + if (!sock) + return; + + sockfd_put(sock); +} + +void ovpn_socket_release_kref(struct kref *kref) +{ + struct ovpn_socket *sock = container_of(kref, struct ovpn_socket, + refcount); + + ovpn_socket_detach(sock->sock); + kfree_rcu(sock, rcu); +} + +static bool ovpn_socket_hold(struct ovpn_socket *sock) +{ + return kref_get_unless_zero(&sock->refcount); +} + +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 (!ovpn_socket_hold(ovpn_sock)) { + pr_warn("%s: found ovpn_socket with ref = 0\n", __func__); + ovpn_sock = NULL; + } + rcu_read_unlock(); + + return ovpn_sock; +} + +/* Finalize release of socket, called after RCU grace period */ +static int ovpn_socket_attach(struct socket *sock, struct ovpn_peer *peer) +{ + int ret = -EOPNOTSUPP; + + if (!sock || !peer) + return -EINVAL; + + if (sock->sk->sk_protocol == IPPROTO_UDP) + ret = ovpn_udp_socket_attach(sock, peer->ovpn); + + return ret; +} + +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 + */ + 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); + return ovpn_sock; + } + + ovpn_sock = kzalloc(sizeof(*ovpn_sock), GFP_KERNEL); + if (!ovpn_sock) + return ERR_PTR(-ENOMEM); + + ovpn_sock->ovpn = peer->ovpn; + ovpn_sock->sock = sock; + kref_init(&ovpn_sock->refcount); + + rcu_assign_sk_user_data(sock->sk, ovpn_sock); + + return ovpn_sock; +} diff --git a/drivers/net/ovpn/socket.h b/drivers/net/ovpn/socket.h new file mode 100644 index 000000000000..0d23de5a9344 --- /dev/null +++ b/drivers/net/ovpn/socket.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: James Yonan + * Antonio Quartulli + */ + +#ifndef _NET_OVPN_SOCK_H_ +#define _NET_OVPN_SOCK_H_ + +#include +#include +#include +#include + +struct ovpn_struct; +struct ovpn_peer; + +/** + * struct ovpn_socket - a kernel socket referenced in the ovpn code + * @ovpn: ovpn instance owning this socket (UDP only) + * @sock: the low level sock object + * @refcount: amount of contexts currently referencing this object + * @rcu: member used to schedule RCU destructor callback + */ +struct ovpn_socket { + struct ovpn_struct *ovpn; + struct socket *sock; + struct kref refcount; + struct rcu_head rcu; +}; + +/** + * ovpn_from_udp_sock - retrieve ovpn instance object from UDP sock + * @sk: the sock to retrieve the instance from + * + * Return: the ovpn instance that this sock is bound to + */ +struct ovpn_struct *ovpn_from_udp_sock(struct sock *sk); + +/** + * ovpn_socket_release_kref - kref_put callback + * @kref: the kref object + */ +void ovpn_socket_release_kref(struct kref *kref); + +/** + * ovpn_socket_put - decrease reference counter + * @sock: the socket whose reference counter should be decreased + */ +static inline void ovpn_socket_put(struct ovpn_socket *sock) +{ + kref_put(&sock->refcount, ovpn_socket_release_kref); +} + +/** + * ovpn_socket_new - create a new socket and initialize it + * @sock: the kernel socket to embed + * @peer: the peer reachable via this socket + * + * Return: an openvpn socket on success or a negative error code otherwise + */ +struct ovpn_socket *ovpn_socket_new(struct socket *sock, + struct ovpn_peer *peer); + +#endif /* _NET_OVPN_SOCK_H_ */ diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c new file mode 100644 index 000000000000..4b7d96a13df0 --- /dev/null +++ b/drivers/net/ovpn/udp.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +/* OpenVPN data channel offload + * + * Copyright (C) 2019-2024 OpenVPN, Inc. + * + * Author: Antonio Quartulli + */ + +#include +#include + +#include "ovpnstruct.h" +#include "main.h" +#include "socket.h" +#include "udp.h" + +int ovpn_udp_socket_attach(struct socket *sock, struct ovpn_struct *ovpn) +{ + struct ovpn_socket *old_data; + + /* sanity check */ + if (sock->sk->sk_protocol != IPPROTO_UDP) { + netdev_err(ovpn->dev, "%s: expected UDP socket\n", __func__); + return -EINVAL; + } + + /* make sure no pre-existing encapsulation handler exists */ + rcu_read_lock(); + old_data = rcu_dereference_sk_user_data(sock->sk); + rcu_read_unlock(); + if (old_data) { + if (old_data->ovpn == ovpn) { + netdev_dbg(ovpn->dev, + "%s: provided socket already owned by this interface\n", + __func__); + return -EALREADY; + } + + netdev_err(ovpn->dev, "%s: provided socket already taken by other user\n", + __func__); + return -EBUSY; + } + + return 0; +} diff --git a/drivers/net/ovpn/udp.h b/drivers/net/ovpn/udp.h new file mode 100644 index 000000000000..16422a649cb9 --- /dev/null +++ b/drivers/net/ovpn/udp.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2019-2024 OpenVPN, Inc. + * + * Author: Antonio Quartulli + */ + +#ifndef _NET_OVPN_UDP_H_ +#define _NET_OVPN_UDP_H_ + +struct ovpn_struct; +struct socket; + +/** + * ovpn_udp_socket_attach - set udp-tunnel CBs on socket and link it to ovpn + * @sock: socket to configure + * @ovpn: the openvp instance to link + * + * After invoking this function, the sock will be controlled by ovpn so that + * any incoming packet may be processed by ovpn first. + * + * Return: 0 on success or a negative error code otherwise + */ +int ovpn_udp_socket_attach(struct socket *sock, struct ovpn_struct *ovpn); + +#endif /* _NET_OVPN_UDP_H_ */