[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20240304150914.11444-5-antonio@openvpn.net>
Date: Mon, 4 Mar 2024 16:08:55 +0100
From: Antonio Quartulli <antonio@...nvpn.net>
To: netdev@...r.kernel.org
Cc: Jakub Kicinski <kuba@...nel.org>,
Sergey Ryazanov <ryazanov.s.a@...il.com>,
Paolo Abeni <pabeni@...hat.com>,
Eric Dumazet <edumazet@...gle.com>,
Antonio Quartulli <antonio@...nvpn.net>
Subject: [PATCH net-next v2 04/22] ovpn: add basic interface creation/destruction/management routines
Signed-off-by: Antonio Quartulli <antonio@...nvpn.net>
---
drivers/net/ovpn/io.c | 26 +++++++++
drivers/net/ovpn/io.h | 1 +
drivers/net/ovpn/main.c | 107 ++++++++++++++++++++++++++++++++++
drivers/net/ovpn/ovpnstruct.h | 16 +++++
4 files changed, 150 insertions(+)
diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c
index a1e19402e36d..b283449ba479 100644
--- a/drivers/net/ovpn/io.c
+++ b/drivers/net/ovpn/io.c
@@ -8,11 +8,37 @@
*/
#include "io.h"
+#include "ovpnstruct.h"
+#include "netlink.h"
#include <linux/netdevice.h>
#include <linux/skbuff.h>
+int ovpn_struct_init(struct net_device *dev)
+{
+ struct ovpn_struct *ovpn = netdev_priv(dev);
+ int err;
+
+ memset(ovpn, 0, sizeof(*ovpn));
+
+ ovpn->dev = dev;
+
+ err = ovpn_nl_init(ovpn);
+ if (err < 0)
+ return err;
+
+ dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
+ if (!dev->tstats)
+ return -ENOMEM;
+
+ err = security_tun_dev_alloc_security(&ovpn->security);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
/* Send user data to the network
*/
netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
diff --git a/drivers/net/ovpn/io.h b/drivers/net/ovpn/io.h
index 0a076d14f721..e7728718c8a9 100644
--- a/drivers/net/ovpn/io.h
+++ b/drivers/net/ovpn/io.h
@@ -14,6 +14,7 @@
struct sk_buff;
+int ovpn_struct_init(struct net_device *dev);
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
index 3769f99cfe6f..1be0fd50c356 100644
--- a/drivers/net/ovpn/main.c
+++ b/drivers/net/ovpn/main.c
@@ -10,15 +10,20 @@
#include "main.h"
#include "netlink.h"
#include "io.h"
+#include "ovpnstruct.h"
+#include "packet.h"
#include <linux/genetlink.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/types.h>
+#include <linux/lockdep.h>
#include <linux/net.h>
#include <linux/inetdevice.h>
#include <linux/netdevice.h>
#include <linux/version.h>
+#include <net/ip.h>
+#include <uapi/linux/if_arp.h>
#include <uapi/linux/ovpn.h>
@@ -28,6 +33,16 @@
#define DRV_DESCRIPTION "OpenVPN data channel offload (ovpn)"
#define DRV_COPYRIGHT "(C) 2020-2024 OpenVPN, Inc."
+static LIST_HEAD(dev_list);
+
+static void ovpn_struct_free(struct net_device *net)
+{
+ struct ovpn_struct *ovpn = netdev_priv(net);
+
+ security_tun_dev_free_security(ovpn->security);
+ free_percpu(net->tstats);
+}
+
/* Net device open */
static int ovpn_net_open(struct net_device *dev)
{
@@ -62,28 +77,120 @@ static const struct net_device_ops ovpn_netdev_ops = {
.ndo_get_stats64 = dev_get_tstats64,
};
+static void ovpn_setup(struct net_device *dev)
+{
+ /* compute the overhead considering AEAD encryption */
+ const int overhead = sizeof(u32) + NONCE_WIRE_SIZE + 16 + sizeof(struct udphdr) +
+ max(sizeof(struct ipv6hdr), sizeof(struct iphdr));
+
+ netdev_features_t feat = NETIF_F_SG | NETIF_F_LLTX |
+ NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_GSO |
+ NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA;
+
+ dev->needs_free_netdev = true;
+
+ dev->netdev_ops = &ovpn_netdev_ops;
+
+ dev->priv_destructor = ovpn_struct_free;
+
+ dev->hard_header_len = 0;
+ dev->addr_len = 0;
+ dev->mtu = ETH_DATA_LEN - overhead;
+ dev->min_mtu = IPV4_MIN_MTU;
+ dev->max_mtu = IP_MAX_MTU - overhead;
+
+ dev->type = ARPHRD_NONE;
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
+ dev->features |= feat;
+ dev->hw_features |= feat;
+ dev->hw_enc_features |= feat;
+
+ dev->needed_headroom = OVPN_HEAD_ROOM;
+ dev->needed_tailroom = OVPN_MAX_PADDING;
+}
+
+int ovpn_iface_create(const char *name, enum ovpn_mode mode, struct net *net)
+{
+ struct net_device *dev;
+ struct ovpn_struct *ovpn;
+ int ret;
+
+ dev = alloc_netdev(sizeof(struct ovpn_struct), name, NET_NAME_USER, ovpn_setup);
+
+ dev_net_set(dev, net);
+
+ ret = ovpn_struct_init(dev);
+ if (ret < 0)
+ goto err;
+
+ ovpn = netdev_priv(dev);
+ ovpn->mode = mode;
+
+ rtnl_lock();
+
+ ret = register_netdevice(dev);
+ if (ret < 0) {
+ netdev_dbg(dev, "cannot register interface %s: %d\n", dev->name, ret);
+ rtnl_unlock();
+ goto err;
+ }
+ rtnl_unlock();
+
+ return ret;
+
+err:
+ free_netdev(dev);
+ return ret;
+}
+
+void ovpn_iface_destruct(struct ovpn_struct *ovpn, bool unregister_netdev)
+{
+ ASSERT_RTNL();
+
+ netif_carrier_off(ovpn->dev);
+
+ list_del(&ovpn->dev_list);
+ ovpn->registered = false;
+
+ if (unregister_netdev)
+ unregister_netdevice(ovpn->dev);
+
+ synchronize_net();
+}
+
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);
+ struct ovpn_struct *ovpn;
if (!ovpn_dev_is_valid(dev))
return NOTIFY_DONE;
+ ovpn = netdev_priv(dev);
+
switch (state) {
case NETDEV_REGISTER:
/* add device to internal list for later destruction upon unregistration */
+ list_add(&ovpn->dev_list, &dev_list);
+ ovpn->registered = true;
break;
case NETDEV_UNREGISTER:
/* can be delivered multiple times, so check registered flag, then
* destroy the interface
*/
+ if (!ovpn->registered)
+ return NOTIFY_DONE;
+
+ ovpn_iface_destruct(ovpn, false);
break;
case NETDEV_POST_INIT:
case NETDEV_GOING_DOWN:
case NETDEV_DOWN:
case NETDEV_UP:
case NETDEV_PRE_UP:
+ break;
default:
return NOTIFY_DONE;
}
diff --git a/drivers/net/ovpn/ovpnstruct.h b/drivers/net/ovpn/ovpnstruct.h
index 932eb90953e0..c2cdfd6f84b3 100644
--- a/drivers/net/ovpn/ovpnstruct.h
+++ b/drivers/net/ovpn/ovpnstruct.h
@@ -10,11 +10,27 @@
#ifndef _NET_OVPN_OVPNSTRUCT_H_
#define _NET_OVPN_OVPNSTRUCT_H_
+#include <uapi/linux/ovpn.h>
#include <linux/netdevice.h>
+#include <linux/types.h>
/* Our state per ovpn interface */
struct ovpn_struct {
struct net_device *dev;
+
+ /* whether this device is still registered with netdev or not */
+ bool registered;
+
+ /* device operation mode (i.e. P2P, MP) */
+ enum ovpn_mode mode;
+
+ unsigned int max_tun_queue_len;
+
+ netdev_features_t set_features;
+
+ void *security;
+
+ struct list_head dev_list;
};
#endif /* _NET_OVPN_OVPNSTRUCT_H_ */
--
2.43.0
Powered by blists - more mailing lists