How to calculate MSS and MTU when setting up pfSense

How to calculate the Maximum Segment Size (MSS) and Maximum Transmission Unit (MTU) when setting up pfSense

What is MTU?

MTU stands for Maximum Transmission Unit. It is a setting that controls the largest size of a single packet of data that can be sent over a network. Think of it like a postcard, just as a postcard has a limit on the amount of text you can write on it, a network has a limit on the amount of data that can be sent in one packet.

The MTU setting makes sure that packets of data sent over the network are not too big and can be properly handled by the devices on the network. It helps to prevent data from getting lost or delayed, and ensures that the network runs efficiently.

What is MSS?

MSS is a setting that helps control how much information your computer can send to other computers at one time. Think of it like a package or a box that your computer uses to send information. Just like a box can only fit a certain amount of things inside, MSS makes sure that your computer only sends a certain amount of information at one time. This helps make sure that all the information gets to the other computer correctly and nothing gets lost or wasted.

How to check maximum MTU size using the ping Command

You can use the ping command with the “Don’t Fragment” (DF) flag and a large packet size to determine the maximum MTU size for a network. The process is called “ping of death” or “ping flood”. The idea is to send a ping packet with a large size and see if it reaches the destination without getting fragmented. If the packet is too large and gets fragmented, the destination will respond with an “ICMP Fragmentation Needed” message, which includes the maximum MTU size that can be used without fragmentation.

The “ping” command uses the Internet Control Message Protocol (ICMP) to send echo request (ping) and echo reply (pong) messages between devices. These messages have an overhead of 28 bytes, which includes the following:

  • 8 bytes for the ICMP header: This includes the type, code, and checksum fields.
  • 20 bytes for the IP header: This includes the version, header length, type of service, total length, identification, flags, fragment offset, time to live, protocol, header checksum, and source and destination IP addresses.

So, when you use the “ping” command to check the Maximum Transmission Unit (MTU) size, you need to take this overhead into account.

For example, if you want to send a packet of 1500 bytes, the actual packet size that will be sent over the network is 1500 + 28 = 1528 bytes, because the packet size includes the overhead of the ICMP and IP headers.

Using the ping command to check the maximum MTU size:

Windows

  • Open a command prompt or terminal
  • Type “ping -f -l [packet size] [destination IP or hostname]”
  • Replace packet size with a large number, such as 1500.
  • Replace destination IP address with the hostname or IP address of the device to test

The -f to specify not to fragment the packets, and the -s to specify the size.

Linux

  • Open a terminal or console
  • Type “ping -M do -s [packet size] [destination IP or hostname]”
  • Replace the packet size with a large number, such as 1500.
  • Replace the destination IP or hostname with the hostname or IP address of the device to test

The -M do flag is for the “Don’t Fragment” option, and the -s option is used to specify the packet size.

Example:

In this example using Linux we’ll start with 1500 for our MTU:
ping -c 1 -M do -s 1500 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 1500(1528) bytes of data.
ping: local error: message too long, mtu=1500

Now we can keep reducing until we get a reponse:
ping -s 1466 -M do 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 1466(1494) bytes of data.
From 10.1.8.1 icmp_seq=1 Frag needed and DF set (mtu = 1492)

Here we can see our MTU is 1492, but we’re getting the message about fragmentation, this is because the MTU is set to 1492, but as mentioned above the ping overhead is 28 bytes so 1492-28 = 1464 so lets try that:
ping -s 1464 -M do 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 1464(1492) bytes of data.
76 bytes from 8.8.8.8: icmp_seq=1 ttl=57 (truncated)

We have a response! So our MTU is indeed 1492 (1464 + our ping overhead of 28 = 1492).

Taking overhead into consideration at ping time

On linux we can simplify this to not have to worry about the ping overhead on the command line as follows:

ping -s $((1492 -28)) -M do 8.8.8.8

PING 8.8.8.8 (8.8.8.8) 1464(1492) bytes of data.
76 bytes from 8.8.8.8: icmp_seq=1 ttl=57 (truncated)
76 bytes from 8.8.8.8: icmp_seq=2 ttl=57 (truncated)

On Windows we can achieve a similar thing using powershell:
ping -f -l $((1500-28)) 8.8.8.8

How to determine the maximum MSS size

To determine the Maximum Segment Size (MSS) if the Maximum Transmission Unit (MTU) is 1500, you need to subtract the size of the protocol headers from the MTU. The headers include the IP header, TCP header, and in case of PPPoE, an additional 8 bytes PPPoE header.

For example, if you have an MTU of 1500 and you are using the IP and TCP protocols, the calculation would look like this:

MSS = MTU - IP header size - TCP header size - PPPoE header size

The IP header size is typically 20 bytes and the TCP header size is typically 20 bytes, PPPoE header size is 8 bytes

So, MSS = 1500 - 20 - 20 - 8 = 1452 bytes.

It’s important to note that the MSS value should be adjusted accordingly if the IP or TCP header size is different. Also, some devices or routers may automatically adjust the MSS value for you, so you should check the documentation or consult the vendor for more information.

So in this case, the MSS is 1452 bytes which means that the maximum amount of data that can be sent in a single packet on this network is 1452 bytes.