From: Antonio Quartulli <antonio@openvpn.net>
To: netdev@vger.kernel.org
Cc: kuba@kernel.org, ryazanov.s.a@gmail.com, pabeni@redhat.com,
edumazet@google.com, andrew@lunn.ch, sd@queasysnail.net,
Antonio Quartulli <antonio@openvpn.net>
Subject: [PATCH net-next v4 03/25] net: introduce OpenVPN Data Channel Offload (ovpn)
Date: Mon, 24 Jun 2024 13:31:00 +0200 [thread overview]
Message-ID: <20240624113122.12732-4-antonio@openvpn.net> (raw)
In-Reply-To: <20240624113122.12732-1-antonio@openvpn.net>
OpenVPN is a userspace software existing since around 2005 that allows
users to create secure tunnels.
So far OpenVPN has implemented all operations in userspace, which
implies several back and forth between kernel and user land in order to
process packets (encapsulate/decapsulate, encrypt/decrypt, rerouting..).
With `ovpn` we intend to move the fast path (data channel) entirely
in kernel space and thus improve user measured throughput over the
tunnel.
`ovpn` is implemented as a simple virtual network device driver, that
can be manipulated by means of the standard RTNL APIs. A device of kind
`ovpn` allows only IPv4/6 traffic and can be of type:
* P2P (peer-to-peer): any packet sent over the interface will be
encapsulated and transmitted to the other side (typical OpenVPN
client or peer-to-peer behaviour);
* P2MP (point-to-multipoint): packets sent over the interface are
transmitted to peers based on existing routes (typical OpenVPN
server behaviour).
After the interface has been created, OpenVPN in userspace can
configure it using a new Netlink API. Specifically it is possible
to manage peers and their keys.
The OpenVPN control channel is multiplexed over the same transport
socket by means of OP codes. Anything that is not DATA_V2 (OpenVPN
OP code for data traffic) is sent to userspace and handled there.
This way the `ovpn` codebase is kept as compact as possible while
focusing on handling data traffic only (fast path).
Any OpenVPN control feature (like cipher negotiation, TLS handshake,
rekeying, etc.) is still fully handled by the userspace process.
When userspace establishes a new connection with a peer, it first
performs the handshake and then passes the socket to the `ovpn` kernel
module, which takes ownership. From this moment on `ovpn` will handle
data traffic for the new peer.
When control packets are received on the link, they are forwarded to
userspace through the same transport socket they were received on, as
userspace is still listening to them.
Some events (like peer deletion) are sent to a Netlink multicast group.
Although it wasn't easy to convince the community, `ovpn` implements
only a limited number of the data-channel features supported by the
userspace program.
Each feature that made it to `ovpn` was attentively vetted to
avoid carrying too much legacy along with us (and to give a clear cut to
old and probalby-not-so-useful features).
Notably, only encryption using AEAD ciphers (specifically
ChaCha20Poly1305 and AES-GCM) was implemented. Supporting any other
cipher out there was not deemed useful.
Both UDP and TCP sockets ae supported.
As explained above, in case of P2MP mode, OpenVPN will use the main system
routing table to decide which packet goes to which peer. This implies
that no routing table was re-implemented in the `ovpn` kernel module.
This kernel module can be enabled by selecting the CONFIG_OVPN entry
in the networking drivers section.
NOTE: this first patch introduces the very basic framework only.
Features are then added patch by patch, however, although each patch
will compile and possibly not break at runtime, only after having
applied the full set it is expected to see the ovpn module fully working.
Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
---
MAINTAINERS | 8 +++
drivers/net/Kconfig | 13 +++++
drivers/net/Makefile | 1 +
drivers/net/ovpn/Makefile | 11 ++++
drivers/net/ovpn/io.c | 22 ++++++++
drivers/net/ovpn/io.h | 15 ++++++
drivers/net/ovpn/main.c | 109 ++++++++++++++++++++++++++++++++++++++
drivers/net/ovpn/main.h | 15 ++++++
include/uapi/linux/udp.h | 1 +
9 files changed, 195 insertions(+)
create mode 100644 drivers/net/ovpn/Makefile
create mode 100644 drivers/net/ovpn/io.c
create mode 100644 drivers/net/ovpn/io.h
create mode 100644 drivers/net/ovpn/main.c
create mode 100644 drivers/net/ovpn/main.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 0e3cb040fc16..1620c49ff469 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -16908,6 +16908,14 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs.git
F: Documentation/filesystems/overlayfs.rst
F: fs/overlayfs/
+OPENVPN DATA CHANNEL OFFLOAD
+M: Antonio Quartulli <antonio@openvpn.net>
+L: openvpn-devel@lists.sourceforge.net (moderated for non-subscribers)
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ovpn/
+F: include/uapi/linux/ovpn.h
+
P54 WIRELESS DRIVER
M: Christian Lamparter <chunkeey@googlemail.com>
L: linux-wireless@vger.kernel.org
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 9920b3a68ed1..c5743288242d 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -115,6 +115,19 @@ config WIREGUARD_DEBUG
Say N here unless you know what you're doing.
+config OVPN
+ tristate "OpenVPN data channel offload"
+ depends on NET && INET
+ select NET_UDP_TUNNEL
+ select DST_CACHE
+ select CRYPTO
+ select CRYPTO_AES
+ select CRYPTO_GCM
+ select CRYPTO_CHACHA20POLY1305
+ help
+ This module enhances the performance of the OpenVPN userspace software
+ by offloading the data channel processing to kernelspace.
+
config EQUALIZER
tristate "EQL (serial line load balancing) support"
help
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 13743d0e83b5..5152b3330e28 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_IPVLAN) += ipvlan/
obj-$(CONFIG_IPVTAP) += ipvlan/
obj-$(CONFIG_DUMMY) += dummy.o
obj-$(CONFIG_WIREGUARD) += wireguard/
+obj-$(CONFIG_OVPN) += ovpn/
obj-$(CONFIG_EQUALIZER) += eql.o
obj-$(CONFIG_IFB) += ifb.o
obj-$(CONFIG_MACSEC) += macsec.o
diff --git a/drivers/net/ovpn/Makefile b/drivers/net/ovpn/Makefile
new file mode 100644
index 000000000000..53fb197027d7
--- /dev/null
+++ b/drivers/net/ovpn/Makefile
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# ovpn -- OpenVPN data channel offload in kernel space
+#
+# Copyright (C) 2020-2024 OpenVPN, Inc.
+#
+# Author: Antonio Quartulli <antonio@openvpn.net>
+
+obj-$(CONFIG_OVPN) := ovpn.o
+ovpn-y += main.o
+ovpn-y += io.o
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
new file mode 100644
index 000000000000..ad3813419c33
--- /dev/null
+++ b/drivers/net/ovpn/io.c
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0
+/* OpenVPN data channel offload
+ *
+ * Copyright (C) 2019-2024 OpenVPN, Inc.
+ *
+ * Author: James Yonan <james@openvpn.net>
+ * Antonio Quartulli <antonio@openvpn.net>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+
+#include "io.h"
+
+/* Send user data to the network
+ */
+netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ skb_tx_error(skb);
+ kfree_skb(skb);
+ return NET_XMIT_DROP;
+}
diff --git a/drivers/net/ovpn/io.h b/drivers/net/ovpn/io.h
new file mode 100644
index 000000000000..aa259be66441
--- /dev/null
+++ b/drivers/net/ovpn/io.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* OpenVPN data channel offload
+ *
+ * Copyright (C) 2019-2024 OpenVPN, Inc.
+ *
+ * Author: James Yonan <james@openvpn.net>
+ * Antonio Quartulli <antonio@openvpn.net>
+ */
+
+#ifndef _NET_OVPN_OVPN_H_
+#define _NET_OVPN_OVPN_H_
+
+netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev);
+
+#endif /* _NET_OVPN_OVPN_H_ */
diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c
new file mode 100644
index 000000000000..8a90319e4600
--- /dev/null
+++ b/drivers/net/ovpn/main.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0
+/* OpenVPN data channel offload
+ *
+ * Copyright (C) 2020-2024 OpenVPN, Inc.
+ *
+ * Author: Antonio Quartulli <antonio@openvpn.net>
+ * James Yonan <james@openvpn.net>
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/version.h>
+#include <net/rtnetlink.h>
+
+#include "main.h"
+#include "io.h"
+
+/* Driver info */
+#define DRV_DESCRIPTION "OpenVPN data channel offload (ovpn)"
+#define DRV_COPYRIGHT "(C) 2020-2024 OpenVPN, Inc."
+
+/**
+ * ovpn_dev_is_valid - check if the netdevice is of type 'ovpn'
+ * @dev: the interface to check
+ *
+ * Return: whether the netdevice is of type 'ovpn'
+ */
+bool ovpn_dev_is_valid(const struct net_device *dev)
+{
+ return dev->netdev_ops->ndo_start_xmit == ovpn_net_xmit;
+}
+
+/* we register with rtnl to let core know that ovpn is a virtual driver and
+ * therefore ifaces should be destroyed when exiting a netns
+ */
+static struct rtnl_link_ops ovpn_link_ops = {
+};
+
+static int ovpn_netdev_notifier_call(struct notifier_block *nb,
+ unsigned long state, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
+ if (!ovpn_dev_is_valid(dev))
+ return NOTIFY_DONE;
+
+ switch (state) {
+ case NETDEV_REGISTER:
+ /* add device to internal list for later destruction upon
+ * unregistration
+ */
+ break;
+ case NETDEV_UNREGISTER:
+ /* can be delivered multiple times, so check registered flag,
+ * then destroy the interface
+ */
+ break;
+ case NETDEV_POST_INIT:
+ case NETDEV_GOING_DOWN:
+ case NETDEV_DOWN:
+ case NETDEV_UP:
+ case NETDEV_PRE_UP:
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ovpn_netdev_notifier = {
+ .notifier_call = ovpn_netdev_notifier_call,
+};
+
+static int __init ovpn_init(void)
+{
+ int err = register_netdevice_notifier(&ovpn_netdev_notifier);
+
+ if (err) {
+ pr_err("ovpn: can't register netdevice notifier: %d\n", err);
+ return err;
+ }
+
+ err = rtnl_link_register(&ovpn_link_ops);
+ if (err) {
+ pr_err("ovpn: can't register rtnl link ops: %d\n", err);
+ goto unreg_netdev;
+ }
+
+ return 0;
+
+unreg_netdev:
+ unregister_netdevice_notifier(&ovpn_netdev_notifier);
+ return err;
+}
+
+static __exit void ovpn_cleanup(void)
+{
+ rtnl_link_unregister(&ovpn_link_ops);
+ unregister_netdevice_notifier(&ovpn_netdev_notifier);
+
+ rcu_barrier();
+}
+
+module_init(ovpn_init);
+module_exit(ovpn_cleanup);
+
+MODULE_DESCRIPTION(DRV_DESCRIPTION);
+MODULE_AUTHOR(DRV_COPYRIGHT);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ovpn/main.h b/drivers/net/ovpn/main.h
new file mode 100644
index 000000000000..a3215316c49b
--- /dev/null
+++ b/drivers/net/ovpn/main.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* OpenVPN data channel offload
+ *
+ * Copyright (C) 2019-2024 OpenVPN, Inc.
+ *
+ * Author: James Yonan <james@openvpn.net>
+ * Antonio Quartulli <antonio@openvpn.net>
+ */
+
+#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/include/uapi/linux/udp.h b/include/uapi/linux/udp.h
index 1a0fe8b151fb..f9f8ffddfd0c 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 */
--
2.44.2
next prev parent reply other threads:[~2024-06-24 11:29 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-24 11:30 [PATCH net-next v4 00/25] Introducing OpenVPN Data Channel Offload Antonio Quartulli
2024-06-24 11:30 ` [PATCH net-next v4 01/25] netlink: add NLA_POLICY_MAX_LEN macro Antonio Quartulli
2024-06-24 11:30 ` [PATCH net-next v4 02/25] rtnetlink: don't crash on unregister if no dellink exists Antonio Quartulli
2024-06-24 11:31 ` Antonio Quartulli [this message]
2024-06-24 11:31 ` [PATCH net-next v4 04/25] ovpn: add basic netlink support Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 05/25] ovpn: add basic interface creation/destruction/management routines Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 06/25] ovpn: implement interface creation/destruction via netlink Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 07/25] ovpn: keep carrier always on Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 08/25] ovpn: introduce the ovpn_peer object Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 09/25] ovpn: introduce the ovpn_socket object Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 10/25] ovpn: implement basic TX path (UDP) Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 11/25] ovpn: implement basic RX " Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 12/25] ovpn: implement packet processing Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 13/25] ovpn: store tunnel and transport statistics Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 14/25] ovpn: implement TCP transport Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 15/25] ovpn: implement multi-peer support Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 16/25] ovpn: implement peer lookup logic Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 17/25] ovpn: implement keepalive mechanism Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 18/25] ovpn: add support for updating local UDP endpoint Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 19/25] ovpn: add support for peer floating Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 20/25] ovpn: implement peer add/dump/delete via netlink Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 21/25] ovpn: implement key add/del/swap " Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 22/25] ovpn: kill key and notify userspace in case of IV exhaustion Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 23/25] ovpn: notify userspace when a peer is deleted Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 24/25] ovpn: add basic ethtool support Antonio Quartulli
2024-06-24 11:31 ` [PATCH net-next v4 25/25] testing/selftest: add test tool and scripts for ovpn module Antonio Quartulli
2024-06-25 15:14 ` Jakub Kicinski
2024-06-27 6:46 ` Antonio Quartulli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20240624113122.12732-4-antonio@openvpn.net \
--to=antonio@openvpn.net \
--cc=andrew@lunn.ch \
--cc=edumazet@google.com \
--cc=kuba@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=ryazanov.s.a@gmail.com \
--cc=sd@queasysnail.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).