Skip to content

Commit ab66abb

Browse files
ordexPaolo Abeni
authored andcommitted
ovpn: implement basic RX path (UDP)
Packets received over the socket are forwarded to the user device. Implementation is UDP only. TCP will be added by a later patch. Note: no decryption/decapsulation exists yet, packets are forwarded as they arrive without much processing. Signed-off-by: Antonio Quartulli <[email protected]> Link: https://patch.msgid.link/[email protected] Reviewed-by: Sabrina Dubroca <[email protected]> Tested-by: Oleksandr Natalenko <[email protected]> Signed-off-by: Paolo Abeni <[email protected]>
1 parent 08857b5 commit ab66abb

File tree

8 files changed

+290
-5
lines changed

8 files changed

+290
-5
lines changed

drivers/net/ovpn/io.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,77 @@
99

1010
#include <linux/netdevice.h>
1111
#include <linux/skbuff.h>
12+
#include <net/gro_cells.h>
1213
#include <net/gso.h>
1314

14-
#include "io.h"
1515
#include "ovpnpriv.h"
1616
#include "peer.h"
17+
#include "io.h"
18+
#include "netlink.h"
19+
#include "proto.h"
1720
#include "udp.h"
1821
#include "skb.h"
1922
#include "socket.h"
2023

24+
/* Called after decrypt to write the IP packet to the device.
25+
* This method is expected to manage/free the skb.
26+
*/
27+
static void ovpn_netdev_write(struct ovpn_peer *peer, struct sk_buff *skb)
28+
{
29+
unsigned int pkt_len;
30+
int ret;
31+
32+
/* we can't guarantee the packet wasn't corrupted before entering the
33+
* VPN, therefore we give other layers a chance to check that
34+
*/
35+
skb->ip_summed = CHECKSUM_NONE;
36+
37+
/* skb hash for transport packet no longer valid after decapsulation */
38+
skb_clear_hash(skb);
39+
40+
/* post-decrypt scrub -- prepare to inject encapsulated packet onto the
41+
* interface, based on __skb_tunnel_rx() in dst.h
42+
*/
43+
skb->dev = peer->ovpn->dev;
44+
skb_set_queue_mapping(skb, 0);
45+
skb_scrub_packet(skb, true);
46+
47+
skb_reset_network_header(skb);
48+
skb_reset_transport_header(skb);
49+
skb_reset_inner_headers(skb);
50+
51+
/* cause packet to be "received" by the interface */
52+
pkt_len = skb->len;
53+
ret = gro_cells_receive(&peer->ovpn->gro_cells, skb);
54+
if (likely(ret == NET_RX_SUCCESS))
55+
/* update RX stats with the size of decrypted packet */
56+
dev_dstats_rx_add(peer->ovpn->dev, pkt_len);
57+
}
58+
59+
static void ovpn_decrypt_post(struct sk_buff *skb, int ret)
60+
{
61+
struct ovpn_peer *peer = ovpn_skb_cb(skb)->peer;
62+
63+
if (unlikely(ret < 0))
64+
goto drop;
65+
66+
ovpn_netdev_write(peer, skb);
67+
/* skb is passed to upper layer - don't free it */
68+
skb = NULL;
69+
drop:
70+
if (unlikely(skb))
71+
dev_dstats_rx_dropped(peer->ovpn->dev);
72+
ovpn_peer_put(peer);
73+
kfree_skb(skb);
74+
}
75+
76+
/* RX path entry point: decrypt packet and forward it to the device */
77+
void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb)
78+
{
79+
ovpn_skb_cb(skb)->peer = peer;
80+
ovpn_decrypt_post(skb, 0);
81+
}
82+
2183
static void ovpn_encrypt_post(struct sk_buff *skb, int ret)
2284
{
2385
struct ovpn_peer *peer = ovpn_skb_cb(skb)->peer;

drivers/net/ovpn/io.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,6 @@
2121

2222
netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev);
2323

24+
void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb);
25+
2426
#endif /* _NET_OVPN_OVPN_H_ */

drivers/net/ovpn/main.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/module.h>
1212
#include <linux/netdevice.h>
1313
#include <linux/inetdevice.h>
14+
#include <net/gro_cells.h>
1415
#include <net/ip.h>
1516
#include <net/rtnetlink.h>
1617
#include <uapi/linux/if_arp.h>
@@ -21,8 +22,25 @@
2122
#include "io.h"
2223
#include "peer.h"
2324
#include "proto.h"
25+
#include "udp.h"
26+
27+
static int ovpn_net_init(struct net_device *dev)
28+
{
29+
struct ovpn_priv *ovpn = netdev_priv(dev);
30+
31+
return gro_cells_init(&ovpn->gro_cells, dev);
32+
}
33+
34+
static void ovpn_net_uninit(struct net_device *dev)
35+
{
36+
struct ovpn_priv *ovpn = netdev_priv(dev);
37+
38+
gro_cells_destroy(&ovpn->gro_cells);
39+
}
2440

2541
static const struct net_device_ops ovpn_netdev_ops = {
42+
.ndo_init = ovpn_net_init,
43+
.ndo_uninit = ovpn_net_uninit,
2644
.ndo_start_xmit = ovpn_net_xmit,
2745
};
2846

drivers/net/ovpn/ovpnpriv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#ifndef _NET_OVPN_OVPNSTRUCT_H_
1111
#define _NET_OVPN_OVPNSTRUCT_H_
1212

13+
#include <net/gro_cells.h>
1314
#include <uapi/linux/if_link.h>
1415
#include <uapi/linux/ovpn.h>
1516

@@ -19,12 +20,14 @@
1920
* @mode: device operation mode (i.e. p2p, mp, ..)
2021
* @lock: protect this object
2122
* @peer: in P2P mode, this is the only remote peer
23+
* @gro_cells: pointer to the Generic Receive Offload cell
2224
*/
2325
struct ovpn_priv {
2426
struct net_device *dev;
2527
enum ovpn_mode mode;
2628
spinlock_t lock; /* protect writing to the ovpn_priv object */
2729
struct ovpn_peer __rcu *peer;
30+
struct gro_cells gro_cells;
2831
};
2932

3033
#endif /* _NET_OVPN_OVPNSTRUCT_H_ */

drivers/net/ovpn/proto.h

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
#ifndef _NET_OVPN_PROTO_H_
1111
#define _NET_OVPN_PROTO_H_
1212

13+
#include "main.h"
14+
15+
#include <linux/bitfield.h>
16+
#include <linux/skbuff.h>
17+
1318
/* When the OpenVPN protocol is ran in AEAD mode, use
1419
* the OpenVPN packet ID as the AEAD nonce:
1520
*
@@ -34,5 +39,48 @@
3439
#define OVPN_NONCE_WIRE_SIZE (OVPN_NONCE_SIZE - OVPN_NONCE_TAIL_SIZE)
3540

3641
#define OVPN_OPCODE_SIZE 4 /* DATA_V2 opcode size */
42+
#define OVPN_OPCODE_KEYID_MASK 0x07000000
43+
#define OVPN_OPCODE_PKTTYPE_MASK 0xF8000000
44+
#define OVPN_OPCODE_PEERID_MASK 0x00FFFFFF
45+
46+
/* packet opcodes of interest to us */
47+
#define OVPN_DATA_V1 6 /* data channel v1 packet */
48+
#define OVPN_DATA_V2 9 /* data channel v2 packet */
49+
50+
#define OVPN_PEER_ID_UNDEF 0x00FFFFFF
51+
52+
/**
53+
* ovpn_opcode_from_skb - extract OP code from skb at specified offset
54+
* @skb: the packet to extract the OP code from
55+
* @offset: the offset in the data buffer where the OP code is located
56+
*
57+
* Note: this function assumes that the skb head was pulled enough
58+
* to access the first 4 bytes.
59+
*
60+
* Return: the OP code
61+
*/
62+
static inline u8 ovpn_opcode_from_skb(const struct sk_buff *skb, u16 offset)
63+
{
64+
u32 opcode = be32_to_cpu(*(__be32 *)(skb->data + offset));
65+
66+
return FIELD_GET(OVPN_OPCODE_PKTTYPE_MASK, opcode);
67+
}
68+
69+
/**
70+
* ovpn_peer_id_from_skb - extract peer ID from skb at specified offset
71+
* @skb: the packet to extract the OP code from
72+
* @offset: the offset in the data buffer where the OP code is located
73+
*
74+
* Note: this function assumes that the skb head was pulled enough
75+
* to access the first 4 bytes.
76+
*
77+
* Return: the peer ID
78+
*/
79+
static inline u32 ovpn_peer_id_from_skb(const struct sk_buff *skb, u16 offset)
80+
{
81+
u32 opcode = be32_to_cpu(*(__be32 *)(skb->data + offset));
82+
83+
return FIELD_GET(OVPN_OPCODE_PEERID_MASK, opcode);
84+
}
3785

38-
#endif /* _NET_OVPN_PROTO_H_ */
86+
#endif /* _NET_OVPN_OVPNPROTO_H_ */

drivers/net/ovpn/socket.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,10 @@ static void ovpn_socket_release_kref(struct kref *kref)
2323
struct ovpn_socket *sock = container_of(kref, struct ovpn_socket,
2424
refcount);
2525

26-
if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
26+
if (sock->sock->sk->sk_protocol == IPPROTO_UDP) {
2727
ovpn_udp_socket_detach(sock);
28+
netdev_put(sock->ovpn->dev, &sock->dev_tracker);
29+
}
2830

2931
kfree_rcu(sock, rcu);
3032
}
@@ -179,7 +181,6 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
179181
goto sock_release;
180182
}
181183

182-
ovpn_sock->ovpn = peer->ovpn;
183184
ovpn_sock->sock = sock;
184185
kref_init(&ovpn_sock->refcount);
185186

@@ -190,6 +191,15 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
190191
goto sock_release;
191192
}
192193

194+
if (sock->sk->sk_protocol == IPPROTO_UDP) {
195+
/* in UDP we only link the ovpn instance since the socket is
196+
* shared among multiple peers
197+
*/
198+
ovpn_sock->ovpn = peer->ovpn;
199+
netdev_hold(peer->ovpn->dev, &ovpn_sock->dev_tracker,
200+
GFP_KERNEL);
201+
}
202+
193203
rcu_assign_sk_user_data(sock->sk, ovpn_sock);
194204
sock_release:
195205
release_sock(sock->sk);

drivers/net/ovpn/socket.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,19 @@ struct ovpn_peer;
2020
/**
2121
* struct ovpn_socket - a kernel socket referenced in the ovpn code
2222
* @ovpn: ovpn instance owning this socket (UDP only)
23+
* @dev_tracker: reference tracker for associated dev (UDP only)
2324
* @sock: the low level sock object
2425
* @refcount: amount of contexts currently referencing this object
2526
* @rcu: member used to schedule RCU destructor callback
2627
*/
2728
struct ovpn_socket {
28-
struct ovpn_priv *ovpn;
29+
union {
30+
struct {
31+
struct ovpn_priv *ovpn;
32+
netdevice_tracker dev_tracker;
33+
};
34+
};
35+
2936
struct socket *sock;
3037
struct kref refcount;
3138
struct rcu_head rcu;

0 commit comments

Comments
 (0)