From patchwork Mon Dec 2 15:07:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846798 Received: from mail-wr1-f41.google.com (mail-wr1-f41.google.com [209.85.221.41]) (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 C8C08207A35 for ; Mon, 2 Dec 2024 15:07:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152082; cv=none; b=qO11UFlll5P7KYpnqxDzxG66kyoy6wMGkWjnqdTo6dSCWBtTlCOkYm3v98iWy7RVmgjHKhvn4Deykm2/tcRFQdGfO8XxTbyJoBbvRfgH2USx9X6QxasmDecxzWGFbf7vLDoYbeqrOcMXqG81HMWNL3Bm0mPGZJV6VSE9JPFpUuU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152082; c=relaxed/simple; bh=35rR6BxWiaqQLrkOwzSeMjod5LvXDiiOd1tUaFDw33w=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=R5Lt4U//0hZIZ8wZvyHiI8q2YnNV4zvBSpRV2nUZmwujxO/lSE6aIkPV8Ru+oy5JZMh8o9Q5p4g/CUPClMfMThi32hl95qs5KxhfzKJZNuO9n1KkqLM9ZUM3VQ0J5dSO9xRbxs6eH5ie+4Wa2f4zOyCwUD0gw9wZCe6c6Qub3m8= 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=YFgp1pUL; arc=none smtp.client-ip=209.85.221.41 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="YFgp1pUL" Received: by mail-wr1-f41.google.com with SMTP id ffacd0b85a97d-385f07cd1a4so1129919f8f.1 for ; Mon, 02 Dec 2024 07:07:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152078; x=1733756878; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=8yqSGRd2x0XCn8o0DHYhNZRjWsTUVn1h5+n6wvi8VHk=; b=YFgp1pULHfb+kHgBzzl323cJT7m0DgmHS5PfjxjpwyFhm99OuYuw9Mr7aEDWqxdqv7 5lmI0P84nA3UtbL/WdO3pOMOBk0tuRMCfT12Jy3J5U4NIJJHTXAfU+AuXdkgL5/TqeLf uDs+thmlhsSIs/UWEKxbALHG79Of5Kw8i4RspfBW7oHG5cGE4W9F0lv4hKX1VzClJjMr LXaCGNXj7J5KHuTfirpDasICk9DsRlo1p9ve2W7Ugdl7wGqnmtEIuMWLUWWkxW2DQgCB 8hX2ZJZEY0bvmtCE7OwZ/1wJP7U03I1yu+86BkzSqt+BHa49yVmOr6Hs+hUO9qrcDYNB UBMg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152078; x=1733756878; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=8yqSGRd2x0XCn8o0DHYhNZRjWsTUVn1h5+n6wvi8VHk=; b=Cl0w5ipt3hypv0KlNVLbSrKE7Q299Mgt0IVxFcbWsYp3IyFOVsnxCNGn7lx12xNJNR cSOM25jv1sxPbR0hJN9RE62rp/6hZYw5Xe2rG0olGLs4Rer41i9FV4vpN64UywDTCsme PTnXISErMGowBB/TgsotfaXlO+LZ/Y8xFvLzpKn3ucPuZNg56WQStYqogprRv7rvO4lK RAByQOSDapNxfC5BJGO7COEk9IoMMFRvAIOcNSS1ICod/fiJKWSSL0ivKxMSWorUngil 9Jz7+tRlrQsj249TiA1P/dijgogfSeFPMelF9K/lFPcLMzP6mQRhRQfiTHdcuH16C49d Nbmw== X-Forwarded-Encrypted: i=1; AJvYcCXKOO/7dFNqJG1E0iCXf5WAzhfl6NKocJs2xZxp8BpI8F8FVmnELtTa/l87A0iU5MU6IwAJtfttXu08qA1zyA8=@vger.kernel.org X-Gm-Message-State: AOJu0Ywz8WUN6mLp5etOBBZ2YUqhs4DYzC332gLdQAGCNZzorQnxn5Ob WViBexnCIaxfOnAnMpwJQnHJFlMZNqTZzEhWLKFvHG4M5AEsKA5Bzi3I6hrDL94= X-Gm-Gg: ASbGncsaLCaKQ1tlCNEylRLnnedHN5XSUK3KwIc0lQfF9PmHYZkrasJkpG1dwOpjyJ+ NuZJ5tvUsV2GqTEYPuwUEp2RKMUby85jHlAtYXjQSaqpYiJJTzwlKMgkkJGa4pmns8SXsHLwK3F fMIJJ+5xYQj0j3/j+bbZcBO4GkRvQoTnPW+u6KZ8Zb/7IoRVdTQTIxUeAV6BNKTu5GTRvFxjs4W kHYQrvQnUlO/vrchgzOqCxTa+0NHb1+OZXsobHl3ZE4iSxfGamQoirbjwXw X-Google-Smtp-Source: AGHT+IHUaelEZRv7UT1DxxazJuvWx1zT34fis/cLBVo3URYYdbxkrayKRD+RKLEixz26+qDPLopsnA== X-Received: by 2002:a05:6000:154e:b0:385:f44a:a68 with SMTP id ffacd0b85a97d-385f44a108amr3620524f8f.35.1733152070415; Mon, 02 Dec 2024 07:07:50 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.07.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:07:49 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:20 +0100 Subject: [PATCH net-next v12 02/22] ovpn: add basic netlink support Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-2-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=31935; i=antonio@openvpn.net; h=from:subject:message-id; bh=35rR6BxWiaqQLrkOwzSeMjod5LvXDiiOd1tUaFDw33w=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1lDjG7MEaPgzSQvJviuxxs8x4xKTdfFp23Z Wn1IAw9AmCJATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZQAKCRALcOU6oDjV h7CBCACY/4jhNeeNY1T2AsHcjAZ/PRlmO4mG7yy6Wggr/M9WHhkoGiRjYxcDbJrbuohuuJDb97v ChXLE1ppk23JYOcMEqwstBMWKFfHf9MmGNE3CvPhlHkv8kugJ6w08A2T5cCFdwB4BmKcGsZigYi ZrZZ3LW6cgE+/rY4b2gnmQbZVBxAY10I9uZh1UU+8hw6kpk3YQyMQJr1+HXJBGIitx/teycjIqB KcaMIglH8pyHZtuSfIcl9mZ5O17Fcq+gNiVrjMqAkaZhJvhuDe186M2lSb4fBfEbk3fo+GMyfLB 7bGaK/LdT5c/5HJD+jBz52G/Fe9rwDYnfXozkGXzlp75aXyP X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C This commit introduces basic netlink support with family registration/unregistration functionalities and stub pre/post-doit. More importantly it introduces the YAML uAPI description along with its auto-generated files: - include/uapi/linux/ovpn.h - drivers/net/ovpn/netlink-gen.c - drivers/net/ovpn/netlink-gen.h Cc: donald.hunter@gmail.com Signed-off-by: Antonio Quartulli --- Documentation/netlink/specs/ovpn.yaml | 368 ++++++++++++++++++++++++++++++++++ MAINTAINERS | 2 + drivers/net/ovpn/Makefile | 2 + drivers/net/ovpn/main.c | 17 +- drivers/net/ovpn/main.h | 14 ++ drivers/net/ovpn/netlink-gen.c | 212 ++++++++++++++++++++ drivers/net/ovpn/netlink-gen.h | 41 ++++ drivers/net/ovpn/netlink.c | 156 ++++++++++++++ drivers/net/ovpn/netlink.h | 15 ++ drivers/net/ovpn/ovpnstruct.h | 25 +++ include/uapi/linux/ovpn.h | 110 ++++++++++ 11 files changed, 961 insertions(+), 1 deletion(-) diff --git a/Documentation/netlink/specs/ovpn.yaml b/Documentation/netlink/specs/ovpn.yaml new file mode 100644 index 0000000000000000000000000000000000000000..96fe3c913f4fb77ecdfcb1de64983eceb81a2d02 --- /dev/null +++ b/Documentation/netlink/specs/ovpn.yaml @@ -0,0 +1,368 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +# +# Author: Antonio Quartulli +# +# Copyright (c) 2024, OpenVPN Inc. +# + +name: ovpn + +protocol: genetlink + +doc: Netlink protocol to control OpenVPN network devices + +definitions: + - + type: const + name: nonce-tail-size + value: 8 + - + type: enum + name: cipher-alg + entries: [ none, aes-gcm, chacha20-poly1305 ] + - + type: enum + name: del-peer-reason + entries: + - teardown + - admindown + - userspace + - expired + - transport-error + - transport-disconnect + - + type: enum + name: key-slot + entries: [ primary, secondary ] + +attribute-sets: + - + name: peer + attributes: + - + name: id + type: u32 + doc: | + The unique ID of the peer in the device context. To be used to identify + peers during operations for a specific device + checks: + max: 0xFFFFFF + - + name: remote-ipv4 + type: u32 + doc: The remote IPv4 address of the peer + byte-order: big-endian + display-hint: ipv4 + - + name: remote-ipv6 + type: binary + doc: The remote IPv6 address of the peer + display-hint: ipv6 + checks: + exact-len: 16 + - + name: remote-ipv6-scope-id + type: u32 + doc: The scope id of the remote IPv6 address of the peer (RFC2553) + - + name: remote-port + type: u16 + doc: The remote port of the peer + byte-order: big-endian + checks: + min: 1 + - + name: socket + type: u32 + doc: The socket to be used to communicate with the peer + - + name: vpn-ipv4 + type: u32 + doc: The IPv4 address assigned to the peer by the server + byte-order: big-endian + display-hint: ipv4 + - + name: vpn-ipv6 + type: binary + doc: The IPv6 address assigned to the peer by the server + display-hint: ipv6 + checks: + exact-len: 16 + - + name: local-ipv4 + type: u32 + doc: The local IPv4 to be used to send packets to the peer (UDP only) + byte-order: big-endian + display-hint: ipv4 + - + name: local-ipv6 + type: binary + doc: The local IPv6 to be used to send packets to the peer (UDP only) + display-hint: ipv6 + checks: + exact-len: 16 + - + name: local-port + type: u16 + doc: The local port to be used to send packets to the peer (UDP only) + byte-order: big-endian + checks: + min: 1 + - + name: keepalive-interval + type: u32 + doc: | + The number of seconds after which a keep alive message is sent to the + peer + - + name: keepalive-timeout + type: u32 + doc: | + The number of seconds from the last activity after which the peer is + assumed dead + - + name: del-reason + type: u32 + doc: The reason why a peer was deleted + enum: del-peer-reason + - + name: vpn-rx-bytes + type: uint + doc: Number of bytes received over the tunnel + - + name: vpn-tx-bytes + type: uint + doc: Number of bytes transmitted over the tunnel + - + name: vpn-rx-packets + type: uint + doc: Number of packets received over the tunnel + - + name: vpn-tx-packets + type: uint + doc: Number of packets transmitted over the tunnel + - + name: link-rx-bytes + type: uint + doc: Number of bytes received at the transport level + - + name: link-tx-bytes + type: uint + doc: Number of bytes transmitted at the transport level + - + name: link-rx-packets + type: u32 + doc: Number of packets received at the transport level + - + name: link-tx-packets + type: u32 + doc: Number of packets transmitted at the transport level + - + name: keyconf + attributes: + - + name: peer-id + type: u32 + doc: | + The unique ID of the peer in the device context. To be used to + identify peers during key operations + checks: + max: 0xFFFFFF + - + name: slot + type: u32 + doc: The slot where the key should be stored + enum: key-slot + - + name: key-id + doc: | + The unique ID of the key in the peer context. Used to fetch the + correct key upon decryption + type: u32 + checks: + max: 7 + - + name: cipher-alg + type: u32 + doc: The cipher to be used when communicating with the peer + enum: cipher-alg + - + name: encrypt-dir + type: nest + doc: Key material for encrypt direction + nested-attributes: keydir + - + name: decrypt-dir + type: nest + doc: Key material for decrypt direction + nested-attributes: keydir + - + name: keydir + attributes: + - + name: cipher-key + type: binary + doc: The actual key to be used by the cipher + checks: + max-len: 256 + - + name: nonce-tail + type: binary + doc: | + Random nonce to be concatenated to the packet ID, in order to + obtain the actual cipher IV + checks: + exact-len: nonce-tail-size + - + name: ovpn + attributes: + - + name: ifindex + type: u32 + doc: Index of the ovpn interface to operate on + - + name: ifname + type: string + doc: Name of the ovpn interface + - + name: peer + type: nest + doc: | + The peer object containing the attributed of interest for the specific + operation + nested-attributes: peer + - + name: keyconf + type: nest + doc: Peer specific cipher configuration + nested-attributes: keyconf + +operations: + list: + - + name: peer-new + attribute-set: ovpn + flags: [ admin-perm ] + doc: Add a remote peer + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - peer + - + name: peer-set + attribute-set: ovpn + flags: [ admin-perm ] + doc: modify a remote peer + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - peer + - + name: peer-get + attribute-set: ovpn + flags: [ admin-perm ] + doc: Retrieve data about existing remote peers (or a specific one) + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - peer + reply: + attributes: + - peer + dump: + request: + attributes: + - ifindex + reply: + attributes: + - peer + - + name: peer-del + attribute-set: ovpn + flags: [ admin-perm ] + doc: Delete existing remote peer + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - peer + - + name: peer-del-ntf + doc: Notification about a peer being deleted + notify: peer-get + mcgrp: peers + + - + name: key-new + attribute-set: ovpn + flags: [ admin-perm ] + doc: Add a cipher key for a specific peer + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - keyconf + - + name: key-get + attribute-set: ovpn + flags: [ admin-perm ] + doc: Retrieve non-sensitive data about peer key and cipher + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - keyconf + reply: + attributes: + - keyconf + - + name: key-swap + attribute-set: ovpn + flags: [ admin-perm ] + doc: Swap primary and secondary session keys for a specific peer + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - keyconf + - + name: key-swap-ntf + notify: key-get + doc: | + Notification about key having exhausted its IV space and requiring + renegotiation + mcgrp: peers + - + name: key-del + attribute-set: ovpn + flags: [ admin-perm ] + doc: Delete cipher key for a specific peer + do: + pre: ovpn-nl-pre-doit + post: ovpn-nl-post-doit + request: + attributes: + - ifindex + - keyconf + +mcast-groups: + list: + - + name: peers diff --git a/MAINTAINERS b/MAINTAINERS index 6de1767f7cc80a571e0ab6e9f4dfe5650eb704d4..848538c52a01d18e0031ab34dca24c1151de4b8b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17478,7 +17478,9 @@ L: openvpn-devel@lists.sourceforge.net (subscribers-only) L: netdev@vger.kernel.org S: Supported T: git https://github.com/OpenVPN/linux-kernel-ovpn.git +F: Documentation/netlink/specs/ovpn.yaml F: drivers/net/ovpn/ +F: include/uapi/linux/ovpn.h OPENVSWITCH M: Pravin B Shelar diff --git a/drivers/net/ovpn/Makefile b/drivers/net/ovpn/Makefile index ae19cf445b29367da680e226f06a341c42c892c2..19305a39e57eede2dc391aa0423702c5321649a6 100644 --- a/drivers/net/ovpn/Makefile +++ b/drivers/net/ovpn/Makefile @@ -8,3 +8,5 @@ obj-$(CONFIG_OVPN) := ovpn.o ovpn-y += main.o +ovpn-y += netlink.o +ovpn-y += netlink-gen.o diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 72c56e73771cdece22e50645b29c79962f06caf3..3475dab4b40f3edd882e05dbdf8badd03d7c78a3 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -7,9 +7,15 @@ * James Yonan */ +#include #include #include #include +#include + +#include "ovpnstruct.h" +#include "main.h" +#include "netlink.h" static const struct net_device_ops ovpn_netdev_ops = { }; @@ -20,7 +26,7 @@ static const struct net_device_ops ovpn_netdev_ops = { * * Return: whether the netdevice is of type 'ovpn' */ -static bool ovpn_dev_is_valid(const struct net_device *dev) +bool ovpn_dev_is_valid(const struct net_device *dev) { return dev->netdev_ops == &ovpn_netdev_ops; } @@ -89,8 +95,16 @@ static int __init ovpn_init(void) goto unreg_netdev; } + err = ovpn_nl_register(); + if (err) { + pr_err("ovpn: can't register netlink family: %d\n", err); + goto unreg_rtnl; + } + return 0; +unreg_rtnl: + rtnl_link_unregister(&ovpn_link_ops); unreg_netdev: unregister_netdevice_notifier(&ovpn_netdev_notifier); return err; @@ -98,6 +112,7 @@ static int __init ovpn_init(void) static __exit void ovpn_cleanup(void) { + ovpn_nl_unregister(); rtnl_link_unregister(&ovpn_link_ops); unregister_netdevice_notifier(&ovpn_netdev_notifier); diff --git a/drivers/net/ovpn/main.h b/drivers/net/ovpn/main.h new file mode 100644 index 0000000000000000000000000000000000000000..1a0e83fe1649459289ebec8184c45e757f055dc2 --- /dev/null +++ b/drivers/net/ovpn/main.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: Antonio Quartulli + */ + +#ifndef _NET_OVPN_MAIN_H_ +#define _NET_OVPN_MAIN_H_ + +bool ovpn_dev_is_valid(const struct net_device *dev); + +#endif /* _NET_OVPN_MAIN_H_ */ diff --git a/drivers/net/ovpn/netlink-gen.c b/drivers/net/ovpn/netlink-gen.c new file mode 100644 index 0000000000000000000000000000000000000000..e99d6487d116e7082293ccdd2f0a253b8769389c --- /dev/null +++ b/drivers/net/ovpn/netlink-gen.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/ovpn.yaml */ +/* YNL-GEN kernel source */ + +#include +#include + +#include "netlink-gen.h" + +#include + +/* Integer value ranges */ +static const struct netlink_range_validation ovpn_a_peer_id_range = { + .max = 16777215ULL, +}; + +static const struct netlink_range_validation ovpn_a_keyconf_peer_id_range = { + .max = 16777215ULL, +}; + +/* Common nested types */ +const struct nla_policy ovpn_keyconf_nl_policy[OVPN_A_KEYCONF_DECRYPT_DIR + 1] = { + [OVPN_A_KEYCONF_PEER_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_keyconf_peer_id_range), + [OVPN_A_KEYCONF_SLOT] = NLA_POLICY_MAX(NLA_U32, 1), + [OVPN_A_KEYCONF_KEY_ID] = NLA_POLICY_MAX(NLA_U32, 7), + [OVPN_A_KEYCONF_CIPHER_ALG] = NLA_POLICY_MAX(NLA_U32, 2), + [OVPN_A_KEYCONF_ENCRYPT_DIR] = NLA_POLICY_NESTED(ovpn_keydir_nl_policy), + [OVPN_A_KEYCONF_DECRYPT_DIR] = NLA_POLICY_NESTED(ovpn_keydir_nl_policy), +}; + +const struct nla_policy ovpn_keydir_nl_policy[OVPN_A_KEYDIR_NONCE_TAIL + 1] = { + [OVPN_A_KEYDIR_CIPHER_KEY] = NLA_POLICY_MAX_LEN(256), + [OVPN_A_KEYDIR_NONCE_TAIL] = NLA_POLICY_EXACT_LEN(OVPN_NONCE_TAIL_SIZE), +}; + +const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_LINK_TX_PACKETS + 1] = { + [OVPN_A_PEER_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_id_range), + [OVPN_A_PEER_REMOTE_IPV4] = { .type = NLA_BE32, }, + [OVPN_A_PEER_REMOTE_IPV6] = NLA_POLICY_EXACT_LEN(16), + [OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID] = { .type = NLA_U32, }, + [OVPN_A_PEER_REMOTE_PORT] = NLA_POLICY_MIN(NLA_BE16, 1), + [OVPN_A_PEER_SOCKET] = { .type = NLA_U32, }, + [OVPN_A_PEER_VPN_IPV4] = { .type = NLA_BE32, }, + [OVPN_A_PEER_VPN_IPV6] = NLA_POLICY_EXACT_LEN(16), + [OVPN_A_PEER_LOCAL_IPV4] = { .type = NLA_BE32, }, + [OVPN_A_PEER_LOCAL_IPV6] = NLA_POLICY_EXACT_LEN(16), + [OVPN_A_PEER_LOCAL_PORT] = NLA_POLICY_MIN(NLA_BE16, 1), + [OVPN_A_PEER_KEEPALIVE_INTERVAL] = { .type = NLA_U32, }, + [OVPN_A_PEER_KEEPALIVE_TIMEOUT] = { .type = NLA_U32, }, + [OVPN_A_PEER_DEL_REASON] = NLA_POLICY_MAX(NLA_U32, 5), + [OVPN_A_PEER_VPN_RX_BYTES] = { .type = NLA_UINT, }, + [OVPN_A_PEER_VPN_TX_BYTES] = { .type = NLA_UINT, }, + [OVPN_A_PEER_VPN_RX_PACKETS] = { .type = NLA_UINT, }, + [OVPN_A_PEER_VPN_TX_PACKETS] = { .type = NLA_UINT, }, + [OVPN_A_PEER_LINK_RX_BYTES] = { .type = NLA_UINT, }, + [OVPN_A_PEER_LINK_TX_BYTES] = { .type = NLA_UINT, }, + [OVPN_A_PEER_LINK_RX_PACKETS] = { .type = NLA_U32, }, + [OVPN_A_PEER_LINK_TX_PACKETS] = { .type = NLA_U32, }, +}; + +/* OVPN_CMD_PEER_NEW - do */ +static const struct nla_policy ovpn_peer_new_nl_policy[OVPN_A_PEER + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_nl_policy), +}; + +/* OVPN_CMD_PEER_SET - do */ +static const struct nla_policy ovpn_peer_set_nl_policy[OVPN_A_PEER + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_nl_policy), +}; + +/* OVPN_CMD_PEER_GET - do */ +static const struct nla_policy ovpn_peer_get_do_nl_policy[OVPN_A_PEER + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_nl_policy), +}; + +/* OVPN_CMD_PEER_GET - dump */ +static const struct nla_policy ovpn_peer_get_dump_nl_policy[OVPN_A_IFINDEX + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, +}; + +/* OVPN_CMD_PEER_DEL - do */ +static const struct nla_policy ovpn_peer_del_nl_policy[OVPN_A_PEER + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_PEER] = NLA_POLICY_NESTED(ovpn_peer_nl_policy), +}; + +/* OVPN_CMD_KEY_NEW - do */ +static const struct nla_policy ovpn_key_new_nl_policy[OVPN_A_KEYCONF + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_nl_policy), +}; + +/* OVPN_CMD_KEY_GET - do */ +static const struct nla_policy ovpn_key_get_nl_policy[OVPN_A_KEYCONF + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_nl_policy), +}; + +/* OVPN_CMD_KEY_SWAP - do */ +static const struct nla_policy ovpn_key_swap_nl_policy[OVPN_A_KEYCONF + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_nl_policy), +}; + +/* OVPN_CMD_KEY_DEL - do */ +static const struct nla_policy ovpn_key_del_nl_policy[OVPN_A_KEYCONF + 1] = { + [OVPN_A_IFINDEX] = { .type = NLA_U32, }, + [OVPN_A_KEYCONF] = NLA_POLICY_NESTED(ovpn_keyconf_nl_policy), +}; + +/* Ops table for ovpn */ +static const struct genl_split_ops ovpn_nl_ops[] = { + { + .cmd = OVPN_CMD_PEER_NEW, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_peer_new_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_peer_new_nl_policy, + .maxattr = OVPN_A_PEER, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = OVPN_CMD_PEER_SET, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_peer_set_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_peer_set_nl_policy, + .maxattr = OVPN_A_PEER, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = OVPN_CMD_PEER_GET, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_peer_get_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_peer_get_do_nl_policy, + .maxattr = OVPN_A_PEER, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = OVPN_CMD_PEER_GET, + .dumpit = ovpn_nl_peer_get_dumpit, + .policy = ovpn_peer_get_dump_nl_policy, + .maxattr = OVPN_A_IFINDEX, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP, + }, + { + .cmd = OVPN_CMD_PEER_DEL, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_peer_del_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_peer_del_nl_policy, + .maxattr = OVPN_A_PEER, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = OVPN_CMD_KEY_NEW, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_key_new_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_key_new_nl_policy, + .maxattr = OVPN_A_KEYCONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = OVPN_CMD_KEY_GET, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_key_get_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_key_get_nl_policy, + .maxattr = OVPN_A_KEYCONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = OVPN_CMD_KEY_SWAP, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_key_swap_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_key_swap_nl_policy, + .maxattr = OVPN_A_KEYCONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, + { + .cmd = OVPN_CMD_KEY_DEL, + .pre_doit = ovpn_nl_pre_doit, + .doit = ovpn_nl_key_del_doit, + .post_doit = ovpn_nl_post_doit, + .policy = ovpn_key_del_nl_policy, + .maxattr = OVPN_A_KEYCONF, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, + }, +}; + +static const struct genl_multicast_group ovpn_nl_mcgrps[] = { + [OVPN_NLGRP_PEERS] = { "peers", }, +}; + +struct genl_family ovpn_nl_family __ro_after_init = { + .name = OVPN_FAMILY_NAME, + .version = OVPN_FAMILY_VERSION, + .netnsok = true, + .parallel_ops = true, + .module = THIS_MODULE, + .split_ops = ovpn_nl_ops, + .n_split_ops = ARRAY_SIZE(ovpn_nl_ops), + .mcgrps = ovpn_nl_mcgrps, + .n_mcgrps = ARRAY_SIZE(ovpn_nl_mcgrps), +}; diff --git a/drivers/net/ovpn/netlink-gen.h b/drivers/net/ovpn/netlink-gen.h new file mode 100644 index 0000000000000000000000000000000000000000..66a4e4a0a055b4477b67801ded825e9ec068b0e6 --- /dev/null +++ b/drivers/net/ovpn/netlink-gen.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/ovpn.yaml */ +/* YNL-GEN kernel header */ + +#ifndef _LINUX_OVPN_GEN_H +#define _LINUX_OVPN_GEN_H + +#include +#include + +#include + +/* Common nested types */ +extern const struct nla_policy ovpn_keyconf_nl_policy[OVPN_A_KEYCONF_DECRYPT_DIR + 1]; +extern const struct nla_policy ovpn_keydir_nl_policy[OVPN_A_KEYDIR_NONCE_TAIL + 1]; +extern const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_LINK_TX_PACKETS + 1]; + +int ovpn_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); +void +ovpn_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info); + +int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info); +int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info); +int ovpn_nl_peer_get_doit(struct sk_buff *skb, struct genl_info *info); +int ovpn_nl_peer_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb); +int ovpn_nl_peer_del_doit(struct sk_buff *skb, struct genl_info *info); +int ovpn_nl_key_new_doit(struct sk_buff *skb, struct genl_info *info); +int ovpn_nl_key_get_doit(struct sk_buff *skb, struct genl_info *info); +int ovpn_nl_key_swap_doit(struct sk_buff *skb, struct genl_info *info); +int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info); + +enum { + OVPN_NLGRP_PEERS, +}; + +extern struct genl_family ovpn_nl_family; + +#endif /* _LINUX_OVPN_GEN_H */ diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c new file mode 100644 index 0000000000000000000000000000000000000000..c91368408b805d2bf4f12d64d5c55f4ed6d81343 --- /dev/null +++ b/drivers/net/ovpn/netlink.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0 +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: Antonio Quartulli + */ + +#include +#include + +#include + +#include "ovpnstruct.h" +#include "main.h" +#include "netlink.h" +#include "netlink-gen.h" + +MODULE_ALIAS_GENL_FAMILY(OVPN_FAMILY_NAME); + +/** + * ovpn_get_dev_from_attrs - retrieve the ovpn private data from the netdevice + * a netlink message is targeting + * @net: network namespace where to look for the interface + * @info: generic netlink info from the user request + * + * Return: the ovpn private data, if found, or an error otherwise + */ +static struct ovpn_priv * +ovpn_get_dev_from_attrs(struct net *net, const struct genl_info *info) +{ + struct ovpn_priv *ovpn; + struct net_device *dev; + int ifindex; + + if (GENL_REQ_ATTR_CHECK(info, OVPN_A_IFINDEX)) + return ERR_PTR(-EINVAL); + + ifindex = nla_get_u32(info->attrs[OVPN_A_IFINDEX]); + + rcu_read_lock(); + dev = dev_get_by_index_rcu(net, ifindex); + if (!dev) { + rcu_read_unlock(); + NL_SET_ERR_MSG_MOD(info->extack, + "ifindex does not match any interface"); + return ERR_PTR(-ENODEV); + } + + if (!ovpn_dev_is_valid(dev)) { + rcu_read_unlock(); + NL_SET_ERR_MSG_MOD(info->extack, + "specified interface is not ovpn"); + NL_SET_BAD_ATTR(info->extack, info->attrs[OVPN_A_IFINDEX]); + return ERR_PTR(-EINVAL); + } + + ovpn = netdev_priv(dev); + netdev_hold(dev, &ovpn->dev_tracker, GFP_KERNEL); + rcu_read_unlock(); + + return ovpn; +} + +int ovpn_nl_pre_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct ovpn_priv *ovpn = ovpn_get_dev_from_attrs(genl_info_net(info), + info); + + if (IS_ERR(ovpn)) + return PTR_ERR(ovpn); + + info->user_ptr[0] = ovpn; + + return 0; +} + +void ovpn_nl_post_doit(const struct genl_split_ops *ops, struct sk_buff *skb, + struct genl_info *info) +{ + struct ovpn_priv *ovpn = info->user_ptr[0]; + + if (ovpn) + netdev_put(ovpn->dev, &ovpn->dev_tracker); +} + +int ovpn_nl_peer_new_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_peer_set_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_peer_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_peer_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_peer_del_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_key_new_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_key_get_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_key_swap_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info) +{ + return -EOPNOTSUPP; +} + +/** + * ovpn_nl_register - perform any needed registration in the NL subsustem + * + * Return: 0 on success, a negative error code otherwise + */ +int __init ovpn_nl_register(void) +{ + int ret = genl_register_family(&ovpn_nl_family); + + if (ret) { + pr_err("ovpn: genl_register_family failed: %d\n", ret); + return ret; + } + + return 0; +} + +/** + * ovpn_nl_unregister - undo any module wide netlink registration + */ +void ovpn_nl_unregister(void) +{ + genl_unregister_family(&ovpn_nl_family); +} diff --git a/drivers/net/ovpn/netlink.h b/drivers/net/ovpn/netlink.h new file mode 100644 index 0000000000000000000000000000000000000000..9e87cf11d1e9813b7a75ddf3705ab7d5fabe899f --- /dev/null +++ b/drivers/net/ovpn/netlink.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: Antonio Quartulli + */ + +#ifndef _NET_OVPN_NETLINK_H_ +#define _NET_OVPN_NETLINK_H_ + +int ovpn_nl_register(void); +void ovpn_nl_unregister(void); + +#endif /* _NET_OVPN_NETLINK_H_ */ diff --git a/drivers/net/ovpn/ovpnstruct.h b/drivers/net/ovpn/ovpnstruct.h new file mode 100644 index 0000000000000000000000000000000000000000..b4e37e922fe5a5659e030174f1e42b3935967ca0 --- /dev/null +++ b/drivers/net/ovpn/ovpnstruct.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2019-2024 OpenVPN, Inc. + * + * Author: James Yonan + * Antonio Quartulli + */ + +#ifndef _NET_OVPN_OVPNSTRUCT_H_ +#define _NET_OVPN_OVPNSTRUCT_H_ + +#include + +/** + * struct ovpn_priv - per ovpn interface state + * @dev: the actual netdev representing the tunnel + * @dev_tracker: reference tracker for associated dev + */ +struct ovpn_priv { + struct net_device *dev; + netdevice_tracker dev_tracker; +}; + +#endif /* _NET_OVPN_OVPNSTRUCT_H_ */ diff --git a/include/uapi/linux/ovpn.h b/include/uapi/linux/ovpn.h new file mode 100644 index 0000000000000000000000000000000000000000..de0c6ff421871685a648dbee67070a89d9f3e53f --- /dev/null +++ b/include/uapi/linux/ovpn.h @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/ovpn.yaml */ +/* YNL-GEN uapi header */ + +#ifndef _UAPI_LINUX_OVPN_H +#define _UAPI_LINUX_OVPN_H + +#define OVPN_FAMILY_NAME "ovpn" +#define OVPN_FAMILY_VERSION 1 + +#define OVPN_NONCE_TAIL_SIZE 8 + +enum ovpn_cipher_alg { + OVPN_CIPHER_ALG_NONE, + OVPN_CIPHER_ALG_AES_GCM, + OVPN_CIPHER_ALG_CHACHA20_POLY1305, +}; + +enum ovpn_del_peer_reason { + OVPN_DEL_PEER_REASON_TEARDOWN, + OVPN_DEL_PEER_REASON_ADMINDOWN, + OVPN_DEL_PEER_REASON_USERSPACE, + OVPN_DEL_PEER_REASON_EXPIRED, + OVPN_DEL_PEER_REASON_TRANSPORT_ERROR, + OVPN_DEL_PEER_REASON_TRANSPORT_DISCONNECT, +}; + +enum ovpn_key_slot { + OVPN_KEY_SLOT_PRIMARY, + OVPN_KEY_SLOT_SECONDARY, +}; + +enum { + OVPN_A_PEER_ID = 1, + OVPN_A_PEER_REMOTE_IPV4, + OVPN_A_PEER_REMOTE_IPV6, + OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID, + OVPN_A_PEER_REMOTE_PORT, + OVPN_A_PEER_SOCKET, + OVPN_A_PEER_VPN_IPV4, + OVPN_A_PEER_VPN_IPV6, + OVPN_A_PEER_LOCAL_IPV4, + OVPN_A_PEER_LOCAL_IPV6, + OVPN_A_PEER_LOCAL_PORT, + OVPN_A_PEER_KEEPALIVE_INTERVAL, + OVPN_A_PEER_KEEPALIVE_TIMEOUT, + OVPN_A_PEER_DEL_REASON, + OVPN_A_PEER_VPN_RX_BYTES, + OVPN_A_PEER_VPN_TX_BYTES, + OVPN_A_PEER_VPN_RX_PACKETS, + OVPN_A_PEER_VPN_TX_PACKETS, + OVPN_A_PEER_LINK_RX_BYTES, + OVPN_A_PEER_LINK_TX_BYTES, + OVPN_A_PEER_LINK_RX_PACKETS, + OVPN_A_PEER_LINK_TX_PACKETS, + + __OVPN_A_PEER_MAX, + OVPN_A_PEER_MAX = (__OVPN_A_PEER_MAX - 1) +}; + +enum { + OVPN_A_KEYCONF_PEER_ID = 1, + OVPN_A_KEYCONF_SLOT, + OVPN_A_KEYCONF_KEY_ID, + OVPN_A_KEYCONF_CIPHER_ALG, + OVPN_A_KEYCONF_ENCRYPT_DIR, + OVPN_A_KEYCONF_DECRYPT_DIR, + + __OVPN_A_KEYCONF_MAX, + OVPN_A_KEYCONF_MAX = (__OVPN_A_KEYCONF_MAX - 1) +}; + +enum { + OVPN_A_KEYDIR_CIPHER_KEY = 1, + OVPN_A_KEYDIR_NONCE_TAIL, + + __OVPN_A_KEYDIR_MAX, + OVPN_A_KEYDIR_MAX = (__OVPN_A_KEYDIR_MAX - 1) +}; + +enum { + OVPN_A_IFINDEX = 1, + OVPN_A_IFNAME, + OVPN_A_PEER, + OVPN_A_KEYCONF, + + __OVPN_A_MAX, + OVPN_A_MAX = (__OVPN_A_MAX - 1) +}; + +enum { + OVPN_CMD_PEER_NEW = 1, + OVPN_CMD_PEER_SET, + OVPN_CMD_PEER_GET, + OVPN_CMD_PEER_DEL, + OVPN_CMD_PEER_DEL_NTF, + OVPN_CMD_KEY_NEW, + OVPN_CMD_KEY_GET, + OVPN_CMD_KEY_SWAP, + OVPN_CMD_KEY_SWAP_NTF, + OVPN_CMD_KEY_DEL, + + __OVPN_CMD_MAX, + OVPN_CMD_MAX = (__OVPN_CMD_MAX - 1) +}; + +#define OVPN_MCGRP_PEERS "peers" + +#endif /* _UAPI_LINUX_OVPN_H */ From patchwork Mon Dec 2 15:07:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846797 Received: from mail-wm1-f46.google.com (mail-wm1-f46.google.com [209.85.128.46]) (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 388081FECDE for ; Mon, 2 Dec 2024 15:08:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152113; cv=none; b=TZmY/15bCftP28DqQ0VKxG010bDfphc7IV67f5yRu41bmKuM7MpvX0jiqio+wRbgdXkHHb5gB3Cdv3JsLCj9Aomoh3lDyaWeswJKJ8nPRoAPT10ktkkft/rccVhG2ufEUHNlyT9Zm+29YzU9gwLZ59GpZz1b01/3S5qmF2ZDKZU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152113; c=relaxed/simple; bh=GchxL43RZVWbeeTak50ypiKEh4su8ul45OjPZ601Tf0=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KjmL6elC4ys+COQ967FqlbXelqaOXUGDuA91ruVKtBSKpMCqT9o7a8YepnN6Xw7DLmAdn4REBVlJc9oc1Ptvd5NCpIRJXGSeLQgdiK74AzFK6jM6firLViefypgAh2v+ZJ9x4SUfVNt8tB80PE0YgyFeTgKVj00QVEib/GjKJhE= 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=esPEu45F; arc=none smtp.client-ip=209.85.128.46 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="esPEu45F" Received: by mail-wm1-f46.google.com with SMTP id 5b1f17b1804b1-434a2033562so35515615e9.1 for ; Mon, 02 Dec 2024 07:08:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152109; x=1733756909; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=eFk85mO/CYRQjFZfRXq+/JqMZn31zCiBs+VMv6XbtEo=; b=esPEu45FQ2zf0tcLqVuhRUOOYBeN282xm9W0GrnxPIqSOqHFpbpw0NsLM1ozSGDb2y tKeYvDSn0eRBH3nlry+eMC5n0mnv5e2cBBkwsQW7amhgSKWlmpG4Q2epexmxuIkpI3aE NgqyszcLRbHnr4RARkQR4oQ1gzho24bt1ZWy+b/ubUXq56Rik5s37dWceazjCGBL1nga Eq4mONolGf8Xdn3TS3BLuIHTwbpmIpDyb+o/+iXYWpwLRqRAwit0IIFxgtzOydJjv9m4 IerPemQ1CtPM+7+PE5r12JOKDmICqa+imU27Wh+aJVF/aI8LuK1OQ5trMvLywADtzegI SG6w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152109; x=1733756909; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=eFk85mO/CYRQjFZfRXq+/JqMZn31zCiBs+VMv6XbtEo=; b=fTQi8gj/BiaBUsl5s7NZ5maVmsVlOStlY/W1zWO+8C2WMvP8aUeE5vxqtIYTLiS5aB GareLUJShRVWybGO+zqbKGJxUtjz6lsSiVxsE6BoPhvB6zTuz7JN5Ai2Gd47aSxa97Zr 3fgRgAnSdovIEIYqTDhuIOGp03tY86dzdBO+Y0POiBRDVFVWMz9rcMHBhdl5CKaj0y8B tzGZMMbWrgPfCd4WUHs90Qh/R1LJfkwVz3VR9wWc5Kycif03w81F2E8bU3VHAqUSCBac rwRb9RC4p4VHjTxtbdUjCeiLjIcR/T7l2r4DVdm5QCb0cnWvOkW7xguqJRsmnFxRjR9s kAsQ== X-Forwarded-Encrypted: i=1; AJvYcCWUi7oUS1IS0tDDmxPkiohKyMx5J7NM46bUfZqvMJYU1YH3CoJLn3H/7laTMokK5w38Ju0CK01Z1KiJGPgjZ2U=@vger.kernel.org X-Gm-Message-State: AOJu0Yz1qIAK8054SrHC2v3kZzwxg36MkkU0pdTuTS1+ysw7knsZ2+fB tPNUwUH6URLxzyinJiBkox9ZQr2h8+qHwtr21PvCCsZNoNKXxN4CEpVn11GVWDQ= X-Gm-Gg: ASbGnctlhfqfssVK1UxzVX7LMEQ97qqyvqB7f6vkpb6F+yQPbBdyJoIU0G9IFNjQ0UG MhtPCt4aLIHF7DCMdW7NenA6UNfeH0kQYxV1RLYn81tz8iY7H9oRG5hl93XnKEZ8OlongU6j1ek Fb2r9cpYvyMy/T6mDbweTTrzlCF8zVzdIZg3vP17kDhGejdlUVTGVvQtj9O9X/lC86hJtkIl7kU P3feoqJUnb6/YRS1wOF5ILUcOJiQ1XdzzgY9Bzq0DWVSZn7LerQqTplNG6e X-Google-Smtp-Source: AGHT+IE9+NpE7NGThJI4CkKY2J7SsTibLxytfXaCc5NoapUYpxSgqRJT4hJqKc1EJkgF72rjCKebsg== X-Received: by 2002:a05:600c:5488:b0:434:a91e:c709 with SMTP id 5b1f17b1804b1-434a9e0c1e8mr174361285e9.28.1733152077890; Mon, 02 Dec 2024 07:07:57 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.07.56 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:07:57 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:22 +0100 Subject: [PATCH net-next v12 04/22] ovpn: keep carrier always on for MP interfaces Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-4-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1056; i=antonio@openvpn.net; h=from:subject:message-id; bh=GchxL43RZVWbeeTak50ypiKEh4su8ul45OjPZ601Tf0=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1lMvkiriFWfbYx3aXmiy27DEU6gCwkU5U1W xWoMBJEYm2JATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZQAKCRALcOU6oDjV h6veB/9JdnZ+5+QBboFK3XmI04EenUg5uTWy1foOJqjQZn/x7RVCXTKoi/LpkySyiz5o72ulOSj nUwafSmFFdeArvM51iWOSlDbEKhWvZ2oVMmbw3VpUaLTejFLMkcPliWaU6hHvVtFqqCQCcjF4uN zB8uqxNlDqbkdb1MybWIPxWRMArjy+MVebNC4KxXtcS4f/X+Oo3AJTmFz8YJtcI6+ghKCECsjCT Fl+zCBaarLhyKu+ftRqD3QJ1SfcacDpwV2PXxogrx9erNvH1HlI4MRvwc/t55SZm7q7gzSLuJG8 vlpcEGEu2UjMLlUQDvPt5xR3ZJ8J6Qdww6KkCPpFAc1ZKZUE X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C An ovpn interface configured in MP mode will keep carrier always on and let the user decide when to bring it administratively up and down. This way a MP node (i.e. a server) will keep its interface always up and running, even when no peer is connected. Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 60954c5b2b9254db1d24d01ac383935765c7ce5b..274d6166741ef2d6275a252d0c042bc66f8f41f7 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -23,6 +23,15 @@ static int ovpn_net_open(struct net_device *dev) { + struct ovpn_priv *ovpn = netdev_priv(dev); + + /* carrier for P2P interfaces is switched on and off when + * the peer is added or deleted. + * + * in case of P2MP interfaces we just keep the carrier always on + */ + if (ovpn->mode == OVPN_MODE_MP) + netif_carrier_on(dev); netif_tx_start_all_queues(dev); return 0; } From patchwork Mon Dec 2 15:07:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846796 Received: from mail-wr1-f52.google.com (mail-wr1-f52.google.com [209.85.221.52]) (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 455DE207A1A for ; Mon, 2 Dec 2024 15:08:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152116; cv=none; b=SI/ZyGePz/4zp7MET8fbQql6VGMdaGWTxB4egg9aDlMQ7/CZ+9of7wwA+J8Hkhr+kKlE4I0RW5XmoAmB6JIFyRYUMmeZZvSOu4HVsQRAHz3yiGQsbjBJKjKfzMF1v3X9Eb5O3TavhTIBLcsZOp6JambCLU1iHfVoM6mAEfmmHI0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152116; c=relaxed/simple; bh=s4/ZdT9zdOkVSSi9e3WzjwtVGY+a1rBt+0eChPO/3OE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=eiuBrbmXRaSdW+okbp5OY+SpRCoii1z0SmqU6+03e9MYRarJrBNIN2whaDmx3cSVjCJBtAVR7/pKa0tSGlFbZTS5iRmM0iUUMPEUb7f1/ztIOdtRZWd5QK1eNIPt1BWTtM+xmRLmGJlA1ltW1ON39j+04NM2ta6RpFRYTiHWc+c= 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=BGQerBWa; arc=none smtp.client-ip=209.85.221.52 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="BGQerBWa" Received: by mail-wr1-f52.google.com with SMTP id ffacd0b85a97d-385e3621518so1702482f8f.1 for ; Mon, 02 Dec 2024 07:08:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152112; x=1733756912; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=3daJ53YHoVN7jrj6xC4iHVjMVlqLQppA0hCq5GaWo3g=; b=BGQerBWatDXOzP7Wv2/FQaRxtYh9onTr3lFQA0vbLPtHPmdHUcmFA0szdJeuVHGNhL 1Qqygvz4rgGgLlDS9SZk2t6veNqez5mnnV03ksM8mcuGVkW3shJwzFz3BVlPvdoSFTSq joaiBJGpnh+QNzaI9borbl0ODtqZcg4aHOJpH6YDgaz2xnzzUJfkIT/yakEhmesaHFGl rSK4O0Quzetx8oJ3IPdSsPaD/TyN0Mx6SvaWFNjQxHVhNS90ZHlIhws8MoyzvSDuM4x+ YmvnMkzImw8sndYuIjAF2ldzvcrA1NMfXmV6xZRMXM9u0GDfr3/7XmCFpj5q5f72oT/h Hm4w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152112; x=1733756912; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=3daJ53YHoVN7jrj6xC4iHVjMVlqLQppA0hCq5GaWo3g=; b=ZdYSaNpq4ECgni/rwC4Ge9JOjdSznPfhtrTA+3zLGagcFyns7AuHV4K25GtDZ7Te/h oZFX9TndaabfELVmvNDuMoO8hDq4lN8hng3XghR5PQkPQ+QnL6WKi+ptc0Dc5zRXMFJQ wSvMK1J4t+mCmLGSb8LTqjZ4dsZDSX1HBLF7vRdG5sqIvBGyYW2e0Y6wOpozZ0HYhXVS 6eDJdzEnm74/2rPALNXaKp0ikuPeP1rmb9o5hBcIbdlo4dppD2jMz7cHeKuSMZEp9Yq/ bKvI2YRODGJOnJ9ue5AH5jM6AG1TxaapuuAla81TWT2BEGhK4qX2w3uZ3+2CGCHgdwiq qKpQ== X-Forwarded-Encrypted: i=1; AJvYcCWjAUbTB/bunVoKXX7DOdrMtC6zosg+S32TPwRMNKql0JgjD0arpE4HUxP8KpFBp+mSijq7oRaH80xBCUK4RLk=@vger.kernel.org X-Gm-Message-State: AOJu0YyFjZo8WN5pEfNmg5S7OZzp9Z5DMYZBrWtzTOe/UFDyajXMdkfm 76S/x0tmfsrbmbX85xk7XOd9SiRmxojfU3y9Td9h6Ep0pLJ0OqhSO/6j5kTgITk= X-Gm-Gg: ASbGncuBnlrPnzNAjr/lSsZ3JcMGFvA0NzeukxUcGwpUxwgIjfNLmzUqPh7Cv8ImoTk g9HjfUSoZ13hfS5mdj1BoKbDo96DREWq03yS253qQXV0fF2Vvrwpcop6C26ah2FCaNVzgNYKT2o ki17JWggKIMq/eiPBYHLVPkEShBo3+9MBDRMHINy73GdtkRz6TUPJ74fdyEX6me1sodWhY8YEIh GpqffvPJd8fBEBJ1WMBJFj5YnwT+upGLyyiuDm3PaqCRySsEYjDV/vnhb53 X-Google-Smtp-Source: AGHT+IEhKROhUN0wfgdS73vJ3uswtm21WXaoM04qgso+ZMHHE0VVnC/mFKbobALKNYDkWQCQYs2jMQ== X-Received: by 2002:a05:6000:79e:b0:385:e429:e591 with SMTP id ffacd0b85a97d-385e429e6cfmr6626252f8f.23.1733152110576; Mon, 02 Dec 2024 07:08:30 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:30 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:24 +0100 Subject: [PATCH net-next v12 06/22] ovpn: introduce the ovpn_socket object Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-6-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=9367; i=antonio@openvpn.net; h=from:subject:message-id; bh=s4/ZdT9zdOkVSSi9e3WzjwtVGY+a1rBt+0eChPO/3OE=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1mnKn/3pk7y3wJc5jvvvZVrMIi4u2latKvV ZR3ixZownGJATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZgAKCRALcOU6oDjV h2JsB/0asCCjSSHfsjMZ9mPTVL7u6bxNUqaRwz+4NcgYa6syHf7mJhw2L+4SncGoHSdh6ookqfC a+DO7q+bDK0g/3RyT/oz9gx6tZGrYFd94to6t9/Cyllzh9TwWqxNa4mmC6pTvUrzJMUXwrHAvHB qVmRzOHNx4ElSiehFAHHpGLXAFjEwI9vIUs0tUsY+1DXR7leS7XTBFBoE5M88nf9bD90GDRBtIV KeflkiKfc9rYIHcA6GdHY0NI+QVcZuJQeUJBCOeCizssWmFbr98wI13yUh+qzUjky2zftVPCfAX 86U03ykSehRvgIotzm7UTufcxg9pCyy9CEn9WjEqjnYizdMk X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C 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 attached 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 | 119 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ovpn/socket.h | 48 +++++++++++++++++++ drivers/net/ovpn/udp.c | 65 +++++++++++++++++++++++++ drivers/net/ovpn/udp.h | 17 +++++++ include/uapi/linux/udp.h | 1 + 6 files changed, 252 insertions(+) diff --git a/drivers/net/ovpn/Makefile b/drivers/net/ovpn/Makefile index ce13499b3e1775a7f2a9ce16c6cb0aa088f93685..56bddc9bef83e0befde6af3c3565bb91731d7b22 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 0000000000000000000000000000000000000000..0abac02e13fb4ef1e212dacae075d5b58e872d34 --- /dev/null +++ b/drivers/net/ovpn/socket.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: James Yonan + * Antonio Quartulli + */ + +#include +#include +#include + +#include "ovpnstruct.h" +#include "main.h" +#include "io.h" +#include "peer.h" +#include "socket.h" +#include "udp.h" + +static void ovpn_socket_detach(struct socket *sock) +{ + if (!sock) + return; + + sockfd_put(sock); +} + +/** + * ovpn_socket_release_kref - kref_put callback + * @kref: the kref object + */ +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 (WARN_ON(!ovpn_socket_hold(ovpn_sock))) + ovpn_sock = NULL; + rcu_read_unlock(); + + return ovpn_sock; +} + +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; +} + +/** + * 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) +{ + 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); + 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 0000000000000000000000000000000000000000..904814d2b9e9f2b0773bf942372bcbe904ef5474 --- /dev/null +++ b/drivers/net/ovpn/socket.h @@ -0,0 +1,48 @@ +/* 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 + +struct ovpn_priv; +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_priv *ovpn; + struct socket *sock; + struct kref refcount; + struct rcu_head rcu; +}; + +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); +} + +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 0000000000000000000000000000000000000000..c00e07f148d72ff737e732028fd73f82a507fb57 --- /dev/null +++ b/drivers/net/ovpn/udp.c @@ -0,0 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0 +/* OpenVPN data channel offload + * + * Copyright (C) 2019-2024 OpenVPN, Inc. + * + * Author: Antonio Quartulli + */ + +#include +#include +#include +#include + +#include "ovpnstruct.h" +#include "main.h" +#include "socket.h" +#include "udp.h" + +/** + * 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_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 + * hosts and therefore openvpn instantiates one only for all its peers + */ + if ((READ_ONCE(udp_sk(sock->sk)->encap_type) == UDP_ENCAP_OVPNINUDP) && + old_data->ovpn == ovpn) { + netdev_dbg(ovpn->dev, + "provided socket already owned by this interface\n"); + ret = -EALREADY; + } else { + netdev_dbg(ovpn->dev, + "provided socket already taken by other user\n"); + ret = -EBUSY; + } + rcu_read_unlock(); + + return ret; +} diff --git a/drivers/net/ovpn/udp.h b/drivers/net/ovpn/udp.h new file mode 100644 index 0000000000000000000000000000000000000000..3c48a06f15eed624aec0a2a7b871f0e7f3004137 --- /dev/null +++ b/drivers/net/ovpn/udp.h @@ -0,0 +1,17 @@ +/* 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_priv; +struct socket; + +int ovpn_udp_socket_attach(struct socket *sock, struct ovpn_priv *ovpn); + +#endif /* _NET_OVPN_UDP_H_ */ diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h index d85d671deed3c78f6969189281b9083dcac000c6..edca3e430305a6bffc34e617421f1f3071582e69 100644 --- a/include/uapi/linux/udp.h +++ b/include/uapi/linux/udp.h @@ -43,5 +43,6 @@ struct udphdr { #define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */ #define UDP_ENCAP_RXRPC 6 #define TCP_ENCAP_ESPINTCP 7 /* Yikes, this is really xfrm encap types. */ +#define UDP_ENCAP_OVPNINUDP 8 /* OpenVPN traffic */ #endif /* _UAPI_LINUX_UDP_H */ From patchwork Mon Dec 2 15:07:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846795 Received: from mail-wr1-f47.google.com (mail-wr1-f47.google.com [209.85.221.47]) (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 87668209687 for ; Mon, 2 Dec 2024 15:08:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.47 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152119; cv=none; b=FyIsG6YOMSTtA/yp+EJh9LVp2JaV8qZj2ASScn5aN0sxc/zVIv/cjd17aEVQ8dXRxAmaHuuEzYDPJr7e6zAVZ6GZ4i1R0+Z3owj2OQcur3UTEqZJN6fqksgQ5iGjhfwFNzUM0d+BtjGOAAF7k7gFF/TbQ9H1laXrZLiWA2vbibk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152119; c=relaxed/simple; bh=kyXOaAbFmCPM0EBalznyzeL5T2BVV3JBJXdYrjkMBPM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cfUE/6wQxIPXR6zNrXPGuIMCxzxtKAPHjpLqKe8htNKg/AHJ7N9YUD3PWw+1Oynul3FXrfAWTxTQ+hxxdN3glZ+zr0mUnOMnkH524byOD6qFMHgaF4tFcfZ/0NTJIUSkcVF5teUftjrFQZt6x6y20c12mgQCyKlb4NaZgVH87BE= 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=bwtyHRX3; arc=none smtp.client-ip=209.85.221.47 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="bwtyHRX3" Received: by mail-wr1-f47.google.com with SMTP id ffacd0b85a97d-385ef8b64b3so1136895f8f.0 for ; Mon, 02 Dec 2024 07:08:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152115; x=1733756915; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=fIi1oBzwJxrG/vKWNS80Yq664rJ9nJjFLkN3WL6mQZ0=; b=bwtyHRX3TyOCTrhZ33FmAjabJCLdONKq/j7sHK/z9jnqs9G+qB3qHqyouFb90abnYj OZETCt4bnXmb5ynt/1k9+UvaFMImzXn6lcevtN+yg+giChMJJEJWHksqPcxATtTrht95 Th6bUZF45Rlnkb1Mj4dciHJ/xFaAsZmrlbHb0DAQPr7M6/UTnxJJRlbEstNdFPRJAhio bCF+S2YReL/YITsqwmMy9Y4506Jl0UQWQDH7b/GJrMYRyl5AER9RNioz/xg/r9iAEcDk h97O1DyIzz2lCAs7NctZF2qTZqww3QNXFNonsZBr7hlqkRJdauiul4L0DnUyz2gAl6WV k+Zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152115; x=1733756915; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=fIi1oBzwJxrG/vKWNS80Yq664rJ9nJjFLkN3WL6mQZ0=; b=Uld6Hyg8OMzaTRvs5LOINQGzulxJ8PnZXhwyaVvcREzWlb+Vl4hmaqrvY0BwRH2QED +E5/yjC8gMwVjwR/O69a0lw8iCTM2r9JwTlxea1iEvxnqrefDWC3I+8dcfuRlNlRWwXl XuHHlOpVfM2q2O7szudNUi0h0t6nLkeRX5mUq9SZohVhgMXioogzpI4fd0JW+ZcoPtg7 w7SEWNd+eDWQ/esDxirKZk+NfkIgmSLn6CQ+NNDUR9SpobynXnF5W8fNeaBS/nDLINzK EjACal3VIvWl+4olxR2JIcJxq48Mtjsi1Q2j0Nydsw5PlDENgTQ5ge/pTpA+7epdVPvb 6Ovg== X-Forwarded-Encrypted: i=1; AJvYcCUO0MWM2KAFM7YV70LYpDXvoXvmKdmgu9+4YWFdOIYHTc4cErKMwRY/jibQTt0JDBOpoFOExJC8PvDG/m/ZucI=@vger.kernel.org X-Gm-Message-State: AOJu0YxkLaej7WOGp9zKkBaNOi73mXNxYOEyOiKEsYLl2fBsJQqwXDJ7 dD43nrwpe03m7ILuqQV/CKTCqmr9vR83GEvlz5zXIqWS9VTUPLQQgKYfDYJgdEs= X-Gm-Gg: ASbGncsgjgrqsBNjJMvX0LjtJFImQHhZ3yZvKAggGdV9fNhSquYWwE7hXyPH+GLjMif cNpljqrhg9qCeVw+Kq08VS0IEac68c386p6QnzLwxSNrdrgFchrcx3XM1sdYd11/5qVkjCBzVKw +qnrDH/9r8dXhe0AHc0faEQdaz8gbi1KlpasLmt9r0i5ju7vZq+VYqHvlpny1xKku/x1+32C9ru qCWDs3ET1DFlJVkqQwT/B4YmjrIpdYbYKCLaMPQrzdZ/zY0nzMqZyDVh2eK X-Google-Smtp-Source: AGHT+IENJDptYvtgBnZQKTZ5qyio6YMSGGNaVqv2i7vqUnNgARzMREImkX7V53qLvTaT4c2VkGU7JA== X-Received: by 2002:a5d:5e83:0:b0:385:f1d6:7b6a with SMTP id ffacd0b85a97d-385f1d67e25mr6246744f8f.55.1733152111952; Mon, 02 Dec 2024 07:08:31 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:31 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:25 +0100 Subject: [PATCH net-next v12 07/22] ovpn: implement basic TX path (UDP) Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-7-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=17133; i=antonio@openvpn.net; h=from:subject:message-id; bh=kyXOaAbFmCPM0EBalznyzeL5T2BVV3JBJXdYrjkMBPM=; b=owGbwMvMwMHIXfDUaoHF1XbG02pJDOm+Z9PenQ2x7jUO0VySacjkc010x0KdPuYOiUkSD1fMy Tx5zPNAJ6MxCwMjB4OsmCLLzNV3cn5cEXpyL/7AH5hBrEwgUxi4OAVgIunb2f8Z8vRF65xzi3// ZOUPlm62S90b5xwXk519xz1R/9Ex5aUxnOZ6ocqC17J3ZGy2m2tbuHdN3cHNhXNENB//cNy6KOy Fi5Okp5SgMWv0v/8OhntVWCR75AO3Vug37L3QXJivqHEopeGpR8VpK87jwqcqDugUe1tb2ty5/U Pk29GS724qTnU16cvfbjq1MohFTOfB5wtfItR2pJ34kRgauC3QX+Bpb0j2A1X+mF3KKy0szENU1 AwMpaR6WJK7tOo/bpUsfXQzQYXRQLpYqGxeSbbmvweOX+N0Gnqnl8jqH47psUth5FBUfKKzSbmb fbrc5wUnmBQP13+dZL1Ak/XX1eY5IccklG8q+y48/3wBAA== X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C Packets sent over the ovpn interface are processed and transmitted to the connected peer, if any. Implementation is UDP only. TCP will be added by a later patch. Note: no crypto/encapsulation exists yet. Packets are just captured and sent. Signed-off-by: Antonio Quartulli --- drivers/net/Kconfig | 1 + drivers/net/ovpn/io.c | 129 ++++++++++++++++++++++++++- drivers/net/ovpn/peer.c | 35 ++++++++ drivers/net/ovpn/peer.h | 4 + drivers/net/ovpn/skb.h | 54 +++++++++++ drivers/net/ovpn/udp.c | 233 ++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ovpn/udp.h | 5 ++ 7 files changed, 460 insertions(+), 1 deletion(-) diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d6c1810f042e222143f53563a8d8df4bc9df27ed..f4f985fc003373ddc14dc18f8b3f73295a3ae0a6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -119,6 +119,7 @@ config OVPN tristate "OpenVPN data channel offload" depends on NET && INET select DST_CACHE + select NET_UDP_TUNNEL help This module enhances the performance of the OpenVPN userspace software by offloading the data channel processing to kernelspace. diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index ad3813419c33cbdfe7e8ad6f5c8b444a3540a69f..2a3dbc723813a14070159318097755cc7ea3f216 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -9,14 +9,141 @@ #include #include +#include #include "io.h" +#include "ovpnstruct.h" +#include "peer.h" +#include "udp.h" +#include "skb.h" +#include "socket.h" + +static void ovpn_encrypt_post(struct sk_buff *skb, int ret) +{ + struct ovpn_peer *peer = ovpn_skb_cb(skb)->peer; + + if (unlikely(ret < 0)) + goto err; + + skb_mark_not_on_list(skb); + + switch (peer->sock->sock->sk->sk_protocol) { + case IPPROTO_UDP: + ovpn_udp_send_skb(peer, skb); + break; + default: + /* no transport configured yet */ + goto err; + } + /* skb passed down the stack - don't free it */ + skb = NULL; +err: + if (unlikely(skb)) + dev_core_stats_tx_dropped_inc(peer->ovpn->dev); + ovpn_peer_put(peer); + kfree_skb(skb); +} + +static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) +{ + ovpn_skb_cb(skb)->peer = peer; + + /* take a reference to the peer because the crypto code may run async. + * ovpn_encrypt_post() will release it upon completion + */ + if (unlikely(!ovpn_peer_hold(peer))) { + DEBUG_NET_WARN_ON_ONCE(1); + return false; + } + + ovpn_encrypt_post(skb, 0); + return true; +} + +/* send skb to connected peer, if any */ +static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, + struct ovpn_peer *peer) +{ + struct sk_buff *curr, *next; + + /* this might be a GSO-segmented skb list: process each skb + * independently + */ + skb_list_walk_safe(skb, curr, next) { + if (unlikely(!ovpn_encrypt_one(peer, curr))) { + dev_core_stats_tx_dropped_inc(ovpn->dev); + kfree_skb(curr); + } + } + + ovpn_peer_put(peer); +} /* Send user data to the network */ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) { + struct ovpn_priv *ovpn = netdev_priv(dev); + struct sk_buff *segments, *curr, *next; + struct sk_buff_head skb_list; + struct ovpn_peer *peer; + __be16 proto; + int ret; + + /* reset netfilter state */ + nf_reset_ct(skb); + + /* verify IP header size in network packet */ + proto = ovpn_ip_check_protocol(skb); + if (unlikely(!proto || skb->protocol != proto)) + goto drop; + + if (skb_is_gso(skb)) { + segments = skb_gso_segment(skb, 0); + if (IS_ERR(segments)) { + ret = PTR_ERR(segments); + net_err_ratelimited("%s: cannot segment payload packet: %d\n", + netdev_name(dev), ret); + goto drop; + } + + consume_skb(skb); + skb = segments; + } + + /* from this moment on, "skb" might be a list */ + + __skb_queue_head_init(&skb_list); + skb_list_walk_safe(skb, curr, next) { + skb_mark_not_on_list(curr); + + curr = skb_share_check(curr, GFP_ATOMIC); + if (unlikely(!curr)) { + net_err_ratelimited("%s: skb_share_check failed for payload packet\n", + netdev_name(dev)); + dev_core_stats_tx_dropped_inc(ovpn->dev); + continue; + } + + __skb_queue_tail(&skb_list, curr); + } + skb_list.prev->next = NULL; + + /* retrieve peer serving the destination IP of this packet */ + peer = ovpn_peer_get_by_dst(ovpn, skb); + if (unlikely(!peer)) { + net_dbg_ratelimited("%s: no peer to send data to\n", + netdev_name(ovpn->dev)); + goto drop; + } + + ovpn_send(ovpn, skb_list.next, peer); + + return NETDEV_TX_OK; + +drop: + dev_core_stats_tx_dropped_inc(ovpn->dev); skb_tx_error(skb); - kfree_skb(skb); + kfree_skb_list(skb); return NET_XMIT_DROP; } diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 2ed853624871b83c1b8922b0cf004ad85f478b44..5bc6854ce701c084982c5b3b6a0c536e828a77bd 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -16,6 +16,7 @@ #include "main.h" #include "netlink.h" #include "peer.h" +#include "socket.h" /** * ovpn_peer_new - allocate and initialize a new peer object @@ -253,6 +254,38 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id) return peer; } +/** + * ovpn_peer_get_by_dst - Lookup peer to send skb to + * @ovpn: the private data representing the current VPN session + * @skb: the skb to extract the destination address from + * + * This function takes a tunnel packet and looks up the peer to send it to + * after encapsulation. The skb is expected to be the in-tunnel packet, without + * any OpenVPN related header. + * + * Assume that the IP header is accessible in the skb data. + * + * Return: the peer if found or NULL otherwise. + */ +struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn, + struct sk_buff *skb) +{ + struct ovpn_peer *peer = NULL; + + /* in P2P mode, no matter the destination, packets are always sent to + * the single peer listening on the other side + */ + if (ovpn->mode == OVPN_MODE_P2P) { + rcu_read_lock(); + peer = rcu_dereference(ovpn->peer); + if (unlikely(peer && !ovpn_peer_hold(peer))) + peer = NULL; + rcu_read_unlock(); + } + + return peer; +} + /** * ovpn_peer_add_p2p - add peer to related tables in a P2P instance * @ovpn: the instance to add the peer to @@ -318,6 +351,8 @@ static void ovpn_peer_remove(struct ovpn_peer *peer, } peer->delete_reason = reason; + if (peer->sock) + ovpn_socket_put(peer->sock); /* reference from ovpn->peer or hashtable dropped */ ovpn_peer_put(peer); diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index c3458732b2cfcd439644423ec8cd77595f9ed5f3..24de7a69e371a521bed48a8ef3116350ea3e9560 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -19,6 +19,7 @@ * @vpn_addrs: IP addresses assigned over the tunnel * @vpn_addrs.ipv4: IPv4 assigned to peer on the tunnel * @vpn_addrs.ipv6: IPv6 assigned to peer on the tunnel + * @sock: the socket being used to talk to this peer * @dst_cache: cache for dst_entry used to send to peer * @bind: remote peer binding * @delete_reason: why peer was deleted (i.e. timeout, transport error, ..) @@ -34,6 +35,7 @@ struct ovpn_peer { struct in_addr ipv4; struct in6_addr ipv6; } vpn_addrs; + struct ovpn_socket *sock; struct dst_cache dst_cache; struct ovpn_bind __rcu *bind; enum ovpn_del_peer_reason delete_reason; @@ -74,5 +76,7 @@ void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, struct ovpn_peer *ovpn_peer_get_by_transp_addr(struct ovpn_priv *ovpn, struct sk_buff *skb); struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id); +struct ovpn_peer *ovpn_peer_get_by_dst(struct ovpn_priv *ovpn, + struct sk_buff *skb); #endif /* _NET_OVPN_OVPNPEER_H_ */ diff --git a/drivers/net/ovpn/skb.h b/drivers/net/ovpn/skb.h new file mode 100644 index 0000000000000000000000000000000000000000..392bb3f77262efa580231d2eada2aa2f399a71f8 --- /dev/null +++ b/drivers/net/ovpn/skb.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: Antonio Quartulli + * James Yonan + */ + +#ifndef _NET_OVPN_SKB_H_ +#define _NET_OVPN_SKB_H_ + +#include +#include +#include +#include +#include +#include + +struct ovpn_cb { + struct ovpn_peer *peer; +}; + +static inline struct ovpn_cb *ovpn_skb_cb(struct sk_buff *skb) +{ + BUILD_BUG_ON(sizeof(struct ovpn_cb) > sizeof(skb->cb)); + return (struct ovpn_cb *)skb->cb; +} + +/* Return IP protocol version from skb header. + * Return 0 if protocol is not IPv4/IPv6 or cannot be read. + */ +static inline __be16 ovpn_ip_check_protocol(struct sk_buff *skb) +{ + __be16 proto = 0; + + /* skb could be non-linear, + * make sure IP header is in non-fragmented part + */ + if (!pskb_network_may_pull(skb, sizeof(struct iphdr))) + return 0; + + if (ip_hdr(skb)->version == 4) { + proto = htons(ETH_P_IP); + } else if (ip_hdr(skb)->version == 6) { + if (!pskb_network_may_pull(skb, sizeof(struct ipv6hdr))) + return 0; + proto = htons(ETH_P_IPV6); + } + + return proto; +} + +#endif /* _NET_OVPN_SKB_H_ */ diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index c00e07f148d72ff737e732028fd73f82a507fb57..04e4b2c51bae1557b7b2665bddce9245ab96cc28 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -7,15 +7,248 @@ */ #include +#include +#include #include #include +#include +#include +#include +#include #include +#include #include "ovpnstruct.h" #include "main.h" +#include "bind.h" +#include "io.h" +#include "peer.h" #include "socket.h" #include "udp.h" +/** + * ovpn_udp4_output - send IPv4 packet over udp socket + * @peer: the destination peer + * @bind: the binding related to the destination peer + * @cache: dst cache + * @sk: the socket to send the packet over + * @skb: the packet to send + * + * Return: 0 on success or a negative error code otherwise + */ +static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind, + struct dst_cache *cache, struct sock *sk, + struct sk_buff *skb) +{ + struct rtable *rt; + struct flowi4 fl = { + .saddr = bind->local.ipv4.s_addr, + .daddr = bind->remote.in4.sin_addr.s_addr, + .fl4_sport = inet_sk(sk)->inet_sport, + .fl4_dport = bind->remote.in4.sin_port, + .flowi4_proto = sk->sk_protocol, + .flowi4_mark = sk->sk_mark, + }; + int ret; + + local_bh_disable(); + rt = dst_cache_get_ip4(cache, &fl.saddr); + if (rt) + goto transmit; + + if (unlikely(!inet_confirm_addr(sock_net(sk), NULL, 0, fl.saddr, + RT_SCOPE_HOST))) { + /* we may end up here when the cached address is not usable + * anymore. In this case we reset address/cache and perform a + * new look up + */ + fl.saddr = 0; + spin_lock_bh(&peer->lock); + bind->local.ipv4.s_addr = 0; + spin_unlock_bh(&peer->lock); + dst_cache_reset(cache); + } + + rt = ip_route_output_flow(sock_net(sk), &fl, sk); + if (IS_ERR(rt) && PTR_ERR(rt) == -EINVAL) { + fl.saddr = 0; + spin_lock_bh(&peer->lock); + bind->local.ipv4.s_addr = 0; + spin_unlock_bh(&peer->lock); + dst_cache_reset(cache); + + rt = ip_route_output_flow(sock_net(sk), &fl, sk); + } + + if (IS_ERR(rt)) { + ret = PTR_ERR(rt); + net_dbg_ratelimited("%s: no route to host %pISpc: %d\n", + netdev_name(peer->ovpn->dev), + &bind->remote.in4, + ret); + goto err; + } + dst_cache_set_ip4(cache, &rt->dst, fl.saddr); + +transmit: + udp_tunnel_xmit_skb(rt, sk, skb, fl.saddr, fl.daddr, 0, + ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport, + fl.fl4_dport, false, sk->sk_no_check_tx); + ret = 0; +err: + local_bh_enable(); + return ret; +} + +#if IS_ENABLED(CONFIG_IPV6) +/** + * ovpn_udp6_output - send IPv6 packet over udp socket + * @peer: the destination peer + * @bind: the binding related to the destination peer + * @cache: dst cache + * @sk: the socket to send the packet over + * @skb: the packet to send + * + * Return: 0 on success or a negative error code otherwise + */ +static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind, + struct dst_cache *cache, struct sock *sk, + struct sk_buff *skb) +{ + struct dst_entry *dst; + int ret; + + struct flowi6 fl = { + .saddr = bind->local.ipv6, + .daddr = bind->remote.in6.sin6_addr, + .fl6_sport = inet_sk(sk)->inet_sport, + .fl6_dport = bind->remote.in6.sin6_port, + .flowi6_proto = sk->sk_protocol, + .flowi6_mark = sk->sk_mark, + .flowi6_oif = bind->remote.in6.sin6_scope_id, + }; + + local_bh_disable(); + dst = dst_cache_get_ip6(cache, &fl.saddr); + if (dst) + goto transmit; + + if (unlikely(!ipv6_chk_addr(sock_net(sk), &fl.saddr, NULL, 0))) { + /* we may end up here when the cached address is not usable + * anymore. In this case we reset address/cache and perform a + * new look up + */ + fl.saddr = in6addr_any; + spin_lock_bh(&peer->lock); + bind->local.ipv6 = in6addr_any; + spin_unlock_bh(&peer->lock); + dst_cache_reset(cache); + } + + dst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sk), sk, &fl, NULL); + if (IS_ERR(dst)) { + ret = PTR_ERR(dst); + net_dbg_ratelimited("%s: no route to host %pISpc: %d\n", + netdev_name(peer->ovpn->dev), + &bind->remote.in6, ret); + goto err; + } + dst_cache_set_ip6(cache, dst, &fl.saddr); + +transmit: + udp_tunnel6_xmit_skb(dst, sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0, + ip6_dst_hoplimit(dst), 0, fl.fl6_sport, + fl.fl6_dport, udp_get_no_check6_tx(sk)); + ret = 0; +err: + local_bh_enable(); + return ret; +} +#endif + +/** + * ovpn_udp_output - transmit skb using udp-tunnel + * @peer: the destination peer + * @cache: dst cache + * @sk: the socket to send the packet over + * @skb: the packet to send + * + * rcu_read_lock should be held on entry. + * On return, the skb is consumed. + * + * Return: 0 on success or a negative error code otherwise + */ +static int ovpn_udp_output(struct ovpn_peer *peer, struct dst_cache *cache, + struct sock *sk, struct sk_buff *skb) +{ + struct ovpn_bind *bind; + int ret; + + /* set sk to null if skb is already orphaned */ + if (!skb->destructor) + skb->sk = NULL; + + /* always permit openvpn-created packets to be (outside) fragmented */ + skb->ignore_df = 1; + + rcu_read_lock(); + bind = rcu_dereference(peer->bind); + if (unlikely(!bind)) { + net_warn_ratelimited("%s: no bind for remote peer %u\n", + netdev_name(peer->ovpn->dev), peer->id); + goto out; + } + + switch (bind->remote.in4.sin_family) { + case AF_INET: + ret = ovpn_udp4_output(peer, bind, cache, sk, skb); + break; +#if IS_ENABLED(CONFIG_IPV6) + case AF_INET6: + ret = ovpn_udp6_output(peer, bind, cache, sk, skb); + break; +#endif + default: + ret = -EAFNOSUPPORT; + break; + } + +out: + rcu_read_unlock(); + return ret; +} + +/** + * ovpn_udp_send_skb - prepare skb and send it over via UDP + * @peer: the destination peer + * @skb: the packet to send + */ +void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sk_buff *skb) +{ + struct socket *sock; + int ret = -1; + + skb->dev = peer->ovpn->dev; + /* no checksum performed at this layer */ + skb->ip_summed = CHECKSUM_NONE; + + /* get socket info */ + sock = peer->sock->sock; + if (unlikely(!sock)) { + net_warn_ratelimited("%s: no sock for remote peer %u\n", + netdev_name(peer->ovpn->dev), peer->id); + goto out; + } + + /* crypto layer -> transport (UDP) */ + ret = ovpn_udp_output(peer, &peer->dst_cache, sock->sk, skb); +out: + if (unlikely(ret < 0)) { + kfree_skb(skb); + return; + } +} + /** * ovpn_udp_socket_attach - set udp-tunnel CBs on socket and link it to ovpn * @sock: socket to configure diff --git a/drivers/net/ovpn/udp.h b/drivers/net/ovpn/udp.h index 3c48a06f15eed624aec0a2a7b871f0e7f3004137..44ebeb82325dc4d172da7e29fb36f21a5609ea8d 100644 --- a/drivers/net/ovpn/udp.h +++ b/drivers/net/ovpn/udp.h @@ -9,9 +9,14 @@ #ifndef _NET_OVPN_UDP_H_ #define _NET_OVPN_UDP_H_ +#include + +struct ovpn_peer; struct ovpn_priv; struct socket; int ovpn_udp_socket_attach(struct socket *sock, struct ovpn_priv *ovpn); +void ovpn_udp_send_skb(struct ovpn_peer *peer, struct sk_buff *skb); + #endif /* _NET_OVPN_UDP_H_ */ From patchwork Mon Dec 2 15:07:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846794 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (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 51343209F55 for ; Mon, 2 Dec 2024 15:08:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152123; cv=none; b=sJkJsRLryc8XzbFu2TqHjOBFb3wCzndIYW6EhAyUpn/VEag45jLEscg4CW5UPKsbWeCJOwl6UQfCbbaMOx0bE17zfJKYpSIwKvNbCaBmYl6hY+EDDQU1opa8n40moOOSBmBKRmsfuY3ofmy1la7PW8ilpyw3KjY/xf0c19T6ET4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152123; c=relaxed/simple; bh=G/sKpvC+pN1QVKvoA9NeKKOS52U/ihJTetuEhBzEgZo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lB6L//NOHrC+XRGaHRCyOo7VH9M/pVdGT0WMPJGxAnX5rsm/sQNrMzdHJqqv4vmPUj94bLU9oWo3JfMV0qS4d/XPXLYzKZ4xmf5DiwRw0w9qNP1V93Q9kKAmVLTaUZy9DNUOlf+6bLjHZa76B9A+XcN2WRmLUkr0dRM+pBTvpFY= 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=GMzbM0DJ; arc=none smtp.client-ip=209.85.128.41 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="GMzbM0DJ" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-434aa222d96so55372125e9.0 for ; Mon, 02 Dec 2024 07:08:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152119; x=1733756919; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=Ed3qdhTNlfpTcT1xlNMz6yOLAqv5NM8S+TY4RkHBFJc=; b=GMzbM0DJ5wQoxGV6W75BGLyWG/Ad3NG+J//gVuyOZhWUPK9fFl2HO52qZhjmEb9Fqh SpGvtYXqaAfzo8K8jqLY2X2ZQ+EP9aJllgmLKOdjvad8r7+SQM5LrAmuGOMMZVfBBzlW /mC+ytcnE2vkzJFCDpDA2pvAKpcj2apjciVPjTMzWUT7n2hAQZ1A5QA39AGlMOtVwHIN 2ytGjI0xTaudgWe4m4A9WSBW0P2oTHG8EivMaToOZwVLolQZTcZyTCoqQUWDFPdVs3+0 s6tYy/XUrKvwz7P0DW9yC4JrjgiHv8j4Lvl6gCxzvV3/Dv+QoH47skWKxWGxacgpKsJW XAeA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152119; x=1733756919; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Ed3qdhTNlfpTcT1xlNMz6yOLAqv5NM8S+TY4RkHBFJc=; b=ugDH8rRDMVhdlRkzOaoO9znWh4EbhiVRrdZ5SxaiYZ2kABXJ0nSZqTas5krHQVC4ci JvDSDpyNdRQ8+RY4W/cVv29p+X/H18iaelaZJZ9YPGdpQg5N6tI79B2edDomEim8tFF6 Kk/ROsd+SBn0Uix21QzKFatvq8GOU97vP6Bd7fIRgcmd/6qwUkTRP2z6Kha+IZuB11tH R3ifjeUFI+evaVYNk5cddaz23/HSOZlCjXrfIx/NFGHVh+37uoEyeZbq1YCMgG+GH0nx 6BYblzdOnyWgp9/FnAC4vUYsrfQahzPYCBYptFsx+Ae0zRCNvDbFrCjRTTH6SvVhqJrw 2tHg== X-Forwarded-Encrypted: i=1; AJvYcCXOiX2yAABEeACHCu86H+tXdUqUOxcRpbyUHArpDgGHk3U1sWuqdvjgTXXsYCI7Dj0w8a3yZ8xbUsXAMys+rOA=@vger.kernel.org X-Gm-Message-State: AOJu0Yw3XZzXiV0+LRAnGkLnej+jLUZTLGRgh8FYaas3vbM5oXpeX/1l outYanE+T+tIrHFS9nJUg0NJBn+IaDuL91Ln/aMSoq9vtKpCpUFp9n+r6y3YwCg= X-Gm-Gg: ASbGncsf+D23okY2q0HOoJIGuSl6IiL02Z2BmiKFmfHQx8lpALy3VPug0ro0kAI3LrA 8v6CfXlKEap8ehWBVaPb697H73ks7vOGcIPShpVTiJIkbyuQHdXDcg9p3aJpKVkwN/g3V2PcnCi YqN9j8KklHX7lTom2gGgF9/VXaPSN9u3yF8UuAr/GeyyLXyxmJNTbiLmDkKGLjARZ+7wL+mvqx6 4yJVg8MFZjRMFQKJTu+HE/lEuIm4hZT0YifL/TPjsF4SAfKLZJK37qDf6uP X-Google-Smtp-Source: AGHT+IE6y11ldctK7/Urobc+4DON3iIksiLWQ51GAnhQg6usSwWXijxzNS4g+1HbYedBlDz9gWjk0w== X-Received: by 2002:a05:600c:3585:b0:434:a04d:1670 with SMTP id 5b1f17b1804b1-434a9d4f86dmr270066625e9.0.1733152116258; Mon, 02 Dec 2024 07:08:36 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:35 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:28 +0100 Subject: [PATCH net-next v12 10/22] ovpn: store tunnel and transport statistics Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-10-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=7121; i=antonio@openvpn.net; h=from:subject:message-id; bh=G/sKpvC+pN1QVKvoA9NeKKOS52U/ihJTetuEhBzEgZo=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1m5t4p9Slw5VSLLQlkcf/JniIEPD1UNEBqH gQGNfc6f4WJATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZgAKCRALcOU6oDjV hzMBB/9ldD43q1W7gg43YUzqsrVpvxLyaX1aqma8EBP9w1hm3GY92vG8YA6u7oGd869AGgsMP+q XR807zsEKks6IiDWw3+T8qcvnVzw3nUPuQBEvlR334OSZUXf/kdjwwObcHuUXOgq0fuVLzxkbPr WaR8nqTRlrRm/AFWCfjc2XFIosADs90BNZGym3w2CYOVNob62YoB4yKzMcKbucxGF7ACj7Y3rIj w7lJb5OC4GbOfbSHWLxw93RdRP1VKaygOyaTn1xkTPNRG1bNBVOM4zTP0CwsSX7dhJTS0pXQWBa /Uqnw6lrUyVTtj4YifWAmzNTdpt1T+7gJHMG4vxLkhl87nFU X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C Byte/packet counters for in-tunnel and transport streams are now initialized and updated as needed. To be exported via netlink. Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/Makefile | 1 + drivers/net/ovpn/io.c | 12 +++++++++++- drivers/net/ovpn/peer.c | 2 ++ drivers/net/ovpn/peer.h | 5 +++++ drivers/net/ovpn/stats.c | 21 +++++++++++++++++++++ drivers/net/ovpn/stats.h | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 1 deletion(-) diff --git a/drivers/net/ovpn/Makefile b/drivers/net/ovpn/Makefile index ccdaeced1982c851475657860a005ff2b9dfbd13..d43fda72646bdc7644d9a878b56da0a0e5680c98 100644 --- a/drivers/net/ovpn/Makefile +++ b/drivers/net/ovpn/Makefile @@ -17,4 +17,5 @@ ovpn-y += netlink-gen.o ovpn-y += peer.o ovpn-y += pktid.o ovpn-y += socket.o +ovpn-y += stats.o ovpn-y += udp.o diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index ffea3f22dd181381d990c7290adb8a1b3e96f46a..daea55e8f6b459a299941a3368c836542c543c32 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "ovpnstruct.h" #include "peer.h" @@ -56,9 +57,11 @@ static void ovpn_netdev_write(struct ovpn_peer *peer, struct sk_buff *skb) /* cause packet to be "received" by the interface */ pkt_len = skb->len; ret = gro_cells_receive(&peer->ovpn->gro_cells, skb); - if (likely(ret == NET_RX_SUCCESS)) + if (likely(ret == NET_RX_SUCCESS)) { /* update RX stats with the size of decrypted packet */ + ovpn_peer_stats_increment_rx(&peer->vpn_stats, pkt_len); dev_sw_netstats_rx_add(peer->ovpn->dev, pkt_len); + } } void ovpn_decrypt_post(void *data, int ret) @@ -156,6 +159,8 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb) struct ovpn_crypto_key_slot *ks; u8 key_id; + ovpn_peer_stats_increment_rx(&peer->link_stats, skb->len); + /* get the key slot matching the key ID in the received packet */ key_id = ovpn_key_id_from_skb(skb); ks = ovpn_crypto_key_id_to_slot(&peer->crypto, key_id); @@ -177,6 +182,7 @@ void ovpn_encrypt_post(void *data, int ret) struct ovpn_crypto_key_slot *ks; struct sk_buff *skb = data; struct ovpn_peer *peer; + unsigned int orig_len; /* encryption is happening asynchronously. This function will be * called later by the crypto callback with a proper return value @@ -199,6 +205,7 @@ void ovpn_encrypt_post(void *data, int ret) goto err; skb_mark_not_on_list(skb); + orig_len = skb->len; switch (peer->sock->sock->sk->sk_protocol) { case IPPROTO_UDP: @@ -208,6 +215,8 @@ void ovpn_encrypt_post(void *data, int ret) /* no transport configured yet */ goto err; } + + ovpn_peer_stats_increment_tx(&peer->link_stats, orig_len); /* skb passed down the stack - don't free it */ skb = NULL; err: @@ -326,6 +335,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) goto drop; } + ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb->len); ovpn_send(ovpn, skb_list.next, peer); return NETDEV_TX_OK; diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 235850e2129c1aea0e6fb3a14519edb675590349..bc796c4e9f891a032f0766070c3200f4f3915c31 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -47,6 +47,8 @@ struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id) ovpn_crypto_state_init(&peer->crypto); spin_lock_init(&peer->lock); kref_init(&peer->refcount); + ovpn_peer_stats_init(&peer->vpn_stats); + ovpn_peer_stats_init(&peer->link_stats); ret = dst_cache_init(&peer->dst_cache, GFP_KERNEL); if (ret < 0) { diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index 1b427870df2cf972e0f572e046452378358f245a..61c54fb864d990ff3d746f18c9a06d4c950bd1ac 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -13,6 +13,7 @@ #include #include "crypto.h" +#include "stats.h" /** * struct ovpn_peer - the main remote peer object @@ -25,6 +26,8 @@ * @crypto: the crypto configuration (ciphers, keys, etc..) * @dst_cache: cache for dst_entry used to send to peer * @bind: remote peer binding + * @vpn_stats: per-peer in-VPN TX/RX stays + * @link_stats: per-peer link/transport TX/RX stats * @delete_reason: why peer was deleted (i.e. timeout, transport error, ..) * @lock: protects binding to peer (bind) * @refcount: reference counter @@ -42,6 +45,8 @@ struct ovpn_peer { struct ovpn_crypto_state crypto; struct dst_cache dst_cache; struct ovpn_bind __rcu *bind; + struct ovpn_peer_stats vpn_stats; + struct ovpn_peer_stats link_stats; enum ovpn_del_peer_reason delete_reason; spinlock_t lock; /* protects bind */ struct kref refcount; diff --git a/drivers/net/ovpn/stats.c b/drivers/net/ovpn/stats.c new file mode 100644 index 0000000000000000000000000000000000000000..a383842c3449b73694c318837b0b92eb9afaec22 --- /dev/null +++ b/drivers/net/ovpn/stats.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: James Yonan + * Antonio Quartulli + */ + +#include + +#include "stats.h" + +void ovpn_peer_stats_init(struct ovpn_peer_stats *ps) +{ + atomic64_set(&ps->rx.bytes, 0); + atomic64_set(&ps->rx.packets, 0); + + atomic64_set(&ps->tx.bytes, 0); + atomic64_set(&ps->tx.packets, 0); +} diff --git a/drivers/net/ovpn/stats.h b/drivers/net/ovpn/stats.h new file mode 100644 index 0000000000000000000000000000000000000000..868f49d25eaa8fef04a02a61c363d95f9c9ef80a --- /dev/null +++ b/drivers/net/ovpn/stats.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2020-2024 OpenVPN, Inc. + * + * Author: James Yonan + * Antonio Quartulli + * Lev Stipakov + */ + +#ifndef _NET_OVPN_OVPNSTATS_H_ +#define _NET_OVPN_OVPNSTATS_H_ + +/* one stat */ +struct ovpn_peer_stat { + atomic64_t bytes; + atomic64_t packets; +}; + +/* rx and tx stats combined */ +struct ovpn_peer_stats { + struct ovpn_peer_stat rx; + struct ovpn_peer_stat tx; +}; + +void ovpn_peer_stats_init(struct ovpn_peer_stats *ps); + +static inline void ovpn_peer_stats_increment(struct ovpn_peer_stat *stat, + const unsigned int n) +{ + atomic64_add(n, &stat->bytes); + atomic64_inc(&stat->packets); +} + +static inline void ovpn_peer_stats_increment_rx(struct ovpn_peer_stats *stats, + const unsigned int n) +{ + ovpn_peer_stats_increment(&stats->rx, n); +} + +static inline void ovpn_peer_stats_increment_tx(struct ovpn_peer_stats *stats, + const unsigned int n) +{ + ovpn_peer_stats_increment(&stats->tx, n); +} + +#endif /* _NET_OVPN_OVPNSTATS_H_ */ From patchwork Mon Dec 2 15:07:30 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846793 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (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 7E18F20A5DA for ; Mon, 2 Dec 2024 15:08:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152127; cv=none; b=A+cA0WpkXnYv29GkaUCd1B59MQkNXeXsL10TSTuVoyfbWlGd6rWVw4GNcnNRjWGk452TtOLs0lsJxHl0tCXoTt4+eXbW2QeNVuROPu44C74oX9kqmU2jyq/tWq/y3u9P/CYprrQzDhzWcSdIZUSqf6D8zYpf99nVsANoJADm9ok= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152127; c=relaxed/simple; bh=kuVUfCIE7So1MZe83U3UjEJzAGoG+bgVJeF9bW8NnbE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=WjBZJ8FXdAt4ZXqkHiuA8CiQ800DqUJclUQyML3LK82E9ZzdfvBxgAgotgssz58btX2ZybdbJGRx5PrANBIoWGWMt2dGl6TntZel/0+oxN3t5NMHilJXPvrkBZ+qI46eZktv6LrIfYf1lzTf2KMr29HRqBs3zNI/UZFIOQukABE= 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=bzzljLID; arc=none smtp.client-ip=209.85.128.41 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="bzzljLID" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-434ab114753so36518785e9.0 for ; Mon, 02 Dec 2024 07:08:41 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152120; x=1733756920; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=rHQSY29oIA1oIlYajzPOTSBoqnGHOeFMy68vHFwPjZo=; b=bzzljLID+ftm4c+wCP2LHUn6VnnGcAI+0gsUDJq45SQ3mUCqP2wqkgGZyBIINtL9RX RO/XGqknms0+bpUR406wzwznjzhBg2qoF8qkU43j9+bFqkI+eAlKqgwyeP/iUpHdjkEN I5Ml83Q+5eFxVjxcN3fudF7Mxar54X8ut+jlGkR/Ij9v8deeGTOx2to/PLZYThWqDPlx hkqipYnAE/EbWkEvDo7Syv2OcnBbuFevow5/tYCO4sSSjcWL6/fIzqaxkX9pwwycDvuJ nMuI4NMUKi8kfXbFiKimh6XEeFckYyaKNZDkfv3V1W4CHQkT+XkU5JD3Ai6LotrZQh/m otEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152120; x=1733756920; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rHQSY29oIA1oIlYajzPOTSBoqnGHOeFMy68vHFwPjZo=; b=npih/EaM3/z09E+tiKadqg3/uZPHYMHDoVbkX3gBqmx+Z2LKmOofKvmta6/S82Yj5c z5qTEAI1qVAQlzVZkvuYdaCbSs0TXSaujmhew8wpQgkMDJrs3Lp+CrfyjAOekvaoalRo FlSeaFo/qxFOAyE3Ua+Yoe4eoHrAJiRInCxmAPfVU4mPycLsJOvDkGlxlI0JrXsebKcv F6Sn3/IOWFvY7dDScGEQ8nrQEH4jOhD9gc5QKVXANDI3gV0rP35poowAKjcPwF0Z8Y9b X66NpSfFmG9rpvtfyA4UGy+y/wWK0b2uCfUBWKOcq+vbxfsIkRrVghUsgsbu+9dOWPBp kicg== X-Forwarded-Encrypted: i=1; AJvYcCWdtGdZahVXQMfhdLlabf7HMjXY6q6ehLlfhIQcv0264BazDkvyN+vwH+huUm5Wg4S77g4zXN+X0PyJKCUArmI=@vger.kernel.org X-Gm-Message-State: AOJu0YzQhrFHqd028V+/N8q/twa/cJ2iDTVtWEi6sZSSnr82RgLcSRJn RJ64aIOsXLFR+asv5SNzFfnTIlKd1X9P/ufZcbuJOnQ6mcnYMsHKeOWYUGy/tFc= X-Gm-Gg: ASbGncu3fhV+GoebCIdyQgQ94b5H1ogSZR2yhEC9P/Aexg+N5nkryRIAIin6VOthVAy 3mrbO5kTVcdUFo9V2RaH45hTjr3ZLlJeAEDsZYpVQqIhRv5T+/0KpvJnWoquPsdCpJHKDwV9a8k esFlRJ/oSM3UbQ4nT7+U1xob7RsI8729ir9rbXHhfLiy5IbgQ2azSGE+DFZBqYOPgNL+BdPCLhC HeomhyEjXoZhGJQIXB1h8kb96kgchQOLxdfNe39iuX5KAWihz+zDaGufTND X-Google-Smtp-Source: AGHT+IElXS5SroNreUG/Olxo++oiArhEPUbSBjod5nGAdSXDGomIseFUvx34xv63xl8vAxWJsrmSKQ== X-Received: by 2002:a5d:47cc:0:b0:385:f47a:e9d1 with SMTP id ffacd0b85a97d-385f47aed3dmr2827151f8f.17.1733152118732; Mon, 02 Dec 2024 07:08:38 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.37 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:38 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:30 +0100 Subject: [PATCH net-next v12 12/22] ovpn: implement multi-peer support Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-12-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=13763; i=antonio@openvpn.net; h=from:subject:message-id; bh=kuVUfCIE7So1MZe83U3UjEJzAGoG+bgVJeF9bW8NnbE=; b=owGbwMvMwMHIXfDUaoHF1XbG02pJDOm+Z9MYUi303NO2b/UQnj9dIZtP4YbeEsMM42bm5sO51 gtd72R0MhqzMDByMMiKKbLMXH0n58cVoSf34g/8gRnEygQ2hYtTACaiK8P+T0ck8KPctKeLXtem /5aax/9+6rO+Se8CPysrSbZwy/wymRGU/Ge9cWly1uu9AdvWrvVebbRrg1EXQ+megAefS1dmV2/ 8diiddUPY0x8f/86Ma90n+i7m0kKed0eY7Rf0idUpbFTuTlX+YBRr1ts/fUa0/IUPi/x2sz8S6W K5fTE3br3sihl5y3b6Fe5r/BNd/PTlOmcWpVx5tosbmsJDpx2eYjvTzc+5lC+1YOUNJou8wLLzD kZyXWmSr62vW9h0/Vl0UkGlYMn8NaI++bOP+MS7lm66Yv3ddndya3PdrCcrXQ5tabYtj/uXeamv 0qrddJW80eLvfPPrHtW+9PF35cpacujW8Xre9pJm16+aAA== X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C With this change an ovpn instance will be able to stay connected to multiple remote endpoints. This functionality is strictly required when running ovpn on an OpenVPN server. Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/main.c | 67 +++++++++++++++- drivers/net/ovpn/ovpnstruct.h | 16 ++++ drivers/net/ovpn/peer.c | 173 ++++++++++++++++++++++++++++++++++++++++-- drivers/net/ovpn/peer.h | 9 +++ 4 files changed, 256 insertions(+), 9 deletions(-) diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index b09e98080737cbb6c446d00cfaad6d2e0c716327..bd0d791cf9ccad7563f89e96b9c443d52b34e8bf 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -24,6 +24,13 @@ #include "proto.h" #include "tcp.h" +static void ovpn_priv_free(struct net_device *net) +{ + struct ovpn_priv *ovpn = netdev_priv(net); + + kfree(ovpn->peers); +} + static int ovpn_net_init(struct net_device *dev) { struct ovpn_priv *ovpn = netdev_priv(dev); @@ -99,6 +106,8 @@ static void ovpn_setup(struct net_device *dev) dev->netdev_ops = &ovpn_netdev_ops; + dev->priv_destructor = ovpn_priv_free; + dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = ETH_DATA_LEN - OVPN_HEAD_ROOM; @@ -120,12 +129,50 @@ static void ovpn_setup(struct net_device *dev) SET_NETDEV_DEVTYPE(dev, &ovpn_type); } +static int ovpn_mp_alloc(struct ovpn_priv *ovpn) +{ + struct in_device *dev_v4; + int i; + + if (ovpn->mode != OVPN_MODE_MP) + return 0; + + dev_v4 = __in_dev_get_rtnl(ovpn->dev); + if (dev_v4) { + /* disable redirects as Linux gets confused by ovpn + * handling same-LAN routing. + * This happens because a multipeer interface is used as + * relay point between hosts in the same subnet, while + * in a classic LAN this would not be needed because the + * two hosts would be able to talk directly. + */ + IN_DEV_CONF_SET(dev_v4, SEND_REDIRECTS, false); + IPV4_DEVCONF_ALL(dev_net(ovpn->dev), SEND_REDIRECTS) = false; + } + + /* the peer container is fairly large, therefore we allocate it only in + * MP mode + */ + ovpn->peers = kzalloc(sizeof(*ovpn->peers), GFP_KERNEL); + if (!ovpn->peers) + return -ENOMEM; + + for (i = 0; i < ARRAY_SIZE(ovpn->peers->by_id); i++) { + INIT_HLIST_HEAD(&ovpn->peers->by_id[i]); + INIT_HLIST_NULLS_HEAD(&ovpn->peers->by_vpn_addr[i], i); + INIT_HLIST_NULLS_HEAD(&ovpn->peers->by_transp_addr[i], i); + } + + return 0; +} + static int ovpn_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[], struct netlink_ext_ack *extack) { struct ovpn_priv *ovpn = netdev_priv(dev); enum ovpn_mode mode = OVPN_MODE_P2P; + int err; if (data && data[IFLA_OVPN_MODE]) { mode = nla_get_u8(data[IFLA_OVPN_MODE]); @@ -136,6 +183,10 @@ static int ovpn_newlink(struct net *src_net, struct net_device *dev, ovpn->mode = mode; spin_lock_init(&ovpn->lock); + err = ovpn_mp_alloc(ovpn); + if (err < 0) + return err; + /* turn carrier explicitly off after registration, this way state is * clearly defined */ @@ -184,14 +235,26 @@ static int ovpn_netdev_notifier_call(struct notifier_block *nb, netif_carrier_off(dev); ovpn->registered = false; - if (ovpn->mode == OVPN_MODE_P2P) + switch (ovpn->mode) { + case OVPN_MODE_P2P: ovpn_peer_release_p2p(ovpn, OVPN_DEL_PEER_REASON_TEARDOWN); + break; + case OVPN_MODE_MP: + ovpn_peers_free(ovpn, OVPN_DEL_PEER_REASON_TEARDOWN); + break; + } break; case NETDEV_DOWN: - if (ovpn->mode == OVPN_MODE_P2P) + switch (ovpn->mode) { + case OVPN_MODE_P2P: ovpn_peer_release_p2p(ovpn, OVPN_DEL_PEER_REASON_ADMINDOWN); + break; + case OVPN_MODE_MP: + ovpn_peers_free(ovpn, OVPN_DEL_PEER_REASON_ADMINDOWN); + break; + } break; case NETDEV_POST_INIT: case NETDEV_GOING_DOWN: diff --git a/drivers/net/ovpn/ovpnstruct.h b/drivers/net/ovpn/ovpnstruct.h index 7af1f21bb5a76acb34269693bcba5ce8f832137f..bca13e8e4439c2f217ae17896f114347e8aefd06 100644 --- a/drivers/net/ovpn/ovpnstruct.h +++ b/drivers/net/ovpn/ovpnstruct.h @@ -16,6 +16,20 @@ #include #include +/** + * struct ovpn_peer_collection - container of peers for MultiPeer mode + * @by_id: table of peers index by ID + * @by_vpn_addr: table of peers indexed by VPN IP address (items can be + * rehashed on the fly due to peer IP change) + * @by_transp_addr: table of peers indexed by transport address (items can be + * rehashed on the fly due to peer IP change) + */ +struct ovpn_peer_collection { + DECLARE_HASHTABLE(by_id, 12); + struct hlist_nulls_head by_vpn_addr[1 << 12]; + struct hlist_nulls_head by_transp_addr[1 << 12]; +}; + /** * struct ovpn_priv - per ovpn interface state * @dev: the actual netdev representing the tunnel @@ -23,6 +37,7 @@ * @registered: whether dev is still registered with netdev or not * @mode: device operation mode (i.e. p2p, mp, ..) * @lock: protect this object + * @peers: data structures holding multi-peer references * @peer: in P2P mode, this is the only remote peer * @gro_cells: pointer to the Generic Receive Offload cell */ @@ -32,6 +47,7 @@ struct ovpn_priv { bool registered; enum ovpn_mode mode; spinlock_t lock; /* protect writing to the ovpn_priv object */ + struct ovpn_peer_collection *peers; struct ovpn_peer __rcu *peer; struct gro_cells gro_cells; }; diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index bc796c4e9f891a032f0766070c3200f4f3915c31..155b8571467274e068bbe30ce199667c4b58717d 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -9,6 +9,7 @@ #include #include +#include #include "ovpnstruct.h" #include "bind.h" @@ -319,6 +320,89 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb, return match; } +#define ovpn_get_hash_head(_tbl, _key, _key_len) ({ \ + typeof(_tbl) *__tbl = &(_tbl); \ + (&(*__tbl)[jhash(_key, _key_len, 0) % HASH_SIZE(*__tbl)]); }) \ + +/** + * ovpn_peer_add_mp - add peer to related tables in a MP instance + * @ovpn: the instance to add the peer to + * @peer: the peer to add + * + * Return: 0 on success or a negative error code otherwise + */ +static int ovpn_peer_add_mp(struct ovpn_priv *ovpn, struct ovpn_peer *peer) +{ + struct sockaddr_storage sa = { 0 }; + struct hlist_nulls_head *nhead; + struct sockaddr_in6 *sa6; + struct sockaddr_in *sa4; + struct ovpn_bind *bind; + struct ovpn_peer *tmp; + size_t salen; + int ret = 0; + + spin_lock_bh(&ovpn->lock); + /* do not add duplicates */ + tmp = ovpn_peer_get_by_id(ovpn, peer->id); + if (tmp) { + ovpn_peer_put(tmp); + ret = -EEXIST; + goto out; + } + + bind = rcu_dereference_protected(peer->bind, true); + /* peers connected via TCP have bind == NULL */ + if (bind) { + switch (bind->remote.in4.sin_family) { + case AF_INET: + sa4 = (struct sockaddr_in *)&sa; + + sa4->sin_family = AF_INET; + sa4->sin_addr.s_addr = bind->remote.in4.sin_addr.s_addr; + sa4->sin_port = bind->remote.in4.sin_port; + salen = sizeof(*sa4); + break; + case AF_INET6: + sa6 = (struct sockaddr_in6 *)&sa; + + sa6->sin6_family = AF_INET6; + sa6->sin6_addr = bind->remote.in6.sin6_addr; + sa6->sin6_port = bind->remote.in6.sin6_port; + salen = sizeof(*sa6); + break; + default: + ret = -EPROTONOSUPPORT; + goto out; + } + + nhead = ovpn_get_hash_head(ovpn->peers->by_transp_addr, &sa, + salen); + hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead); + } + + hlist_add_head_rcu(&peer->hash_entry_id, + ovpn_get_hash_head(ovpn->peers->by_id, &peer->id, + sizeof(peer->id))); + + if (peer->vpn_addrs.ipv4.s_addr != htonl(INADDR_ANY)) { + nhead = ovpn_get_hash_head(ovpn->peers->by_vpn_addr, + &peer->vpn_addrs.ipv4, + sizeof(peer->vpn_addrs.ipv4)); + hlist_nulls_add_head_rcu(&peer->hash_entry_addr4, nhead); + } + + if (!ipv6_addr_any(&peer->vpn_addrs.ipv6)) { + nhead = ovpn_get_hash_head(ovpn->peers->by_vpn_addr, + &peer->vpn_addrs.ipv6, + sizeof(peer->vpn_addrs.ipv6)); + hlist_nulls_add_head_rcu(&peer->hash_entry_addr6, nhead); + } +out: + spin_unlock_bh(&ovpn->lock); + return ret; +} + /** * ovpn_peer_add_p2p - add peer to related tables in a P2P instance * @ovpn: the instance to add the peer to @@ -361,17 +445,42 @@ static int ovpn_peer_add_p2p(struct ovpn_priv *ovpn, struct ovpn_peer *peer) int ovpn_peer_add(struct ovpn_priv *ovpn, struct ovpn_peer *peer) { switch (ovpn->mode) { + case OVPN_MODE_MP: + return ovpn_peer_add_mp(ovpn, peer); case OVPN_MODE_P2P: return ovpn_peer_add_p2p(ovpn, peer); - default: - return -EOPNOTSUPP; } + + return -EOPNOTSUPP; +} + +/** + * ovpn_peer_unhash - remove peer reference from all hashtables + * @peer: the peer to remove + * @reason: the delete reason to attach to the peer + */ +static void ovpn_peer_unhash(struct ovpn_peer *peer, + enum ovpn_del_peer_reason reason) +{ + lockdep_assert_held(&peer->ovpn->lock); + + hlist_del_init_rcu(&peer->hash_entry_id); + + hlist_nulls_del_init_rcu(&peer->hash_entry_addr4); + hlist_nulls_del_init_rcu(&peer->hash_entry_addr6); + hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr); + + ovpn_peer_put(peer); + peer->delete_reason = reason; } static void ovpn_peer_remove(struct ovpn_peer *peer, enum ovpn_del_peer_reason reason) { switch (peer->ovpn->mode) { + case OVPN_MODE_MP: + ovpn_peer_unhash(peer, reason); + break; case OVPN_MODE_P2P: RCU_INIT_POINTER(peer->ovpn->peer, NULL); /* in P2P mode the carrier is switched off when the peer is @@ -379,8 +488,6 @@ static void ovpn_peer_remove(struct ovpn_peer *peer, */ netif_carrier_off(peer->ovpn->dev); break; - default: - return; } peer->delete_reason = reason; @@ -391,6 +498,33 @@ static void ovpn_peer_remove(struct ovpn_peer *peer, ovpn_peer_put(peer); } +/** + * ovpn_peer_del_mp - delete peer from related tables in a MP 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_mp(struct ovpn_peer *peer, + enum ovpn_del_peer_reason reason) +{ + struct ovpn_peer *tmp; + int ret = -ENOENT; + + lockdep_assert_held(&peer->ovpn->lock); + + tmp = ovpn_peer_get_by_id(peer->ovpn, peer->id); + if (tmp == peer) { + ovpn_peer_remove(peer, reason); + ret = 0; + } + + if (tmp) + ovpn_peer_put(tmp); + + return ret; +} + /** * ovpn_peer_del_p2p - delete peer from related tables in a P2P instance * @peer: the peer to delete @@ -447,10 +581,35 @@ void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, */ int ovpn_peer_del(struct ovpn_peer *peer, enum ovpn_del_peer_reason reason) { + int ret = -EOPNOTSUPP; + + spin_lock_bh(&peer->ovpn->lock); switch (peer->ovpn->mode) { + case OVPN_MODE_MP: + ret = ovpn_peer_del_mp(peer, reason); + break; case OVPN_MODE_P2P: - return ovpn_peer_del_p2p(peer, reason); - default: - return -EOPNOTSUPP; + ret = ovpn_peer_del_p2p(peer, reason); + break; } + spin_unlock_bh(&peer->ovpn->lock); + return ret; +} + +/** + * ovpn_peers_free - free all peers in the instance + * @ovpn: the instance whose peers should be released + * @reason: the reason for releasing all peers + */ +void ovpn_peers_free(struct ovpn_priv *ovpn, + enum ovpn_del_peer_reason reason) +{ + struct hlist_node *tmp; + struct ovpn_peer *peer; + int bkt; + + spin_lock_bh(&ovpn->lock); + hash_for_each_safe(ovpn->peers->by_id, bkt, tmp, peer, hash_entry_id) + ovpn_peer_remove(peer, reason); + spin_unlock_bh(&ovpn->lock); } diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index 02e7e53792dcd69fb3d8371e9a447c6dc7aef016..636245521f9502ce9139affd7b90d3ba918d1ea6 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -23,6 +23,10 @@ * @vpn_addrs: IP addresses assigned over the tunnel * @vpn_addrs.ipv4: IPv4 assigned to peer on the tunnel * @vpn_addrs.ipv6: IPv6 assigned to peer on the tunnel + * @hash_entry_id: entry in the peer ID hashtable + * @hash_entry_addr4: entry in the peer IPv4 hashtable + * @hash_entry_addr6: entry in the peer IPv6 hashtable + * @hash_entry_transp_addr: entry in the peer transport address hashtable * @sock: the socket being used to talk to this peer * @tcp: keeps track of TCP specific state * @tcp.strp: stream parser context (TCP only) @@ -55,6 +59,10 @@ struct ovpn_peer { struct in_addr ipv4; struct in6_addr ipv6; } vpn_addrs; + struct hlist_node hash_entry_id; + struct hlist_nulls_node hash_entry_addr4; + struct hlist_nulls_node hash_entry_addr6; + struct hlist_nulls_node hash_entry_transp_addr; struct ovpn_socket *sock; /* state of the TCP reading. Needed to keep track of how much of a @@ -120,6 +128,7 @@ int ovpn_peer_add(struct ovpn_priv *ovpn, struct ovpn_peer *peer); int ovpn_peer_del(struct ovpn_peer *peer, enum ovpn_del_peer_reason reason); void ovpn_peer_release_p2p(struct ovpn_priv *ovpn, enum ovpn_del_peer_reason reason); +void ovpn_peers_free(struct ovpn_priv *ovpn, enum ovpn_del_peer_reason reason); struct ovpn_peer *ovpn_peer_get_by_transp_addr(struct ovpn_priv *ovpn, struct sk_buff *skb); From patchwork Mon Dec 2 15:07:33 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846792 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (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 1D03F204F9E for ; Mon, 2 Dec 2024 15:08:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152129; cv=none; b=MZLd8xcnhd+Jll+MZh6cJPv1ebdamNORu3TVXE/98ofUJD7DbkRuArEq/NM/qPKAB+f1+/4JU0uVoQ9pED1RbZtLF/Rub29AE+mftlw6Z1pqbVvPdtzoyH/804MW3p8foZMzj8rlfn2kHcadTgacjsiNKhugMa74DSC2wHZxnWU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152129; c=relaxed/simple; bh=OdBK3/xyCzwJOGcy6CtLEeb8qE/dLS0KYlWLU1j8sLQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sleNJZHQLVh2HorILL5eo0MzPzbOgohVtxeFwD3+YCdAIPIAl13bEVaNJh0A9gRLxYTddQQKWu2NNXFlsNZYJteF5VB71gDlPwvrdnxsdjZjWIUV9RybW79nxO/VOxXobEZmfLpVTGHU03oWvnsN2RytvzmlNBwJX0Raiex9RvU= 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=P0S7yx7P; arc=none smtp.client-ip=209.85.221.45 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="P0S7yx7P" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-385eaecc213so864621f8f.1 for ; Mon, 02 Dec 2024 07:08:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152124; x=1733756924; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=EbJeURYFV+XkEUFvZdxRbKGSWDfB1xJgrN1rw3Dvxsw=; b=P0S7yx7PXHy+6olFsqhXOq2wHtk/XbhmBIIF1sFDgQ3OTTzRnQIdrj1bA3QOGED+ou eHqH78KCcIL0PCbhPdql28kYCkSyM4xUpQlVaGEykmzK++EMFwp59h/LkPkhO6qOU2mB lK/LiXpZQhRjgQlmjPXqKcNsBS/V2xs3y79aoA+iZjgHMtifAFqswPQGaFt0sGWhC8Nn /x02iioolSl9nRVyOYxkQB6h4hVohX80hNgUaZYJY+/LaaLFVdS3FajkjZ+Hxa6MYaOX 28Bcjaia45iS4eEvqTnn1yGAn70vkkj6OPjsyfuPyJ1FAUQuE3WD9sJqylW46aXLZKvg Nt5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152124; x=1733756924; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=EbJeURYFV+XkEUFvZdxRbKGSWDfB1xJgrN1rw3Dvxsw=; b=u9R+sh7suEwkf1Jmkxa9n6weIA1GZZX2sK8rEnfoVXX8iL5YNgsGGrsJo+RsX/OOR7 iAT5P7aqobfzWk76L4Byf6GJ33y17xxoktGG5J/Lre34ibuhAfDR9XuUOwhtejTD2jye nW++5vCq3A/lUiKvPm/pRlAgv7loiDCn8EW8m0UKJOEVo4g/ylWuaY3KTGwxcFy1bwOO cOBPL9+IaEcYJyM8xDTxD8gYAIZl8f5XbW9b5AYT0Xfmb9O2dSXoaKCdxL05mVCbdj3x CRcjG6uPvtcewNt9iW8ymtuFP/poHdSq75PrbTTGPH3PuFl44r9ASbAKmaWTiXYV31PB f99Q== X-Forwarded-Encrypted: i=1; AJvYcCUsL44sqRWh3qmS6Hg8rplT92rfyIhibRQsbuOiXIYf7DHkJjON6HMwHjANDgo5TdvymHFPi7mVXwhFgW8+d2M=@vger.kernel.org X-Gm-Message-State: AOJu0YzGs82S+l/AIsljHa0Q7iCSIVOxi0PXTimjxsEMoNCXg7So5vxU vNX7W4B0jcFcR/EXkeR8Vxh6ZbXERvV21pryHZChhdFnDufdz4aPBzVzeLhPgB0= X-Gm-Gg: ASbGncumjhCMQo5pJOW4PdF+52QAuO3DC4YsjsNEzapwlaWKtnSKcPbUaxN0UxwiVHy 2eb/tDcwE2NVx2uOV8RykeGTGX0RLl8OCuhau7UDoQGF9O5Ngac8ku1Yl5LcoiiMRdFuV+b3g9q 02m78bfSqmbJwWRyrtnwW7Cn6wPMXWQi5dPZGTwfERfPjpODsG9+HDGjAu4wfjU5KeQTpKhMu9Q MDc0sZqfehWMTjtIEdfSAJg2+R7i0luO6gIOjR3jluWl/hbJ3jZeCMMhYiz X-Google-Smtp-Source: AGHT+IH1E/+inXI9G80H+Nd0qWm2j6ypaYNjfd6tduQbE3k8llS2CkzbbKiYOR6WfsjUtPTr4KGMZg== X-Received: by 2002:a5d:47cc:0:b0:385:ee61:b9ba with SMTP id ffacd0b85a97d-385ee61bbf9mr5680417f8f.22.1733152122800; Mon, 02 Dec 2024 07:08:42 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:42 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:33 +0100 Subject: [PATCH net-next v12 15/22] ovpn: add support for updating local UDP endpoint Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-15-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=2818; i=antonio@openvpn.net; h=from:subject:message-id; bh=OdBK3/xyCzwJOGcy6CtLEeb8qE/dLS0KYlWLU1j8sLQ=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1ng3eOnJxyjaRxKBFcUAzY+47IQmoFfMXCl GNfENE3N9iJATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZwAKCRALcOU6oDjV hxagB/42JJCU7vmJoSsY1aHvxhriTLKmiE8KmAC3YtjvCXXtyrMYfPhujWKaVI7ATgsemFpZy1X lW9B97irOl0mt8J9D848c+nZyZNpnIwpLS184vtcAGzGRvWNwUpPCG5Z59ZbYgw0rLtG8uPK4Fr WYoVxYkDVTVSjCGwq12kyt3F3iQT6Cb/n/AqJomf/9Ju393dm5LltAQCzTtO/cecoJnXXbWVUn+ KOgSwS9a5b36+h0P1HXF0ik67MLq6lZY45z+Z8R8Gm1USu/YXv429dHe1PUlTsGau2ltctqqo2t LIoJObk92x5/QE1/8uMjakm9tm2LKYGiF1optJdR55RndkaM X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C In case of UDP links, the local endpoint used to communicate with a given peer may change without a connection restart. Add support for learning the new address in case of change. Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/peer.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ drivers/net/ovpn/peer.h | 3 +++ 2 files changed, 48 insertions(+) diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 606a5c538d7918148dbb647d5e111d94f5759506..7df9fedd593a74e2349922557ce299a0fcf03038 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -450,6 +450,51 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id) return peer; } +/** + * ovpn_peer_update_local_endpoint - update local endpoint for peer + * @peer: peer to update the endpoint for + * @skb: incoming packet to retrieve the destination address (local) from + */ +void ovpn_peer_update_local_endpoint(struct ovpn_peer *peer, + struct sk_buff *skb) +{ + struct ovpn_bind *bind; + + rcu_read_lock(); + bind = rcu_dereference(peer->bind); + if (unlikely(!bind)) + goto unlock; + + spin_lock_bh(&peer->lock); + switch (skb->protocol) { + case htons(ETH_P_IP): + if (unlikely(bind->local.ipv4.s_addr != ip_hdr(skb)->daddr)) { + net_dbg_ratelimited("%s: learning local IPv4 for peer %d (%pI4 -> %pI4)\n", + netdev_name(peer->ovpn->dev), + peer->id, &bind->local.ipv4.s_addr, + &ip_hdr(skb)->daddr); + bind->local.ipv4.s_addr = ip_hdr(skb)->daddr; + } + break; + case htons(ETH_P_IPV6): + if (unlikely(!ipv6_addr_equal(&bind->local.ipv6, + &ipv6_hdr(skb)->daddr))) { + net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c\n", + netdev_name(peer->ovpn->dev), + peer->id, &bind->local.ipv6, + &ipv6_hdr(skb)->daddr); + bind->local.ipv6 = ipv6_hdr(skb)->daddr; + } + break; + default: + break; + } + spin_unlock_bh(&peer->lock); + +unlock: + rcu_read_unlock(); +} + /** * ovpn_peer_get_by_dst - Lookup peer to send skb to * @ovpn: the private data representing the current VPN session diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index bbaabc73218948e3597dbc567a19b0a5823e32ff..196fa0a04f2db1986fffa6d51b42b68c9837c8e8 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -153,4 +153,7 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb, void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout); void ovpn_peer_keepalive_work(struct work_struct *work); +void ovpn_peer_update_local_endpoint(struct ovpn_peer *peer, + struct sk_buff *skb); + #endif /* _NET_OVPN_OVPNPEER_H_ */ From patchwork Mon Dec 2 15:07:34 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846791 Received: from mail-wm1-f44.google.com (mail-wm1-f44.google.com [209.85.128.44]) (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 EF1E320B7F4 for ; Mon, 2 Dec 2024 15:08:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152132; cv=none; b=nrNR8KHetVRWF9GVLzdbx+SAUc9vMbjfnH6Xqh2b8ykMUhMO9uIY4ioNujKpWBElYbqC0mlJwjQM3wIwfLsR/yXiVyx0wN12LJnO7auz9anOySpIWjbf6bxGObhCv5ZnpwFx3GRSdEPnCHQi+Q4sCMAAoO+v2JQGeUi59lMXDw0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152132; c=relaxed/simple; bh=2qIz2p0fw0aYKbtD0sIQmGm8WFwVQ83diG3BR3Bkayw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dzYUleaCnH4VO1Vc60bEMGEmdgV3mATovSYjUXBDr807qPy3zyd837omxSWGK8hWPy7v2JddDUCv4alRRA7dJaT89IuTtSF143ed+FYJdjpqymTeOecegZVKyBIeraIklWnE5mojtnyZ15aLPJVfTi0i++1gmK0qVOJbi37GvPI= 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=FN3AD5/r; arc=none smtp.client-ip=209.85.128.44 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="FN3AD5/r" Received: by mail-wm1-f44.google.com with SMTP id 5b1f17b1804b1-434a10588f3so27938855e9.1 for ; Mon, 02 Dec 2024 07:08:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152127; x=1733756927; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=ggaE+5wPjKoAPNX3M2/uy1Q8P5VYEq4W790qDE/hRZ4=; b=FN3AD5/rXZZy6pbg2EjNbUuS7YtP5skm9zCHdosYcFfBkpkNghwLzn21Pw7RYp+yeH FoWSjXfGONyUn1zKM7QoeRJVmmtKeQMykYNJfb2aeTPzj/R7S8BKATQb/GX5aRoANStx fHTW13ii33N5RG4HxH+biiHcDMBuFwJabtoi4k+QVZRm9nOj5ybbuUZdg/C8b+DZRuMo QfO0NL0RgXDePU0jS+7sJXqn9BMXpH2lxn7VBBstj4BXhS0ImKUW20GKaiaYLDLfqfD2 fNTiG0xMKsIheJClAVrfKO2KPjoQDnUENkwYDRQPhGa1xokEefQOPVd67rNhpwajvfVv 5buQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152127; x=1733756927; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ggaE+5wPjKoAPNX3M2/uy1Q8P5VYEq4W790qDE/hRZ4=; b=K14qElrovR4blu76/P7tVPpLJ2vo6UP4/82ew3pRlN8mLi3DL/vpFQ5yKJdtBIiiAC 1f7ODLMat7FxG9ynnhDc8b2JeumnWCqZqaLSyJU+yhAtfBkLg/ITmsk30kfHJxPpZAvT 0sUpwnA53g8vxVVCfP60j9wNiIpv3azQLt2xC/6ejT5HoEGlAl03iz8SIt+C3zz4LtKc Z+wlC6KpO/JWrg8pmbvl2dTEesjz/QQbyuXDrgoCRWvz/mxeTPwuMD/JCjyKbXRmtxKx PZNkwG0o6Xo59XoQaRPqobZwIZ+sfpJ0t8Wk5zOMyKF/93/GXoq0hbMf08movcNIKFVB g4cQ== X-Forwarded-Encrypted: i=1; AJvYcCUEH6m6uH4ZZBRDbzvEU5yzytK591L6E4kzAnNUrdwEk82Y+FP/LwRCBTBXGlErD17atScCte5OI0dHw3G3gPc=@vger.kernel.org X-Gm-Message-State: AOJu0YwIDz/Ib6MRVo00jnNs8XYQamwXY+rnooBQmbosC6Vwo/Hj3vIp 6HB/55hNdSyZdzFrn5aKke86tongEQmg23ztEUr1c2hRTf88h2MG9WeRNeLKYvQ= X-Gm-Gg: ASbGncvsCpuy2DuSnE067LmDAViZCvbTojhkhukWFfC8UbL6ppa2F1l8jPAazSnlhii NUID8XhRK6YztyLb9C+r72Kfdg3z7Tn09JVaa6EnIx3Qx3POKPNguWiQFZnqxCFWUxl2FIiaWvB 5wLUkjhlvWmirAzVkmcLUASML21Sa9K4DQhC6i1FBqILM+IXW9S92alpHlWAyXeUMJWcC1NhB59 atkOi8bTaVsmTru0wGANeUTx67p5H8lhw1CSnm3k9/Dey47EQ8etvpvS9fY X-Google-Smtp-Source: AGHT+IGxU/XR/Upr3Ab3tRhInXYUac1ex6IqqewbVOYRCK/zO7zwNTyK13wjuJmQxIQzGY92MKeCDQ== X-Received: by 2002:a05:600c:4fcf:b0:431:60ec:7a91 with SMTP id 5b1f17b1804b1-434a9dbbd8amr215126495e9.2.1733152123969; Mon, 02 Dec 2024 07:08:43 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:43 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:34 +0100 Subject: [PATCH net-next v12 16/22] ovpn: add support for peer floating Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-16-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=10598; i=antonio@openvpn.net; h=from:subject:message-id; bh=2qIz2p0fw0aYKbtD0sIQmGm8WFwVQ83diG3BR3Bkayw=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1neKSW/LerriMkWx6f0I6646POr/Gp3GkM/ /La6SOLQ32JATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZwAKCRALcOU6oDjV h9iKB/9uH09Orsfl/Md5gU4hmP0SEEOUPSnsCqOiGqKBuomIGpfNtYd+K/0WEQgx6a5etHAn6NH Z7dDO1lj1Tncz+vRkS6bcAPc84K/XJm9gw3+yK1U/f4tz2J+G9tJKZqpzHAwm0PHEmQF0VYMndw sFHFKat73UAeZqQFsr/pcgApn2Y651wBpqUduGE/A6OQBWkMKh7ehrEEDdCWv22yU3gI3iowfI1 IMshQdqAs5otc6SySM7bfq/0mkSlEkVD8fy0jDob+2R7RKC4+bHbw7IZqWWNrJjbn0lgqO+VnnS J8/0NXRBcMAtDZ+gONOXEQ/Xj9sOGqvhAb0hF+gpIgX9+rQx X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C A peer connected via UDP may change its IP address without reconnecting (float). Add support for detecting and updating the new peer IP/port in case of floating. Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/bind.c | 9 +- drivers/net/ovpn/io.c | 4 + drivers/net/ovpn/peer.c | 237 +++++++++++++++++++++++++++++++++++++----------- drivers/net/ovpn/peer.h | 3 +- 4 files changed, 190 insertions(+), 63 deletions(-) diff --git a/drivers/net/ovpn/bind.c b/drivers/net/ovpn/bind.c index b4d2ccec2ceddf43bc445b489cc62a578ef0ad0a..c8ca340cca936a357409e9458807f27831511975 100644 --- a/drivers/net/ovpn/bind.c +++ b/drivers/net/ovpn/bind.c @@ -48,11 +48,8 @@ struct ovpn_bind *ovpn_bind_from_sockaddr(const struct sockaddr_storage *ss) */ void ovpn_bind_reset(struct ovpn_peer *peer, struct ovpn_bind *new) { - struct ovpn_bind *old; + lockdep_assert_held(&peer->lock); - spin_lock_bh(&peer->lock); - old = rcu_replace_pointer(peer->bind, new, true); - spin_unlock_bh(&peer->lock); - - kfree_rcu(old, rcu); + kfree_rcu(rcu_replace_pointer(peer->bind, new, + lockdep_is_held(&peer->lock)), rcu); } diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index bad6c0782802a993e6da04ecc1629ffd3ec59f62..ee3bb650ed4700d8fa2c9a128b6d2318e1653f5c 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -135,6 +135,10 @@ void ovpn_decrypt_post(void *data, int ret) /* keep track of last received authenticated packet for keepalive */ WRITE_ONCE(peer->last_recv, ktime_get_real_seconds()); + if (peer->sock->sock->sk->sk_protocol == IPPROTO_UDP) + /* check if this peer changed local or remote endpoint */ + ovpn_peer_endpoints_update(peer, skb); + /* point to encapsulated IP packet */ __skb_pull(skb, payload_offset); diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 7df9fedd593a74e2349922557ce299a0fcf03038..8c5643ca497f78282d6171a8ddbe9896cccef7ed 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -94,6 +94,188 @@ struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id) return peer; } +/** + * ovpn_peer_reset_sockaddr - recreate binding for peer + * @peer: peer to recreate the binding for + * @ss: sockaddr to use as remote endpoint for the binding + * @local_ip: local IP for the binding + * + * Return: 0 on success or a negative error code otherwise + */ +static int ovpn_peer_reset_sockaddr(struct ovpn_peer *peer, + const struct sockaddr_storage *ss, + const u8 *local_ip) +{ + struct ovpn_bind *bind; + size_t ip_len; + + lockdep_assert_held(&peer->lock); + + /* create new ovpn_bind object */ + bind = ovpn_bind_from_sockaddr(ss); + if (IS_ERR(bind)) + return PTR_ERR(bind); + + if (local_ip) { + if (ss->ss_family == AF_INET) { + ip_len = sizeof(struct in_addr); + } else if (ss->ss_family == AF_INET6) { + ip_len = sizeof(struct in6_addr); + } else { + net_dbg_ratelimited("%s: invalid family %u for remote endpoint for peer %u\n", + netdev_name(peer->ovpn->dev), + ss->ss_family, peer->id); + kfree(bind); + return -EINVAL; + } + + memcpy(&bind->local, local_ip, ip_len); + } + + /* set binding */ + ovpn_bind_reset(peer, bind); + + return 0; +} + +#define ovpn_get_hash_slot(_key, _key_len, _tbl) ({ \ + typeof(_tbl) *__tbl = &(_tbl); \ + jhash(_key, _key_len, 0) % HASH_SIZE(*__tbl); \ +}) + +#define ovpn_get_hash_head(_tbl, _key, _key_len) ({ \ + typeof(_tbl) *__tbl = &(_tbl); \ + &(*__tbl)[ovpn_get_hash_slot(_key, _key_len, *__tbl)]; \ +}) + +/** + * ovpn_peer_endpoints_update - update remote or local endpoint for peer + * @peer: peer to update the remote endpoint for + * @skb: incoming packet to retrieve the source/destination address from + */ +void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) +{ + struct hlist_nulls_head *nhead; + struct sockaddr_storage ss; + const u8 *local_ip = NULL; + struct sockaddr_in6 *sa6; + struct sockaddr_in *sa; + struct ovpn_bind *bind; + size_t salen = 0; + + spin_lock_bh(&peer->lock); + bind = rcu_dereference_protected(peer->bind, + lockdep_is_held(&peer->lock)); + if (unlikely(!bind)) + goto unlock; + + switch (skb->protocol) { + case htons(ETH_P_IP): + /* float check */ + if (unlikely(!ovpn_bind_skb_src_match(bind, skb))) { + if (bind->remote.in4.sin_family == AF_INET) + local_ip = (u8 *)&bind->local; + sa = (struct sockaddr_in *)&ss; + sa->sin_family = AF_INET; + sa->sin_addr.s_addr = ip_hdr(skb)->saddr; + sa->sin_port = udp_hdr(skb)->source; + salen = sizeof(*sa); + break; + } + + /* local endpoint update */ + if (unlikely(bind->local.ipv4.s_addr != ip_hdr(skb)->daddr)) { + net_dbg_ratelimited("%s: learning local IPv4 for peer %d (%pI4 -> %pI4)\n", + netdev_name(peer->ovpn->dev), + peer->id, &bind->local.ipv4.s_addr, + &ip_hdr(skb)->daddr); + bind->local.ipv4.s_addr = ip_hdr(skb)->daddr; + } + break; + case htons(ETH_P_IPV6): + /* float check */ + if (unlikely(!ovpn_bind_skb_src_match(bind, skb))) { + if (bind->remote.in6.sin6_family == AF_INET6) + local_ip = (u8 *)&bind->local; + sa6 = (struct sockaddr_in6 *)&ss; + sa6->sin6_family = AF_INET6; + sa6->sin6_addr = ipv6_hdr(skb)->saddr; + sa6->sin6_port = udp_hdr(skb)->source; + sa6->sin6_scope_id = ipv6_iface_scope_id(&ipv6_hdr(skb)->saddr, + skb->skb_iif); + salen = sizeof(*sa6); + } + + /* local endpoint update */ + if (unlikely(!ipv6_addr_equal(&bind->local.ipv6, + &ipv6_hdr(skb)->daddr))) { + net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c\n", + netdev_name(peer->ovpn->dev), + peer->id, &bind->local.ipv6, + &ipv6_hdr(skb)->daddr); + bind->local.ipv6 = ipv6_hdr(skb)->daddr; + } + break; + default: + goto unlock; + } + + /* if the peer did not float, we can bail out now */ + if (likely(!salen)) + goto unlock; + + if (unlikely(ovpn_peer_reset_sockaddr(peer, + (struct sockaddr_storage *)&ss, + local_ip) < 0)) + goto unlock; + + net_dbg_ratelimited("%s: peer %d floated to %pIScp", + netdev_name(peer->ovpn->dev), peer->id, &ss); + + spin_unlock_bh(&peer->lock); + + /* rehashing is required only in MP mode as P2P has one peer + * only and thus there is no hashtable + */ + if (peer->ovpn->mode == OVPN_MODE_MP) { + spin_lock_bh(&peer->ovpn->lock); + spin_lock_bh(&peer->lock); + bind = rcu_dereference_protected(peer->bind, + lockdep_is_held(&peer->lock)); + if (unlikely(!bind)) { + spin_unlock_bh(&peer->lock); + spin_unlock_bh(&peer->ovpn->lock); + return; + } + + /* his function may be invoked concurrently, therefore another + * float may have happened in parallel: perform rehashing + * using the peer->bind->remote directly as key + */ + + switch (bind->remote.in4.sin_family) { + case AF_INET: + salen = sizeof(*sa); + break; + case AF_INET6: + salen = sizeof(*sa6); + break; + } + + /* remove old hashing */ + hlist_nulls_del_init_rcu(&peer->hash_entry_transp_addr); + /* re-add with new transport address */ + nhead = ovpn_get_hash_head(peer->ovpn->peers->by_transp_addr, + &bind->remote, salen); + hlist_nulls_add_head_rcu(&peer->hash_entry_transp_addr, nhead); + spin_unlock_bh(&peer->lock); + spin_unlock_bh(&peer->ovpn->lock); + } + return; +unlock: + spin_unlock_bh(&peer->lock); +} + /** * ovpn_peer_release_rcu - RCU callback performing last peer release steps * @head: RCU member of the ovpn_peer @@ -197,16 +379,6 @@ static struct in6_addr ovpn_nexthop_from_skb6(struct sk_buff *skb) return rt->rt6i_gateway; } -#define ovpn_get_hash_slot(_key, _key_len, _tbl) ({ \ - typeof(_tbl) *__tbl = &(_tbl); \ - jhash(_key, _key_len, 0) % HASH_SIZE(*__tbl); \ -}) - -#define ovpn_get_hash_head(_tbl, _key, _key_len) ({ \ - typeof(_tbl) *__tbl = &(_tbl); \ - &(*__tbl)[ovpn_get_hash_slot(_key, _key_len, *__tbl)]; \ -}) - /** * ovpn_peer_get_by_vpn_addr4 - retrieve peer by its VPN IPv4 address * @ovpn: the openvpn instance to search @@ -450,51 +622,6 @@ struct ovpn_peer *ovpn_peer_get_by_id(struct ovpn_priv *ovpn, u32 peer_id) return peer; } -/** - * ovpn_peer_update_local_endpoint - update local endpoint for peer - * @peer: peer to update the endpoint for - * @skb: incoming packet to retrieve the destination address (local) from - */ -void ovpn_peer_update_local_endpoint(struct ovpn_peer *peer, - struct sk_buff *skb) -{ - struct ovpn_bind *bind; - - rcu_read_lock(); - bind = rcu_dereference(peer->bind); - if (unlikely(!bind)) - goto unlock; - - spin_lock_bh(&peer->lock); - switch (skb->protocol) { - case htons(ETH_P_IP): - if (unlikely(bind->local.ipv4.s_addr != ip_hdr(skb)->daddr)) { - net_dbg_ratelimited("%s: learning local IPv4 for peer %d (%pI4 -> %pI4)\n", - netdev_name(peer->ovpn->dev), - peer->id, &bind->local.ipv4.s_addr, - &ip_hdr(skb)->daddr); - bind->local.ipv4.s_addr = ip_hdr(skb)->daddr; - } - break; - case htons(ETH_P_IPV6): - if (unlikely(!ipv6_addr_equal(&bind->local.ipv6, - &ipv6_hdr(skb)->daddr))) { - net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c\n", - netdev_name(peer->ovpn->dev), - peer->id, &bind->local.ipv6, - &ipv6_hdr(skb)->daddr); - bind->local.ipv6 = ipv6_hdr(skb)->daddr; - } - break; - default: - break; - } - spin_unlock_bh(&peer->lock); - -unlock: - rcu_read_unlock(); -} - /** * ovpn_peer_get_by_dst - Lookup peer to send skb to * @ovpn: the private data representing the current VPN session diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index 196fa0a04f2db1986fffa6d51b42b68c9837c8e8..a95ec054a8c2224cc0a4ef3800d30e76138f1fe6 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -153,7 +153,6 @@ bool ovpn_peer_check_by_src(struct ovpn_priv *ovpn, struct sk_buff *skb, void ovpn_peer_keepalive_set(struct ovpn_peer *peer, u32 interval, u32 timeout); void ovpn_peer_keepalive_work(struct work_struct *work); -void ovpn_peer_update_local_endpoint(struct ovpn_peer *peer, - struct sk_buff *skb); +void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb); #endif /* _NET_OVPN_OVPNPEER_H_ */ From patchwork Mon Dec 2 15:07:36 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846790 Received: from mail-wr1-f48.google.com (mail-wr1-f48.google.com [209.85.221.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 D794C20C468 for ; Mon, 2 Dec 2024 15:08:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.48 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152136; cv=none; b=chmoYQgGhQNXzMEaIObDfmBmYWqfIS/css5ZRVlS5/AygKMlyYFfdQM7npTcbEeMV4Yxhl6E4i67+1F6oRzzPd61lCAItPt50BtRnlsOVHoWz9TblLgvXlv62LUh4Er4ThqPncGQcs7Evv7+hvRdn8bmZIMJtFVMt3qRxHo9/K4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152136; c=relaxed/simple; bh=zOHbASRkauWc+eWDqSV+95PxafqBxLKtcZ1PLAVBffU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=rXQIbKIa0g5e26Yx6bEI61UIyDoFyR4ZHS9PYk+SkdwEdpxd+5WY1YDZ78ASV0/UA9R60opKxWXpeGSzEqahk+mxlKkP5LKlC+DhQhH/OQ7gBx875eMJzjcZppIFG4sBRTKT9lc3/EWX3/rNd1UQXfK11SecvkQG53ydb7YQr0U= 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=Tp76G7Qu; arc=none smtp.client-ip=209.85.221.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="Tp76G7Qu" Received: by mail-wr1-f48.google.com with SMTP id ffacd0b85a97d-385de59c1a0so3040072f8f.2 for ; Mon, 02 Dec 2024 07:08:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152131; x=1733756931; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=6MzTrgxI0j8iL8reeWqysObeOUfk0y8VRHzmBuwqCXg=; b=Tp76G7QuJLyaQ5/rc8Om+DKVoyQLoT9+cFrnWxSHhwiOkCrE2j7eNYXp+Ou2FWNBHv zL0dS2Kop1SN5Zy6JOQxuO70g9KBKzUchoS+5ap2ThdjycR3pKC+alvhrju20ShPUJYX i5pBJ1FLsab6xwtDZZa80RMzqOJjeW2qa6Dl1sWU0zSExiGk7P0TSIjoa8LmGCmSXogv 9uQFs8j0SFFUzaAtbH+SboGT/naqJlJgrFVCWan9GHPz4RPr4Ix7BARxHc6a7Q7n2nbD 1aidMNe4I8a1UfducSFK1iheBq+iA9AtSxb/gOs244X8ldCcLOzPp3D+O2DgXn/LBgG7 dDaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152131; x=1733756931; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=6MzTrgxI0j8iL8reeWqysObeOUfk0y8VRHzmBuwqCXg=; b=a9UvJ8UC4S7Fw2ogEt0oLxlRgFa9K28ss46bSZI6A6rHmHjvBCyUaSIISOOVgCmKBM KHtF9NXt2BjNdGpmWvuhc6EA9rCuqEODFWepABuocHt2X3Csn+OEaqId0BVUCM9TNesZ BRFCZmIJAvN0YTc0pLGXepYqQguAoRkHux3RQQHjC+s3y09zVa/hVlnz5VDIpANCJJMP LG8M/Vf/lacFLavqW8woTxKEoLYpFhc+vgjA4bp8oOmExcvF3YcI+xxSgDGOVKhr9r/7 4LPLHZUNx1Y1iaHJgmpIaHmwUuP+tJnuJP+uF+OJWfA+U7JFDkVroLO4OyBMTsLvf4e+ NCSg== X-Forwarded-Encrypted: i=1; AJvYcCV0045EmBJSr1JWJSkC7oL0NK5LboKVMRUMk79fLm3wAM4seNIOKTpe5XYdIlzfhRBbOyopibSGGv/fgGaYYfQ=@vger.kernel.org X-Gm-Message-State: AOJu0YzdcsdphDnQQY/+08wAfzWjzsW/97tX5q09gXdOcthr4mSyQ5TL niXld4IbjhruqKl0GZ6opU+hfMCg4SoCARJKxwphqF0ARy6MqEiuJuBZXx8nczw= X-Gm-Gg: ASbGnctgY8b512hL0FF/SMwzJI/ShpzJkKMZOAaUEY3miEZlWktJUWGTIvQvx+KvuWv 3VKSz71eb0cjqQEEOV9mDofe2ucSf2I9H/y/lt39cESB0akp4Zl3bpD9q+S9Cwq8IRNrFZK0m+/ VYVX6IDUPvXpKMQuJ7+5inHFkoAWqCDV8lQJsaM6cNb3nddnwyg+BLKV9eDdc5ZMoBwi24GPq0+ b8w7/sEZk6M3wgatnjpFiFYx0HCi4fK66BA33+49z2Dr6PmfJ8vT8XW/2TL X-Google-Smtp-Source: AGHT+IFTNAWRMLay9xA8FGAhtibvpegqVUJLDhKKyKov5rkRFOcuP/A7kItlrUWB+9a/6Eu29s8xCg== X-Received: by 2002:a5d:6d8a:0:b0:385:fa3d:199b with SMTP id ffacd0b85a97d-385fa3d23d2mr761989f8f.40.1733152129416; Mon, 02 Dec 2024 07:08:49 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:48 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:36 +0100 Subject: [PATCH net-next v12 18/22] ovpn: implement key add/get/del/swap via netlink Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-18-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=13971; i=antonio@openvpn.net; h=from:subject:message-id; bh=zOHbASRkauWc+eWDqSV+95PxafqBxLKtcZ1PLAVBffU=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1nLFFdi/ku4C4F2VP4DaO5BuGMPcKbe/bfv kIczKnMQmWJATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZwAKCRALcOU6oDjV h9LvB/42xkKQJBvC4R2LsodmARazlNFyyLtq4Y34KslVY+5n1wDHKurTuBddIOboomwbl+qp3rj MgWY9uA338fUxMhjJjyKYD+GT3TJmvizzZYqxi8oVxObIEcMZlrPuO39gH0XbjRvl7GXU2zT95y WvewoEm0J6zv9/siFmI8Opfz2rb+GewZfP3WlxmiB727GnHyvdPDlNgpN6Y2QdzZIpVG2vI9Xy4 gy5nogsg8Gtr56i2K0n5O8SCptQn4hicOEtaI2zdZB9201ZnoCDt5e1kF8C0qjvcBWEEVm1ge6Z sWvJN+9fyIFnd451e0CqxffhBOpPY/4fV1T4F0cyHMDMPgUE X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C This change introduces the netlink commands needed to add, get, delete and swap keys for a specific peer. Userspace is expected to use these commands to create, inspect (non sensitive data only), destroy and rotate session keys for a specific peer. Signed-off-by: Antonio Quartulli --- drivers/net/ovpn/crypto.c | 40 ++++++ drivers/net/ovpn/crypto.h | 4 + drivers/net/ovpn/crypto_aead.c | 17 +++ drivers/net/ovpn/crypto_aead.h | 2 + drivers/net/ovpn/netlink.c | 301 ++++++++++++++++++++++++++++++++++++++++- 5 files changed, 360 insertions(+), 4 deletions(-) diff --git a/drivers/net/ovpn/crypto.c b/drivers/net/ovpn/crypto.c index fabc19994ba34260753911ac7d3e50b643b9b89f..6fccd73c6cf7d2566d1b819cb6d5d7b2ea98e81d 100644 --- a/drivers/net/ovpn/crypto.c +++ b/drivers/net/ovpn/crypto.c @@ -150,3 +150,43 @@ void ovpn_crypto_key_slots_swap(struct ovpn_crypto_state *cs) spin_unlock_bh(&cs->lock); } + +/** + * ovpn_crypto_config_get - populate keyconf object with non-sensible key data + * @cs: the crypto state to extract the key data from + * @slot: the specific slot to inspect + * @keyconf: the output object to populate + * + * Return: 0 on success or a negative error code otherwise + */ +int ovpn_crypto_config_get(struct ovpn_crypto_state *cs, + enum ovpn_key_slot slot, + struct ovpn_key_config *keyconf) +{ + struct ovpn_crypto_key_slot *ks; + int idx; + + switch (slot) { + case OVPN_KEY_SLOT_PRIMARY: + idx = cs->primary_idx; + break; + case OVPN_KEY_SLOT_SECONDARY: + idx = !cs->primary_idx; + break; + default: + return -EINVAL; + } + + rcu_read_lock(); + ks = rcu_dereference(cs->slots[idx]); + if (!ks) { + rcu_read_unlock(); + return -ENOENT; + } + + keyconf->cipher_alg = ovpn_aead_crypto_alg(ks); + keyconf->key_id = ks->key_id; + rcu_read_unlock(); + + return 0; +} diff --git a/drivers/net/ovpn/crypto.h b/drivers/net/ovpn/crypto.h index b1b77c38ffe68dc21079e3a5354cc0695caa9cf3..05ca312765a4551b3493dc6a27228e8ad48e99f6 100644 --- a/drivers/net/ovpn/crypto.h +++ b/drivers/net/ovpn/crypto.h @@ -136,4 +136,8 @@ void ovpn_crypto_state_release(struct ovpn_crypto_state *cs); void ovpn_crypto_key_slots_swap(struct ovpn_crypto_state *cs); +int ovpn_crypto_config_get(struct ovpn_crypto_state *cs, + enum ovpn_key_slot slot, + struct ovpn_key_config *keyconf); + #endif /* _NET_OVPN_OVPNCRYPTO_H_ */ diff --git a/drivers/net/ovpn/crypto_aead.c b/drivers/net/ovpn/crypto_aead.c index dade83aad09b2d79ad65152ce867a961aeec01bd..b48b4df271bdec37de2996d2b88ecf7766380525 100644 --- a/drivers/net/ovpn/crypto_aead.c +++ b/drivers/net/ovpn/crypto_aead.c @@ -364,3 +364,20 @@ ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc) ovpn_aead_crypto_key_slot_destroy(ks); return ERR_PTR(ret); } + +enum ovpn_cipher_alg ovpn_aead_crypto_alg(struct ovpn_crypto_key_slot *ks) +{ + const char *alg_name; + + if (!ks->encrypt) + return OVPN_CIPHER_ALG_NONE; + + alg_name = crypto_tfm_alg_name(crypto_aead_tfm(ks->encrypt)); + + if (!strcmp(alg_name, ALG_NAME_AES)) + return OVPN_CIPHER_ALG_AES_GCM; + else if (!strcmp(alg_name, ALG_NAME_CHACHAPOLY)) + return OVPN_CIPHER_ALG_CHACHA20_POLY1305; + else + return OVPN_CIPHER_ALG_NONE; +} diff --git a/drivers/net/ovpn/crypto_aead.h b/drivers/net/ovpn/crypto_aead.h index 77ee8141599bc06b0dc664c5b0a4dae660a89238..fb65be82436edd7ff89b171f7a89c9103b617d1f 100644 --- a/drivers/net/ovpn/crypto_aead.h +++ b/drivers/net/ovpn/crypto_aead.h @@ -28,4 +28,6 @@ struct ovpn_crypto_key_slot * ovpn_aead_crypto_key_slot_new(const struct ovpn_key_config *kc); void ovpn_aead_crypto_key_slot_destroy(struct ovpn_crypto_key_slot *ks); +enum ovpn_cipher_alg ovpn_aead_crypto_alg(struct ovpn_crypto_key_slot *ks); + #endif /* _NET_OVPN_OVPNAEAD_H_ */ diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index cc75d23703359a2cb234db42dc6aa735fe229a1d..647ecb71794fc925f49b624d720a5169b72afae3 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -17,6 +17,7 @@ #include "netlink.h" #include "netlink-gen.h" #include "bind.h" +#include "crypto.h" #include "peer.h" #include "socket.h" @@ -729,24 +730,316 @@ int ovpn_nl_peer_del_doit(struct sk_buff *skb, struct genl_info *info) return ret; } +static int ovpn_nl_get_key_dir(struct genl_info *info, struct nlattr *key, + enum ovpn_cipher_alg cipher, + struct ovpn_key_direction *dir) +{ + struct nlattr *attrs[OVPN_A_KEYDIR_MAX + 1]; + int ret; + + ret = nla_parse_nested(attrs, OVPN_A_KEYDIR_MAX, key, + ovpn_keydir_nl_policy, info->extack); + if (ret) + return ret; + + switch (cipher) { + case OVPN_CIPHER_ALG_AES_GCM: + case OVPN_CIPHER_ALG_CHACHA20_POLY1305: + if (NL_REQ_ATTR_CHECK(info->extack, key, attrs, + OVPN_A_KEYDIR_CIPHER_KEY) || + NL_REQ_ATTR_CHECK(info->extack, key, attrs, + OVPN_A_KEYDIR_NONCE_TAIL)) + return -EINVAL; + + dir->cipher_key = nla_data(attrs[OVPN_A_KEYDIR_CIPHER_KEY]); + dir->cipher_key_size = nla_len(attrs[OVPN_A_KEYDIR_CIPHER_KEY]); + + /* These algorithms require a 96bit nonce, + * Construct it by combining 4-bytes packet id and + * 8-bytes nonce-tail from userspace + */ + dir->nonce_tail = nla_data(attrs[OVPN_A_KEYDIR_NONCE_TAIL]); + dir->nonce_tail_size = nla_len(attrs[OVPN_A_KEYDIR_NONCE_TAIL]); + break; + default: + NL_SET_ERR_MSG_MOD(info->extack, "unsupported cipher"); + return -EINVAL; + } + + return 0; +} + +/** + * ovpn_nl_key_new_doit - configure a new key for the specified peer + * @skb: incoming netlink message + * @info: genetlink metadata + * + * This function allows the user to install a new key in the peer crypto + * state. + * Each peer has two 'slots', namely 'primary' and 'secondary', where + * keys can be installed. The key in the 'primary' slot is used for + * encryption, while both keys can be used for decryption by matching the + * key ID carried in the incoming packet. + * + * The user is responsible for rotating keys when necessary. The user + * may fetch peer traffic statistics via netlink in order to better + * identify the right time to rotate keys. + * The renegotiation follows these steps: + * 1. a new key is computed by the user and is installed in the 'secondary' + * slot + * 2. at user discretion (usually after a predetermined time) 'primary' and + * 'secondary' contents are swapped and the new key starts being used for + * encryption, while the old key is kept around for decryption of late + * packets. + * + * Return: 0 on success or a negative error code otherwise. + */ int ovpn_nl_key_new_doit(struct sk_buff *skb, struct genl_info *info) { - return -EOPNOTSUPP; + struct nlattr *attrs[OVPN_A_KEYCONF_MAX + 1]; + struct ovpn_priv *ovpn = info->user_ptr[0]; + struct ovpn_peer_key_reset pkr; + struct ovpn_peer *peer; + u32 peer_id; + int ret; + + if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF)) + return -EINVAL; + + ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX, + info->attrs[OVPN_A_KEYCONF], + ovpn_keyconf_nl_policy, info->extack); + if (ret) + return ret; + + if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_PEER_ID)) + return -EINVAL; + + if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_SLOT) || + NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_KEY_ID) || + NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_CIPHER_ALG) || + NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_ENCRYPT_DIR) || + NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_DECRYPT_DIR)) + return -EINVAL; + + pkr.slot = nla_get_u8(attrs[OVPN_A_KEYCONF_SLOT]); + pkr.key.key_id = nla_get_u16(attrs[OVPN_A_KEYCONF_KEY_ID]); + pkr.key.cipher_alg = nla_get_u16(attrs[OVPN_A_KEYCONF_CIPHER_ALG]); + + ret = ovpn_nl_get_key_dir(info, attrs[OVPN_A_KEYCONF_ENCRYPT_DIR], + pkr.key.cipher_alg, &pkr.key.encrypt); + if (ret < 0) + return ret; + + ret = ovpn_nl_get_key_dir(info, attrs[OVPN_A_KEYCONF_DECRYPT_DIR], + pkr.key.cipher_alg, &pkr.key.decrypt); + if (ret < 0) + return ret; + + peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]); + peer = ovpn_peer_get_by_id(ovpn, peer_id); + if (!peer) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "no peer with id %u to set key for", + peer_id); + return -ENOENT; + } + + ret = ovpn_crypto_state_reset(&peer->crypto, &pkr); + if (ret < 0) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "cannot install new key for peer %u", + peer_id); + goto out; + } + + netdev_dbg(ovpn->dev, "new key installed (id=%u) for peer %u\n", + pkr.key.key_id, peer_id); +out: + ovpn_peer_put(peer); + return ret; +} + +static int ovpn_nl_send_key(struct sk_buff *skb, const struct genl_info *info, + u32 peer_id, enum ovpn_key_slot slot, + const struct ovpn_key_config *keyconf) +{ + struct nlattr *attr; + void *hdr; + + hdr = genlmsg_put(skb, info->snd_portid, info->snd_seq, &ovpn_nl_family, + 0, OVPN_CMD_KEY_GET); + if (!hdr) + return -ENOBUFS; + + attr = nla_nest_start(skb, OVPN_A_KEYCONF); + if (!attr) + goto err; + + if (nla_put_u32(skb, OVPN_A_KEYCONF_PEER_ID, peer_id)) + goto err; + + if (nla_put_u32(skb, OVPN_A_KEYCONF_SLOT, slot) || + nla_put_u32(skb, OVPN_A_KEYCONF_KEY_ID, keyconf->key_id) || + nla_put_u32(skb, OVPN_A_KEYCONF_CIPHER_ALG, keyconf->cipher_alg)) + goto err; + + nla_nest_end(skb, attr); + genlmsg_end(skb, hdr); + + return 0; +err: + genlmsg_cancel(skb, hdr); + return -EMSGSIZE; } int ovpn_nl_key_get_doit(struct sk_buff *skb, struct genl_info *info) { - return -EOPNOTSUPP; + struct nlattr *attrs[OVPN_A_KEYCONF_MAX + 1]; + struct ovpn_priv *ovpn = info->user_ptr[0]; + struct ovpn_key_config keyconf = { 0 }; + enum ovpn_key_slot slot; + struct ovpn_peer *peer; + struct sk_buff *msg; + u32 peer_id; + int ret; + + if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF)) + return -EINVAL; + + ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX, + info->attrs[OVPN_A_KEYCONF], + ovpn_keyconf_nl_policy, info->extack); + if (ret) + return ret; + + if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_PEER_ID)) + return -EINVAL; + + if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_SLOT)) + return -EINVAL; + + peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]); + peer = ovpn_peer_get_by_id(ovpn, peer_id); + if (!peer) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "cannot find peer with id %u", peer_id); + return -ENOENT; + } + + slot = nla_get_u32(attrs[OVPN_A_KEYCONF_SLOT]); + + ret = ovpn_crypto_config_get(&peer->crypto, slot, &keyconf); + if (ret < 0) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "cannot extract key from slot %u for peer %u", + slot, peer_id); + goto err; + } + + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto err; + } + + ret = ovpn_nl_send_key(msg, info, peer->id, slot, &keyconf); + if (ret < 0) { + nlmsg_free(msg); + goto err; + } + + ret = genlmsg_reply(msg, info); +err: + ovpn_peer_put(peer); + return ret; } int ovpn_nl_key_swap_doit(struct sk_buff *skb, struct genl_info *info) { - return -EOPNOTSUPP; + struct ovpn_priv *ovpn = info->user_ptr[0]; + struct nlattr *attrs[OVPN_A_PEER_MAX + 1]; + struct ovpn_peer *peer; + u32 peer_id; + int ret; + + if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF)) + return -EINVAL; + + ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX, + info->attrs[OVPN_A_KEYCONF], + ovpn_keyconf_nl_policy, info->extack); + if (ret) + return ret; + + if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_PEER_ID)) + return -EINVAL; + + peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]); + peer = ovpn_peer_get_by_id(ovpn, peer_id); + if (!peer) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "no peer with id %u to swap keys for", + peer_id); + return -ENOENT; + } + + ovpn_crypto_key_slots_swap(&peer->crypto); + ovpn_peer_put(peer); + + return 0; } int ovpn_nl_key_del_doit(struct sk_buff *skb, struct genl_info *info) { - return -EOPNOTSUPP; + struct nlattr *attrs[OVPN_A_KEYCONF_MAX + 1]; + struct ovpn_priv *ovpn = info->user_ptr[0]; + enum ovpn_key_slot slot; + struct ovpn_peer *peer; + u32 peer_id; + int ret; + + if (GENL_REQ_ATTR_CHECK(info, OVPN_A_KEYCONF)) + return -EINVAL; + + ret = nla_parse_nested(attrs, OVPN_A_KEYCONF_MAX, + info->attrs[OVPN_A_KEYCONF], + ovpn_keyconf_nl_policy, info->extack); + if (ret) + return ret; + + if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_PEER_ID)) + return -EINVAL; + + if (NL_REQ_ATTR_CHECK(info->extack, info->attrs[OVPN_A_KEYCONF], attrs, + OVPN_A_KEYCONF_SLOT)) + return -EINVAL; + + peer_id = nla_get_u32(attrs[OVPN_A_KEYCONF_PEER_ID]); + slot = nla_get_u8(attrs[OVPN_A_KEYCONF_SLOT]); + + peer = ovpn_peer_get_by_id(ovpn, peer_id); + if (!peer) { + NL_SET_ERR_MSG_FMT_MOD(info->extack, + "no peer with id %u to delete key for", + peer_id); + return -ENOENT; + } + + ovpn_crypto_key_slot_delete(&peer->crypto, slot); + ovpn_peer_put(peer); + + return 0; } /** From patchwork Mon Dec 2 15:07:39 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 846789 Received: from mail-wm1-f46.google.com (mail-wm1-f46.google.com [209.85.128.46]) (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 D8ABE20C495 for ; Mon, 2 Dec 2024 15:08:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.46 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152138; cv=none; b=RWk4pUt1OUgeK+wGjiriovK8oRONYkHW42cIH26p1tX71wZSHSWC+yBQwtXK/H9WbpzkxVhqbIflb9qXU4JvY9TUD2dYTwik3m8gWA7GrpB2zTtTsJZvMYFdhzgKNM2j+vBId2oqaC+DnwtUwJ7VUIND/MQypHWg2QtTQncGDbw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1733152138; c=relaxed/simple; bh=W5T+iVYKaPmO/gOfKB0RnKXCUMfDvh3g/zI0cvgMIlg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=I0EO+xfy61lnFTtFOKup0Ygwz7s4tkGCbvK0dWM4iF7xuHwlyNAPGZlr5D17lNFUwJPWIvUf3QhPKDYCr+1LCuDAoYO3cYDfjSXoxYTvNNtVuqZKfQwG+2no9ixQO7aK6LnFXb0p1v0OIxFjQa8Qjgc+14kkdZloHFDPMFssdcs= 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=V+EgCLh7; arc=none smtp.client-ip=209.85.128.46 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="V+EgCLh7" Received: by mail-wm1-f46.google.com with SMTP id 5b1f17b1804b1-43497839b80so27896775e9.2 for ; Mon, 02 Dec 2024 07:08:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=openvpn.net; s=google; t=1733152133; x=1733756933; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=Jb7KHSQUPGhy5o0HEst1Kbqk3ULde1AaGrsUDUj2wbI=; b=V+EgCLh744ibV/CCYfd9yledFrf4TQgCQpIBBQ3ZQYemi39t9L+dACkdko1gGu3pV4 7xzcX0wustZjlQjJYs6FVUjWUvolu5EjLpM+Mcgu0a31ktxJRyq9b1O6CVpHCF0Fs8+F Mm1qxps5tuJlQjCe/PYkMypPIAU8O35SxgMLyGEBHY+PkIz2htdrff97ePaFPdfc3Ixe llj8V7SG3DZ0D5dHmdcjxEd6PMBc16pW4culVcwDoG5zwcMRL5bi8FCNEudczZjm5kxr SMqjGHCZU07kbkHpCGpxxeexriSdF93TY6r/7BYza7BG3qsyZVyMejhuf8FIlxUVnNnx OQHQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1733152133; x=1733756933; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Jb7KHSQUPGhy5o0HEst1Kbqk3ULde1AaGrsUDUj2wbI=; b=hf6mzLSMvE+IxWTqkl34kdDxZqKCIx0keO5/MKNCVz6Q7I3e43a4lRral5JEJp9m0S S4jg2KtB4F9NSFzCS6G105izQGpYutN5iGqWe9aUui/Yq1aEMmNo+Z3n+Rrj+7GaC9iX W14XUr0zXzsNHz6eHBGEMUOWzi8Dvpi74Xp6T6TQzyAm+ZqFpjaDiisUDySjfPCFt1Y3 DK1ZK9/VV5ZMed2OpPkUA9w2VTCj3xZfMeuYLXPg9hGvIr9Wi0LpF2LlcdVeHNgqho78 iO1VwCa4UtjkJfrTw802RbLe981vqGjt5dnX8mSI0zEcWPBkd9vI9MND4znyVIBDBazK 2Sjg== X-Forwarded-Encrypted: i=1; AJvYcCXO+sSXVwWDF+bOg736kt9Q7ySxh0MZiTMNLnz2992O0inym7Lz21sWONhLhvsu+KgnwCJWPeQhJt3OUg14Wrw=@vger.kernel.org X-Gm-Message-State: AOJu0YyvebkR39df2+9CI3BzZxPA4euUJ07Sx+jOiyF4TrgNxQdXD4Qf 6qjmbi0De6Bkf1J4yKp8ce4R4/lS042TuZIayzRliETzam3Op73v8iIaJ+w7EHo= X-Gm-Gg: ASbGncsBv+hoeGhtZHEFWqtS6FmzDIxvUrx8uX80Drr/uQZNnxW75koXpZZ+CHAXT9e cGKXya0bVM2XcoWg9VLhFjxJueQR55iZejRvE8WmRCC3rQWOH2HGkbXMBK43P5cm4MJVxTGriAK +oNcqpkldCnlabPMcTaJjjKRIsMPwEdfq2z1xH/tAHa9KCaHzwiFJGkkgNmDIbxlVFNO8HwVLMm jKCPq/3UTyjQc6BciTZpWLczeOMYjhOK7zNLwkbswplMJUX1fN1hCxwF5bE X-Google-Smtp-Source: AGHT+IEn+KYaLgP1sl4kPtOglN8/sEshdXG03PjEYhnnt+7o+pRUaGL53PJCCS2kPdOoKnoFjeFW9g== X-Received: by 2002:a05:6000:280b:b0:385:ef8e:a641 with SMTP id ffacd0b85a97d-385ef8ea683mr3213538f8f.28.1733152132886; Mon, 02 Dec 2024 07:08:52 -0800 (PST) Received: from serenity.mandelbit.com ([2001:67c:2fbc:1:5d0b:f507:fa8:3b2e]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-385e8a47032sm6570395f8f.51.2024.12.02.07.08.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 02 Dec 2024 07:08:52 -0800 (PST) From: Antonio Quartulli Date: Mon, 02 Dec 2024 16:07:39 +0100 Subject: [PATCH net-next v12 21/22] ovpn: add basic ethtool support Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20241202-b4-ovpn-v12-21-239ff733bf97@openvpn.net> References: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> In-Reply-To: <20241202-b4-ovpn-v12-0-239ff733bf97@openvpn.net> To: Eric Dumazet , Jakub Kicinski , Paolo Abeni , Donald Hunter , Antonio Quartulli , Shuah Khan , donald.hunter@gmail.com, sd@queasysnail.net, ryazanov.s.a@gmail.com, Andrew Lunn Cc: Simon Horman , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=1699; i=antonio@openvpn.net; h=from:subject:message-id; bh=W5T+iVYKaPmO/gOfKB0RnKXCUMfDvh3g/zI0cvgMIlg=; b=owEBbQGS/pANAwAIAQtw5TqgONWHAcsmYgBnTc1nnJJLVJJ7y0wCH14v4nZ2IqFXxcfBGNwR3 FyraAQrRjuJATMEAAEIAB0WIQSZq9xs+NQS5N5fwPwLcOU6oDjVhwUCZ03NZwAKCRALcOU6oDjV h5oAB/kBpJ8kCcDl6LLOf0pEsS0N7H4VbOZumG5shm+X4SiYmPmZfn4rWz03tokFQEIUU193l5/ Z4m6Fx0MEB1YJnYZCVEnqFnTsUGnLbHlEtINFM+xVc5JEUCswZN8ABKUYxmdOhAVGZ2PxgNuTL3 PDWsdlaiQNBVY8QTk+v0wjJeILE8AANEzZDVSXARHAjqhFjoMvcpriC5XWMawhKuNWhkJEy/4fQ g3yZapsV6JBok6SVe7Cr3rhHvAVE+rHykb3TUv3J5CPM5TqRL8dx9U+lPTaraFZ5qpl0MbiGP5b pOqQGnf4US9Bc3t805SfZGRpk1LxDQjAQCNerOH+YTiFDeSB X-Developer-Key: i=antonio@openvpn.net; a=openpgp; fpr=CABDA1282017C267219885C748F0CCB68F59D14C Implement support for basic ethtool functionality. Note that ovpn is a virtual device driver, therefore various ethtool APIs are just not meaningful and thus not implemented. Signed-off-by: Antonio Quartulli Reviewed-by: Andrew Lunn --- drivers/net/ovpn/main.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 6b3a59e75e5aa918b28957c073990be9fb1d2124..6a828728d4f98f84e39ea429a8b76069c6d83e69 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -7,6 +7,7 @@ * James Yonan */ +#include #include #include #include @@ -94,6 +95,19 @@ bool ovpn_dev_is_valid(const struct net_device *dev) return dev->netdev_ops == &ovpn_netdev_ops; } +static void ovpn_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strscpy(info->driver, "ovpn", sizeof(info->driver)); + strscpy(info->bus_info, "ovpn", sizeof(info->bus_info)); +} + +static const struct ethtool_ops ovpn_ethtool_ops = { + .get_drvinfo = ovpn_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_ts_info = ethtool_op_get_ts_info, +}; + static void ovpn_setup(struct net_device *dev) { netdev_features_t feat = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM | @@ -104,6 +118,7 @@ static void ovpn_setup(struct net_device *dev) dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; + dev->ethtool_ops = &ovpn_ethtool_ops; dev->netdev_ops = &ovpn_netdev_ops; dev->priv_destructor = ovpn_priv_free;