Skip to content

Commit 11851cb

Browse files
ordexPaolo Abeni
authored and
Paolo Abeni
committed
ovpn: implement TCP transport
With this change ovpn is allowed to communicate to peers also via TCP. Parsing of incoming messages is implemented through the strparser API. Note that ovpn redefines sk_prot and sk_socket->ops for the TCP socket used to communicate with the peer. For this reason it needs to access inet6_stream_ops, which is declared as extern in the IPv6 module, but it is not fully exported. Therefore this patch is also adding EXPORT_SYMBOL_GPL(inet6_stream_ops) to net/ipv6/af_inet6.c. Cc: David Ahern <[email protected]> Cc: Eric Dumazet <[email protected]> Cc: Jakub Kicinski <[email protected]> Cc: Paolo Abeni <[email protected]> Cc: Simon Horman <[email protected]> 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 04ca149 commit 11851cb

File tree

11 files changed

+717
-11
lines changed

11 files changed

+717
-11
lines changed

drivers/net/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ config OVPN
125125
select CRYPTO_AES
126126
select CRYPTO_GCM
127127
select CRYPTO_CHACHA20POLY1305
128+
select STREAM_PARSER
128129
help
129130
This module enhances the performance of the OpenVPN userspace software
130131
by offloading the data channel processing to kernelspace.

drivers/net/ovpn/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,5 @@ ovpn-y += peer.o
1818
ovpn-y += pktid.o
1919
ovpn-y += socket.o
2020
ovpn-y += stats.o
21+
ovpn-y += tcp.o
2122
ovpn-y += udp.o

drivers/net/ovpn/io.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "crypto_aead.h"
2323
#include "netlink.h"
2424
#include "proto.h"
25+
#include "tcp.h"
2526
#include "udp.h"
2627
#include "skb.h"
2728
#include "socket.h"
@@ -211,6 +212,9 @@ void ovpn_encrypt_post(void *data, int ret)
211212
case IPPROTO_UDP:
212213
ovpn_udp_send_skb(peer, sock->sock, skb);
213214
break;
215+
case IPPROTO_TCP:
216+
ovpn_tcp_send_skb(peer, sock->sock, skb);
217+
break;
214218
default:
215219
/* no transport configured yet */
216220
goto err_unlock;

drivers/net/ovpn/main.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "io.h"
2323
#include "peer.h"
2424
#include "proto.h"
25+
#include "tcp.h"
2526
#include "udp.h"
2627

2728
static int ovpn_net_init(struct net_device *dev)
@@ -177,6 +178,8 @@ static int __init ovpn_init(void)
177178
goto unreg_rtnl;
178179
}
179180

181+
ovpn_tcp_init();
182+
180183
return 0;
181184

182185
unreg_rtnl:

drivers/net/ovpn/ovpnpriv.h

Lines changed: 1 addition & 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 <linux/workqueue.h>
1314
#include <net/gro_cells.h>
1415
#include <uapi/linux/if_link.h>
1516
#include <uapi/linux/ovpn.h>

drivers/net/ovpn/peer.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define _NET_OVPN_OVPNPEER_H_
1212

1313
#include <net/dst_cache.h>
14+
#include <net/strparser.h>
1415

1516
#include "crypto.h"
1617
#include "socket.h"
@@ -25,6 +26,18 @@
2526
* @vpn_addrs.ipv4: IPv4 assigned to peer on the tunnel
2627
* @vpn_addrs.ipv6: IPv6 assigned to peer on the tunnel
2728
* @sock: the socket being used to talk to this peer
29+
* @tcp: keeps track of TCP specific state
30+
* @tcp.strp: stream parser context (TCP only)
31+
* @tcp.user_queue: received packets that have to go to userspace (TCP only)
32+
* @tcp.out_queue: packets on hold while socket is taken by user (TCP only)
33+
* @tcp.tx_in_progress: true if TX is already ongoing (TCP only)
34+
* @tcp.out_msg.skb: packet scheduled for sending (TCP only)
35+
* @tcp.out_msg.offset: offset where next send should start (TCP only)
36+
* @tcp.out_msg.len: remaining data to send within packet (TCP only)
37+
* @tcp.sk_cb.sk_data_ready: pointer to original cb (TCP only)
38+
* @tcp.sk_cb.sk_write_space: pointer to original cb (TCP only)
39+
* @tcp.sk_cb.prot: pointer to original prot object (TCP only)
40+
* @tcp.sk_cb.ops: pointer to the original prot_ops object (TCP only)
2841
* @crypto: the crypto configuration (ciphers, keys, etc..)
2942
* @dst_cache: cache for dst_entry used to send to peer
3043
* @bind: remote peer binding
@@ -45,6 +58,28 @@ struct ovpn_peer {
4558
struct in6_addr ipv6;
4659
} vpn_addrs;
4760
struct ovpn_socket __rcu *sock;
61+
62+
struct {
63+
struct strparser strp;
64+
struct sk_buff_head user_queue;
65+
struct sk_buff_head out_queue;
66+
bool tx_in_progress;
67+
68+
struct {
69+
struct sk_buff *skb;
70+
int offset;
71+
int len;
72+
} out_msg;
73+
74+
struct {
75+
void (*sk_data_ready)(struct sock *sk);
76+
void (*sk_write_space)(struct sock *sk);
77+
struct proto *prot;
78+
const struct proto_ops *ops;
79+
} sk_cb;
80+
81+
struct work_struct defer_del_work;
82+
} tcp;
4883
struct ovpn_crypto_state crypto;
4984
struct dst_cache dst_cache;
5085
struct ovpn_bind __rcu *bind;

drivers/net/ovpn/socket.c

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,18 @@
1616
#include "io.h"
1717
#include "peer.h"
1818
#include "socket.h"
19+
#include "tcp.h"
1920
#include "udp.h"
2021

2122
static void ovpn_socket_release_kref(struct kref *kref)
2223
{
2324
struct ovpn_socket *sock = container_of(kref, struct ovpn_socket,
2425
refcount);
2526

26-
if (sock->sock->sk->sk_protocol == IPPROTO_UDP) {
27+
if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
2728
ovpn_udp_socket_detach(sock);
28-
netdev_put(sock->ovpn->dev, &sock->dev_tracker);
29-
}
30-
31-
kfree_rcu(sock, rcu);
29+
else if (sock->sock->sk->sk_protocol == IPPROTO_TCP)
30+
ovpn_tcp_socket_detach(sock);
3231
}
3332

3433
/**
@@ -38,10 +37,12 @@ static void ovpn_socket_release_kref(struct kref *kref)
3837
*
3938
* This function is only used internally. Users willing to release
4039
* references to the ovpn_socket should use ovpn_socket_release()
40+
*
41+
* Return: true if the socket was released, false otherwise
4142
*/
42-
static void ovpn_socket_put(struct ovpn_peer *peer, struct ovpn_socket *sock)
43+
static bool ovpn_socket_put(struct ovpn_peer *peer, struct ovpn_socket *sock)
4344
{
44-
kref_put(&sock->refcount, ovpn_socket_release_kref);
45+
return kref_put(&sock->refcount, ovpn_socket_release_kref);
4546
}
4647

4748
/**
@@ -65,6 +66,7 @@ static void ovpn_socket_put(struct ovpn_peer *peer, struct ovpn_socket *sock)
6566
void ovpn_socket_release(struct ovpn_peer *peer)
6667
{
6768
struct ovpn_socket *sock;
69+
bool released;
6870

6971
might_sleep();
7072

@@ -89,11 +91,26 @@ void ovpn_socket_release(struct ovpn_peer *peer)
8991
* detached before it can be picked by a concurrent reader.
9092
*/
9193
lock_sock(sock->sock->sk);
92-
ovpn_socket_put(peer, sock);
94+
released = ovpn_socket_put(peer, sock);
9395
release_sock(sock->sock->sk);
9496

9597
/* align all readers with sk_user_data being NULL */
9698
synchronize_rcu();
99+
100+
/* following cleanup should happen with lock released */
101+
if (released) {
102+
if (sock->sock->sk->sk_protocol == IPPROTO_UDP) {
103+
netdev_put(sock->ovpn->dev, &sock->dev_tracker);
104+
} else if (sock->sock->sk->sk_protocol == IPPROTO_TCP) {
105+
/* wait for TCP jobs to terminate */
106+
ovpn_tcp_socket_wait_finish(sock);
107+
ovpn_peer_put(sock->peer);
108+
}
109+
/* we can call plain kfree() because we already waited one RCU
110+
* period due to synchronize_rcu()
111+
*/
112+
kfree(sock);
113+
}
97114
}
98115

99116
static bool ovpn_socket_hold(struct ovpn_socket *sock)
@@ -105,6 +122,8 @@ static int ovpn_socket_attach(struct ovpn_socket *sock, struct ovpn_peer *peer)
105122
{
106123
if (sock->sock->sk->sk_protocol == IPPROTO_UDP)
107124
return ovpn_udp_socket_attach(sock, peer->ovpn);
125+
else if (sock->sock->sk->sk_protocol == IPPROTO_TCP)
126+
return ovpn_tcp_socket_attach(sock, peer);
108127

109128
return -EOPNOTSUPP;
110129
}
@@ -191,7 +210,14 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
191210
goto sock_release;
192211
}
193212

194-
if (sock->sk->sk_protocol == IPPROTO_UDP) {
213+
/* TCP sockets are per-peer, therefore they are linked to their unique
214+
* peer
215+
*/
216+
if (sock->sk->sk_protocol == IPPROTO_TCP) {
217+
INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work);
218+
ovpn_sock->peer = peer;
219+
ovpn_peer_hold(peer);
220+
} else if (sock->sk->sk_protocol == IPPROTO_UDP) {
195221
/* in UDP we only link the ovpn instance since the socket is
196222
* shared among multiple peers
197223
*/

drivers/net/ovpn/socket.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,25 @@ struct ovpn_peer;
2121
* struct ovpn_socket - a kernel socket referenced in the ovpn code
2222
* @ovpn: ovpn instance owning this socket (UDP only)
2323
* @dev_tracker: reference tracker for associated dev (UDP only)
24+
* @peer: unique peer transmitting over this socket (TCP only)
2425
* @sock: the low level sock object
2526
* @refcount: amount of contexts currently referencing this object
26-
* @rcu: member used to schedule RCU destructor callback
27+
* @work: member used to schedule release routine (it may block)
28+
* @tcp_tx_work: work for deferring outgoing packet processing (TCP only)
2729
*/
2830
struct ovpn_socket {
2931
union {
3032
struct {
3133
struct ovpn_priv *ovpn;
3234
netdevice_tracker dev_tracker;
3335
};
36+
struct ovpn_peer *peer;
3437
};
3538

3639
struct socket *sock;
3740
struct kref refcount;
38-
struct rcu_head rcu;
41+
struct work_struct work;
42+
struct work_struct tcp_tx_work;
3943
};
4044

4145
struct ovpn_socket *ovpn_socket_new(struct socket *sock,

0 commit comments

Comments
 (0)