In this recipe, we focus on some of the basic techniques for optimizing TCP-based VPN tunnels. In a TCP-based VPN setup, the connection between the VPN endpoints is a regular TCP connection. This has advantages and drawbacks. The main advantage is that it is often easier to set up a TCP connection than a UDP connection, mostly due to firewall restrictions. The main drawback of tunneling TCP traffic over a TCP-based tunnel is that there is chance of severe performance penalties, especially when the network connection is poor. This performance penalty is caused by the tcp-over-tcp syndrome. The TCP protocol guarantees the ordered delivery of packets, thus if a packet is dropped along the way, the packet will be resent. Once the new packet is received, the packet order is restored. Until that time, all packets after the lost
packet are on hold. The problem with tunneling TCP traffic over a TCP connection is that both layers want to guarantee ordered packet delivery. This can lead to a large amount of retransmits and hence to a large performance penalty.
When tuned correctly, however, an OpenVPN tunnel over a TCP connection can achieve the same performance as an OpenVPN tunnel over a UDP connection. In this recipe, we will show some techniques for tuning such a TCP-based OpenVPN connection.
We use the following network layout:
Set up the client and server certificates using the Setting up the public and private keys recipe from Chapter 2, Client-server IP-only Networks. For this recipe, the server computer was running CentOS 6 Linux and OpenVPN 2.3.11. The client was running Windows 7 64bit and OpenVPN 2.3.11. Keep the configuration file basic-udp-server.conf
from the Server-side routing recipe from Chapter 2, Client-server IP-only Networks, as well as the client configuration file basic-udp-client.ovpn
from the Using an ifconfig-pool block recipe.
proto tcp port 1194 dev tun server 10.200.0.0 255.255.255.0 ca /etc/openvpn/cookbook/ca.crt cert /etc/openvpn/cookbook/server.crt key /etc/openvpn/cookbook/server.key dh /etc/openvpn/cookbook/dh2048.pem tls-auth /etc/openvpn/cookbook/ta.key 0 persist-key persist-tun keepalive 10 60 topology subnet user nobody group nobody daemon log-append /var/log/openvpn.log tcp-nodelay
example8-9-server.conf
.[root@server]# openvpn --config example8-9-server.conf
client proto tcp remote openvpnserver.example.com port 1194 dev tun nobind remote-cert-tls server ca "c:/program files/openvpn/config/ca.crt" cert "c:/program files/openvpn/config/client2.crt" key "c:/program files/openvpn/config/client2.key" tls-auth "c:/program files/openvpn/config/ta.key" 1
example8-9.ovpn
.iperf
on the server:[server]$ iperf -s
[WinClient]> iperf -c 10.200.0.1 -w 128k
On this particular network, the following settings were tested:
Protocol |
Result |
UDP |
147 Mbits/sec |
TCP |
115 Mbits/sec |
TCP with tcp-nodelay |
146 Mbits/sec |
As can be seen, the performance of running OpenVPN over TCP is almost identical to the performance of OpenVPN over UDP, when the --tcp-nodelay
directive is used.
When OpenVPN uses TCP as its underlying protocol, all packets are transferred over a regular TCP connection. By default, TCP connections make use of the Nagle algorithm, where smaller packets are held back and collected before they are sent. For an OpenVPN tunnel, this has an adverse effect on performance in most cases, hence it makes sense to disable the Nagle algorithm. By adding the --tcp-nodelay
directive, we disable the Nagle algorithm and we see an immediate increase in performance.
The two important parameters that can be tweaked for TCP-based connections are:
--tcp-nodelay
directive--tun-mtu
or
--link-mtu
directivesOn Linux, the MTU size of the TUN (or TAP) adapter can be adjusted on-the-fly, but on Windows, this is not as easy. OpenVPN must be configured to match the MTU size as specified on the server. Before the new MTU size is used, however, the MTU of the TAP adapter must be adjusted. Starting with Windows Vista, it is now also possible to do this on-the-fly, using the netsh
command:
[winclient]C:> netsh interface ipv4 show subinterfaces
[winclient]C:> netsh interface ipv4 set subinterface "1"
mtu=1400
Note that these commands must be run with elevated privileges.
If the MTU setting of the Windows TAP-Win32 adapter is larger than the MTU size configured by OpenVPN, the following message can appear in the OpenVPN log file:
... read from TUN/TAP [State=AT?c Err=[c:src21 ap-win32 apdrvr.c/2447] #O=4 Tx=[29510,0] Rx=[15309,0] IrpQ=[0,1,16] PktQ=[0,22,64] InjQ=[0,1,16]]: More data is available. (code=234)
For this particular network, all changes made to the MTU size (with the appropriate Windows reboot) did not have a positive effect on performance.
18.118.27.119