Add basic infrastructure for handling ovpn interfaces.
Unified · Split
| @@ -938,6 +938,12 @@ definitions: · 937 unmodified lines | ||
| 938 | 938 | entries: |
| 939 | 939 | - name: none |
| 940 | 940 | - name: default |
| 941 | + - | |
| 942 | + name: ovpn-mode | |
| 943 | + type: enum | |
| 944 | + entries: | |
| 945 | + - p2p | |
| 946 | + - mp | |
| 941 | 947 | |
| 942 | 948 | attribute-sets: |
| 943 | 949 | - |
| @@ -2272,6 +2278,13 @@ attribute-sets: · 1328 unmodified lines | ||
| 2272 | 2278 | - |
| 2273 | 2279 | name: tailroom |
| 2274 | 2280 | type: u16 |
| 2281 | + - | |
| 2282 | + name: linkinfo-ovpn-attrs | |
| 2283 | + attributes: | |
| 2284 | + - | |
| 2285 | + name: mode | |
| 2286 | + type: u8 | |
| 2287 | + enum: ovpn-mode | |
| 2275 | 2288 | |
| 2276 | 2289 | sub-messages: |
| 2277 | 2290 | - |
| @@ -2322,6 +2335,9 @@ sub-messages: · 44 unmodified lines | ||
| 2322 | 2335 | - |
| 2323 | 2336 | value: netkit |
| 2324 | 2337 | attribute-set: linkinfo-netkit-attrs |
| 2338 | + - | |
| 2339 | + value: ovpn | |
| 2340 | + attribute-set: linkinfo-ovpn-attrs | |
| 2325 | 2341 | - |
| 2326 | 2342 | name: linkinfo-member-data-msg |
| 2327 | 2343 | formats: |
| @@ -8,5 +8,6 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | obj-$(CONFIG_OVPN) := ovpn.o |
| 10 | 10 | ovpn-y += main.o |
| 11 | +ovpn-y += io.o | |
| 11 | 12 | ovpn-y += netlink.o |
| 12 | 13 | ovpn-y += netlink-gen.o |
| @@ -0,0 +1,22 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* OpenVPN data channel offload | |
| 3 | + * | |
| 4 | + * Copyright (C) 2019-2025 OpenVPN, Inc. | |
| 5 | + * | |
| 6 | + * Author: James Yonan <james@openvpn.net> | |
| 7 | + * Antonio Quartulli <antonio@openvpn.net> | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#include <linux/netdevice.h> | |
| 11 | +#include <linux/skbuff.h> | |
| 12 | + | |
| 13 | +#include "io.h" | |
| 14 | + | |
| 15 | +/* Send user data to the network | |
| 16 | + */ | |
| 17 | +netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) | |
| 18 | +{ | |
| 19 | + skb_tx_error(skb); | |
| 20 | + kfree_skb(skb); | |
| 21 | + return NET_XMIT_DROP; | |
| 22 | +} | |
| @@ -0,0 +1,24 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* OpenVPN data channel offload | |
| 3 | + * | |
| 4 | + * Copyright (C) 2019-2025 OpenVPN, Inc. | |
| 5 | + * | |
| 6 | + * Author: James Yonan <james@openvpn.net> | |
| 7 | + * Antonio Quartulli <antonio@openvpn.net> | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#ifndef _NET_OVPN_OVPN_H_ | |
| 11 | +#define _NET_OVPN_OVPN_H_ | |
| 12 | + | |
| 13 | +/* DATA_V2 header size with AEAD encryption */ | |
| 14 | +#define OVPN_HEAD_ROOM (OVPN_OPCODE_SIZE + OVPN_NONCE_WIRE_SIZE + \ | |
| 15 | + 16 /* AEAD TAG length */ + \ | |
| 16 | + max(sizeof(struct udphdr), sizeof(struct tcphdr)) +\ | |
| 17 | + max(sizeof(struct ipv6hdr), sizeof(struct iphdr))) | |
| 18 | + | |
| 19 | +/* max padding required by encryption */ | |
| 20 | +#define OVPN_MAX_PADDING 16 | |
| 21 | + | |
| 22 | +netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev); | |
| 23 | + | |
| 24 | +#endif /* _NET_OVPN_OVPN_H_ */ | |
| @@ -10,14 +10,28 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/genetlink.h> |
| 11 | 11 | #include <linux/module.h> |
| 12 | 12 | #include <linux/netdevice.h> |
| 13 | +#include <linux/inetdevice.h> | |
| 14 | +#include <net/ip.h> | |
| 13 | 15 | #include <net/rtnetlink.h> |
| 14 | −#include <uapi/linux/ovpn.h> | |
| 16 | +#include <uapi/linux/if_arp.h> | |
| 15 | 17 | |
| 16 | 18 | #include "ovpnpriv.h" |
| 17 | 19 | #include "main.h" |
| 18 | 20 | #include "netlink.h" |
| 21 | +#include "io.h" | |
| 22 | +#include "proto.h" | |
| 19 | 23 | |
| 20 | 24 | static const struct net_device_ops ovpn_netdev_ops = { |
| 25 | + .ndo_start_xmit = ovpn_net_xmit, | |
| 26 | +}; | |
| 27 | + | |
| 28 | +static const struct device_type ovpn_type = { | |
| 29 | + .name = OVPN_FAMILY_NAME, | |
| 30 | +}; | |
| 31 | + | |
| 32 | +static const struct nla_policy ovpn_policy[IFLA_OVPN_MAX + 1] = { | |
| 33 | + [IFLA_OVPN_MODE] = NLA_POLICY_RANGE(NLA_U8, OVPN_MODE_P2P, | |
| 34 | + OVPN_MODE_MP), | |
| 21 | 35 | }; |
| 22 | 36 | |
| 23 | 37 | /** |
| @@ -31,18 +45,82 @@ bool ovpn_dev_is_valid(const struct net_device *dev) · 7 unmodified lines | ||
| 31 | 45 | return dev->netdev_ops == &ovpn_netdev_ops; |
| 32 | 46 | } |
| 33 | 47 | |
| 48 | +static void ovpn_setup(struct net_device *dev) | |
| 49 | +{ | |
| 50 | + netdev_features_t feat = NETIF_F_SG | NETIF_F_GSO | | |
| 51 | + NETIF_F_GSO_SOFTWARE | NETIF_F_HIGHDMA; | |
| 52 | + | |
| 53 | + dev->needs_free_netdev = true; | |
| 54 | + | |
| 55 | + dev->pcpu_stat_type = NETDEV_PCPU_STAT_DSTATS; | |
| 56 | + | |
| 57 | + dev->netdev_ops = &ovpn_netdev_ops; | |
| 58 | + | |
| 59 | + dev->hard_header_len = 0; | |
| 60 | + dev->addr_len = 0; | |
| 61 | + dev->mtu = ETH_DATA_LEN - OVPN_HEAD_ROOM; | |
| 62 | + dev->min_mtu = IPV4_MIN_MTU; | |
| 63 | + dev->max_mtu = IP_MAX_MTU - OVPN_HEAD_ROOM; | |
| 64 | + | |
| 65 | + dev->type = ARPHRD_NONE; | |
| 66 | + dev->flags = IFF_POINTOPOINT | IFF_NOARP; | |
| 67 | + dev->priv_flags |= IFF_NO_QUEUE; | |
| 68 | + | |
| 69 | + dev->lltx = true; | |
| 70 | + dev->features |= feat; | |
| 71 | + dev->hw_features |= feat; | |
| 72 | + dev->hw_enc_features |= feat; | |
| 73 | + | |
| 74 | + dev->needed_headroom = ALIGN(OVPN_HEAD_ROOM, 4); | |
| 75 | + dev->needed_tailroom = OVPN_MAX_PADDING; | |
| 76 | + | |
| 77 | + SET_NETDEV_DEVTYPE(dev, &ovpn_type); | |
| 78 | +} | |
| 79 | + | |
| 34 | 80 | static int ovpn_newlink(struct net_device *dev, |
| 35 | 81 | struct rtnl_newlink_params *params, |
| 36 | 82 | struct netlink_ext_ack *extack) |
| 37 | 83 | { |
| 38 | − return -EOPNOTSUPP; | |
| 84 | + struct ovpn_priv *ovpn = netdev_priv(dev); | |
| 85 | + struct nlattr **data = params->data; | |
| 86 | + enum ovpn_mode mode = OVPN_MODE_P2P; | |
| 87 | + | |
| 88 | + if (data && data[IFLA_OVPN_MODE]) { | |
| 89 | + mode = nla_get_u8(data[IFLA_OVPN_MODE]); | |
| 90 | + netdev_dbg(dev, "setting device mode: %u\n", mode); | |
| 91 | + } | |
| 92 | + | |
| 93 | + ovpn->dev = dev; | |
| 94 | + ovpn->mode = mode; | |
| 95 | + | |
| 96 | + /* turn carrier explicitly off after registration, this way state is | |
| 97 | + * clearly defined | |
| 98 | + */ | |
| 99 | + netif_carrier_off(dev); | |
| 100 | + | |
| 101 | + return register_netdevice(dev); | |
| 102 | +} | |
| 103 | + | |
| 104 | +static int ovpn_fill_info(struct sk_buff *skb, const struct net_device *dev) | |
| 105 | +{ | |
| 106 | + struct ovpn_priv *ovpn = netdev_priv(dev); | |
| 107 | + | |
| 108 | + if (nla_put_u8(skb, IFLA_OVPN_MODE, ovpn->mode)) | |
| 109 | + return -EMSGSIZE; | |
| 110 | + | |
| 111 | + return 0; | |
| 39 | 112 | } |
| 40 | 113 | |
| 41 | 114 | static struct rtnl_link_ops ovpn_link_ops = { |
| 42 | 115 | .kind = "ovpn", |
| 43 | 116 | .netns_refund = false, |
| 117 | + .priv_size = sizeof(struct ovpn_priv), | |
| 118 | + .setup = ovpn_setup, | |
| 119 | + .policy = ovpn_policy, | |
| 120 | + .maxtype = IFLA_OVPN_MAX, | |
| 44 | 121 | .newlink = ovpn_newlink, |
| 45 | 122 | .dellink = unregister_netdevice_queue, |
| 123 | + .fill_info = ovpn_fill_info, | |
| 46 | 124 | }; |
| 47 | 125 | |
| 48 | 126 | static int __init ovpn_init(void) |
| @@ -10,12 +10,17 @@ · 9 unmodified lines | ||
| 10 | 10 | #ifndef _NET_OVPN_OVPNSTRUCT_H_ |
| 11 | 11 | #define _NET_OVPN_OVPNSTRUCT_H_ |
| 12 | 12 | |
| 13 | +#include <uapi/linux/if_link.h> | |
| 14 | +#include <uapi/linux/ovpn.h> | |
| 15 | + | |
| 13 | 16 | /** |
| 14 | 17 | * struct ovpn_priv - per ovpn interface state |
| 15 | 18 | * @dev: the actual netdev representing the tunnel |
| 19 | + * @mode: device operation mode (i.e. p2p, mp, ..) | |
| 16 | 20 | */ |
| 17 | 21 | struct ovpn_priv { |
| 18 | 22 | struct net_device *dev; |
| 23 | + enum ovpn_mode mode; | |
| 19 | 24 | }; |
| 20 | 25 | |
| 21 | 26 | #endif /* _NET_OVPN_OVPNSTRUCT_H_ */ |
| @@ -0,0 +1,38 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ | |
| 2 | +/* OpenVPN data channel offload | |
| 3 | + * | |
| 4 | + * Copyright (C) 2020-2025 OpenVPN, Inc. | |
| 5 | + * | |
| 6 | + * Author: Antonio Quartulli <antonio@openvpn.net> | |
| 7 | + * James Yonan <james@openvpn.net> | |
| 8 | + */ | |
| 9 | + | |
| 10 | +#ifndef _NET_OVPN_PROTO_H_ | |
| 11 | +#define _NET_OVPN_PROTO_H_ | |
| 12 | + | |
| 13 | +/* When the OpenVPN protocol is ran in AEAD mode, use | |
| 14 | + * the OpenVPN packet ID as the AEAD nonce: | |
| 15 | + * | |
| 16 | + * 00000005 521c3b01 4308c041 | |
| 17 | + * [seq # ] [ nonce_tail ] | |
| 18 | + * [ 12-byte full IV ] -> OVPN_NONCE_SIZE | |
| 19 | + * [4-bytes -> OVPN_NONCE_WIRE_SIZE | |
| 20 | + * on wire] | |
| 21 | + */ | |
| 22 | + | |
| 23 | +/* nonce size (96bits) as required by AEAD ciphers */ | |
| 24 | +#define OVPN_NONCE_SIZE 12 | |
| 25 | +/* last 8 bytes of AEAD nonce: provided by userspace and usually derived | |
| 26 | + * from key material generated during TLS handshake | |
| 27 | + */ | |
| 28 | +#define OVPN_NONCE_TAIL_SIZE 8 | |
| 29 | + | |
| 30 | +/* OpenVPN nonce size reduced by 8-byte nonce tail -- this is the | |
| 31 | + * size of the AEAD Associated Data (AD) sent over the wire | |
| 32 | + * and is normally the head of the IV | |
| 33 | + */ | |
| 34 | +#define OVPN_NONCE_WIRE_SIZE (OVPN_NONCE_SIZE - OVPN_NONCE_TAIL_SIZE) | |
| 35 | + | |
| 36 | +#define OVPN_OPCODE_SIZE 4 /* DATA_V2 opcode size */ | |
| 37 | + | |
| 38 | +#endif /* _NET_OVPN_PROTO_H_ */ | |
| @@ -1986,4 +1986,19 @@ enum { · 1985 unmodified lines | ||
| 1986 | 1986 | |
| 1987 | 1987 | #define IFLA_DSA_MAX (__IFLA_DSA_MAX - 1) |
| 1988 | 1988 | |
| 1989 | +/* OVPN section */ | |
| 1990 | + | |
| 1991 | +enum ovpn_mode { | |
| 1992 | + OVPN_MODE_P2P, | |
| 1993 | + OVPN_MODE_MP, | |
| 1994 | +}; | |
| 1995 | + | |
| 1996 | +enum { | |
| 1997 | + IFLA_OVPN_UNSPEC, | |
| 1998 | + IFLA_OVPN_MODE, | |
| 1999 | + __IFLA_OVPN_MAX, | |
| 2000 | +}; | |
| 2001 | + | |
| 2002 | +#define IFLA_OVPN_MAX (__IFLA_OVPN_MAX - 1) | |
| 2003 | + | |
| 1989 | 2004 | #endif /* _UAPI_LINUX_IF_LINK_H */ |