Maximum Transmission Unit (MTU) is the largest size in bytes that a certain layer can forward. The MTU is different for each protocol and medium that we use. Ethernet, for example, has an MTU of 1500 bytes by default.
This means that a single Ethernet frame can carry up to 1500 bytes of data. On top of this data, we add the Ethernet header. Typical header sizes are 14 bytes for Ethernet (add another 4 bytes if you use 802.1Q tagging).
Below is a picture with the different MTU fields that you might encounter:
You can see that a typical Ethernet header is 14 bytes, IP is 20 bytes and TCP is also 20 bytes. The maximum amount of payload that TCP can use is called the TCP MSS (Maximum Segment Size). This MSS value is the largest amount of data that a host can receive in a single TCP segment. This value is used to set a limit on the payload in order to prevent fragmentation and is sent in the SYN packet during the 3-way handshake. The MSS value isn’t synchronized between hosts, it can be different for each direction.
So why is all of this important to know? Let’s imagine we have an IP packet that is sent on our LAN. The size of the Ethernet frame will be like this:
- 1460 bytes of payload for TCP.
- 20 bytes for the TCP header.
- 20 bytes for the IP header.
- 14 bytes for the Ethernet header.
1460 (PAYLOAD) + 20 (TCP) + 20 (IP) = 1500 bytes + 14 (ETHERNET) = 1514 bytes in total.
Sending 1514 bytes is no problem for Ethernet, but some other mediums might have issues with large MTU values. Often problems arise when you add additional headers because of PPPoE, GRE Tunneling, or IPSEC since this reduces the available bytes for our MTU. To demonstrate this problem (and how to solve it!) I will use a simple network with a reduced MTU. Here’s what it looks like:
The network above has two routers, a web server (S1) behind R1 and a client (H1) behind R2. Here’s what the configuration looks like:
First, we’ll configure some IP addresses:
R1(config)#interface fastEthernet 0/0 R1(config-if)#ip address 192.168.12.1 255.255.255.0 R1(config)#interface fastEthernet 0/1 R1(config-if)#ip address 192.168.1.254 255.255.255.0
R2(config)#interface fastEthernet 0/0 R2(config-if)#ip address 192.168.12.2 255.255.255.0
R2(config)#interface fastEthernet 0/1 R2(config-if)#ip address 192.168.2.254 255.255.255.0
I’ll add some static routes for connectivity:
R1(config)#ip route 192.168.2.0 255.255.255.0 192.168.12.2
R2(config)#ip route 192.168.1.0 255.255.255.0 192.168.12.1
Here’s what the default MTU values look like:
R2#show interfaces fastEthernet 0/0 | include MTU MTU 1500 bytes, BW 100000 Kbit/sec, DLY 100 usec, R2#show ip interface fastEthernet 0/0 | include MTU MTU is 1500 bytes
The first MTU value is the interface MTU, it’s 1500 bytes by default for Ethernet. The second one is the IP MTU which is also 1500 bytes. Once you get above 1500 bytes, your router will start fragmenting the IP packets.
Is this limit of 1500 bytes working? There’s an easy way to find out. Let’s do a ping with the DF-bit (Don’t Fragment) between the routers:
R2#ping Protocol [ip]: Target IP address: 192.168.12.1 Repeat count : 1 Datagram size : Timeout in seconds : Extended commands [n]: y Source address or interface: Type of service : Set DF bit in IP header? [no]: y Validate reply data? [no]: Data pattern [0xABCD]: Loose, Strict, Record, Timestamp, Verbose[none]: v Loose, Strict, Record, Timestamp, Verbose[V]: Sweep range of sizes [n]: y Sweep min size : 1495 Sweep max size : 1505 Sweep interval : Type escape sequence to abort. Sending 11, [1495..1505]-byte ICMP Echos to 192.168.12.1, timeout is 2 seconds: Packet sent with the DF bit set Reply to request 0 (1 ms) (size 1495) Reply to request 1 (4 ms) (size 1496) Reply to request 2 (1 ms) (size 1497) Reply to request 3 (4 ms) (size 1498) Reply to request 4 (1 ms) (size 1499) Reply to request 5 (4 ms) (size 1500) Request 6 timed out (size 1501) Request 7 timed out (size 1502) Request 8 timed out (size 1503) Request 9 timed out (size 1504) Request 10 timed out (size 1505) Success rate is 54 percent (6/11), round-trip min/avg/max = 1/2/4 ms
In the ping above, you can see that the largest packet that I can send is 1500 bytes. The second packet with 1501 bytes can’t be sent because it is too large, and we set the DF-bit.
Let’s look at an actual packet between the client and the web server, see what these values look like in an actual frame:
Above, you can see the TCP MSS, which is 1460 bytes. What else can we see in Wireshark?
Above, you see that the total length of the IP packet is 1500 bytes (1460 bytes for TCP MSS + 40 bytes for the TCP/IP header). Ethernet adds another 14 bytes, which is how we get to 1514 bytes in total.
To simulate a network with a lower MTU, I will reduce the MTU of the FastEthernet 0/0 interface of R2:
R2(config)#interface fastEthernet 0/0 R2(config-if)#mtu 1400
By reducing the MTU to 1400 bytes, the largest TCP segment size will be only 1360 bytes (1400 – 40 = 1360). This is a scenario where users often complain that sending a ping is no problem, but accessing a website or something else doesn’t work. Why? Let’s look at the example below:
Above, you see a ping between the client and the web server. As you can see, the total length is only 74 bytes…no problem sending this because our MTU allows 1400 bytes. Now we will try to connect to the web server from the client using HTTP:
This is where things go wrong…as you can see above, the total length of the IP Packet is 1500 bytes which is 100 bytes above our MTU of 1400 bytes. It’s impossible to communicate between the client and the web server now.
How do we fix this? There are two solutions for this:
- Set the correct IP MTU value so the router knows when to fragment IP packets.
- Reduce the TCP MSS value for outgoing connections so there is less payload.
Here’s how to configure the correct IP MTU value: