MTU and OpenVPN: How does it work?

(2011-12-11)

I use OpenVPN relatively often, for example to get reliable IPv6-connectivity in places which don’t have IPv6 yet (miredo works well most of the time, but an own VPN is more stable). One of the things which I previously understood only a little bit was the MTU (Maximum Transfer Unit). Not configuring it properly leads to transferring more data than necessary (best case) or losing some packets entirely (worst case). The evil detail is that it only affects packets of a certain size – for example Kerberos packets are usually pretty large and thus often get dropped when your MTU is misconfigured.

MTU on the link

The MTU is a setting of the IP protocol and specifies how much data can fit into a single IP packet. Typical values for the MTU are 1500 bytes on Ethernet links or 1492 bytes on PPPoE links. You can find out the MTU by looking at your interface configuration:

$ ip link show dev eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
    link/ether 00:1f:16:3a:f9:b8 brd ff:ff:ff:ff:ff:ff

Let’s take an ICMP packet as an example: ICMP sits on top of IP. So, we have the IP header which is 20 bytes, plus the ICMP header which is 8 bytes (use Wireshark and look at the "Total Length" field of the IP packet to verify this). Therefore, with an MTU of 1500 bytes, you can fit 1500 - 20 - 8 = 1472 bytes in one packet. We can use ping(1) to send packets with that size:

$ ping -M do -c 1 -s 1472 www.heise.de
PING www.heise.de (193.99.144.85) 1472(1500) bytes of data.
1480 bytes from www.heise.de (193.99.144.85): icmp_req=1 ttl=243 time=96.4 ms

--- www.heise.de ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 96.489/96.489/96.489/0.000 ms

As you can see, ping takes the ICMP payload size of 1472 bytes, leading to a total size of 1500 bytes. I think that the -s argument varies between operating systems, because a lot of examples on the web use -s 1500, which is just wrong (on Linux at least). The -M do parameter advises ping to set the "do not fragment" bit.

Here is an example of the output you will get when you use the wrong MTU for your link:

$ ping -M do -c 1 -s 1500 www.heise.de
PING www.heise.de (193.99.144.85) 1500(1528) bytes of data.
From 87.198.114.189 icmp_seq=1 Frag needed and DF set (mtu = 1500)

--- www.heise.de ping statistics ---
0 packets transmitted, 0 received, +1 errors

In this case, I got an ICMP error telling me about the correct MTU size to use. This is called "Path MTU Discovery", but in some rare cases, administrators block all ICMP traffic in their firewall and therefore this feature does not work. In that case, you would just get no ping reply.

To find out the right MTU, decrease the ping size until you get a reply, then set the MTU to the total packet size. Don’t just pick one single host to test with, though – maybe the host has a misconfigured MTU :-).

MTU in OpenVPN

Above, we have figured out that the MTU indeed is 1500 bytes for our link. Now how do we configure OpenVPN for that? I assume you are running OpenVPN using UDP. The UDP header is 8 bytes (just like ICMP), so we will end up with 1472 bytes as the payload size. In our OpenVPN configuration, we will therefore use the link-mtu 1472 directive. This leads to OpenVPN setting the correct MTU on its tun0 interface:

$ ip link show dev tun0              
35: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1427 state UNKNOWN
    link/none 

The MTU is 1427 due to the OpenVPN overhead. We can verify that packets using the full MTU will arrive correctly by using ping:

$ sudo ip -4 route add 193.99.144.85 via 10.254.254.254
$ ping -M do -c 1 -s 1399 193.99.144.85
PING 193.99.144.85 (193.99.144.85) 1399(1427) bytes of data.
1407 bytes from 193.99.144.85: icmp_req=1 ttl=246 time=97.4 ms

--- 193.99.144.85 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 97.420/97.420/97.420/0.000 ms

By the way, I’ve sometimes seen OpenVPN error messages saying:

Authenticate/Decrypt packet error: packet HMAC authentication failed

Seeing these only some times (while the VPN itself works) is a hint to incorrect MTU configuration.

See also