How to Calculate MTU for Tunnels

Posted: April 7th, 2011 | Author: | Filed under: Blog, Networking | Tags: , , , , | 3 Comments »

WARNING: BORING ALERT!!!!

Packet Fragmentation Example

If you have any tunnels in your network you may notice at times packet loss between subnets or perhaps stalled web sessions. This usually has to do with a combination of MTU negotiation and packet fragmentation.

MTU 101

Maximum Transmission Unit refers to how much data in bytes the data layer can send forward. For ethernet the size is 1500 bytes, which coincides with how much data can fit in an ethernet frame. Within the MTU is another size called MSS (Maximum Segment Size) which refers to how much TCP data can be transmitted. This is also known as the payload and is usually 1460 bytes. The 40 bytes difference between the MTU and MSS sizes are for TCP/IP headers. But this can create a problem when GRE is introduced.

Enter the Tunnel

The big problem with GRE is that it doesn’t fit into the 7 layer dip of the OSI model. It acts as a separator between the network and transport layers. GRE adds a header to all the packets that will traverse the GRE tunnel, thus consume some of the 1500 bytes of the ethernet frame. The MTU then needs to be decreased to allow the packet to fit within the frame. This can result in packet fragmentation or packet loss as some packets will have a “don’t fragment” bit set.

Determine MTU

To optimize your network performance it would be best practice to determine the MTU through the tunnel. This size my vary depending upon encapsulation, encryption, and routing. To determine the MTU size we will conduct some tests with “don’t fragment” ping packets from a host on one side of the tunnel to a host on the other side of the tunnel.

First let’s take a look at how “don’t fragment” pings work. We’re going to send two pings (-c 2) with the don’t fragment (-D) bit set and specify the payload to be 1472 bytes (-s 1472)

homer:~ jordan$ ping -D -c 2 -s 1472 4.2.2.2
PING 4.2.2.2 (4.2.2.2): 1472 data bytes
1480 bytes from 4.2.2.2: icmp_seq=0 ttl=54 time=37.163 ms
1480 bytes from 4.2.2.2: icmp_seq=1 ttl=54 time=34.799 ms

This shows us that the MTU between us and 4.2.2.2 which is a public root DNS server is 1500. The difference between the MTU size (1500) and ping payload size (1472) is the ICMP headers of 28 bytes. This is important to note, as ping payloads used to test the MTU must be 28 bytes lower than the MTU value you are testing.

If we add one byte to this test it will cause the ping to be lost.

homer:~ jordan$ ping -D -c 2 -s 1473 4.2.2.2
PING 4.2.2.2 (4.2.2.2): 1473 data bytes
ping: sendto: Message too long
ping: sendto: Message too long

So let’s try and determine the MTU for this sample network. We have a host on each side with a default MTU of 1500 and tunnel in between the two of them. To determine the MTU we issue the command listed above

homer:~ jordan$ ping -D -c 2 -s 1472 172.16.10.10
PING 172.16.10.10 (172.16.10.10): 1472 data bytes
ping: sendto: Message too long
ping: sendto: Message too long

Clearly this shows us the payload is too large and thus the MTU is lower than 1500. So let’s lower the payload by 10 bytes and round it down, if it fails decrement the payload by 10 bytes again and again while testing until you have a successful test. Then increment by 1 byte until it stops working. The last test payload size, plus 28 bytes is your MTU.

Example:

homer:~ jordan$ ping -D -c 2 -s 1460 172.16.10.10
PING 172.16.10.10 (172.16.10.10): 1460 data bytes
ping: sendto: Message too long
ping: sendto: Message too long
homer:~ jordan$ ping -D -c 2 -s 1450 172.16.10.10
PING 172.16.10.10 (172.16.10.10): 1450 data bytes
ping: sendto: Message too long
ping: sendto: Message too long
homer:~ jordan$ ping -D -c 2 -s 1440 172.16.10.10
PING 172.16.10.10 (172.16.10.10): 1440 data bytes
1448 bytes from 172.16.10.10: icmp_seq=0 ttl=254 time=72.199 ms
1448 bytes from 172.16.10.10: icmp_seq=1 ttl=254 time=78.266 ms
homer:~ jordan$ ping -D -c 2 -s 1441 172.16.10.10
PING 172.16.10.10 (172.16.10.10): 1441 data bytes
ping: sendto: Message too long
ping: sendto: Message too long

Tada, the last payload that worked was 1440, therefore our MTU is 1468. Ping payload size of 1440 bytes + ICMP header of 28 bytes = MTU of 1468 bytes

I hope you enjoyed yourself as much as I have, please feel free to leave questions in the comments here.


3 Comments on “How to Calculate MTU for Tunnels”

  1. 1 IVAN said at 4:35 pm on August 22nd, 2014:

    Bien loco, excelente explicación.

  2. 2 Michael said at 1:50 am on March 3rd, 2015:

    Would it be possible to calculate the size of a payload which was causing DNSKey RRset transmission failures, due to exceeding a specific MTU size cap?

  3. 3 cpk said at 12:12 pm on September 9th, 2015:

    I love stuff like this. Thanks for the incrementation tip for finding an unknow MTU.

    Now to shoehorn some 8th grade algebra into a python script to automate it.


Leave a Reply