Jeremy Friesner
Jeremy Friesner

Reputation: 73081

Calculating the maximum UDP payload size to avoid fragmentation on an Ethernet LAN

I've got a program that is designed to send/receive UDP packets across a Gigabit Ethernet LAN (note: not the general Internet), and to maximize throughput, I would like to have it make the packets as large as possible without causing any fragmentation.

I understand that the MTU size for Ethernet is 1500 bytes; however those 1500 bytes are used not only by my application's payload data but also by the packet's IP and UDP headers, which means that I need to reduce my payload size by the size of those headers in order to fit everything in under the MTU-size and avoid fragmentation.

Given that, I use the code shown below to calculate the maximum payload size I should pass to sendto(). The program below gives this output when I run it:

Recommended maximum payload size for an IPv4 packet is 1404 bytes.
Recommended maximum payload size for an IPv6 packet is 1388 bytes.

My question is: are my calculations correct, or have I missed some important detail?

#include <stdio.h>

/** The total maximum size of a UDP packet (including all the headers and payload data) that can be sent
 *  over a network without causing packet fragmentation.  1500 is appropriate for standard Ethernet LANs(?)
 */
const int RAW_MTU_SIZE_BYTES = 1500;

const int POTENTIAL_EXTRA_HEADERS_SIZE_BYTES = 64; /**< Extra room, just in case some router or VLAN headers need to be added to the packet also */

const int IPV4_HEADER_SIZE_BYTES = 24;  /**< Number of bytes in an IPv4 packet header: assumes worst-case scenario (i.e. that the options field is included) */
const int IPV6_HEADER_SIZE_BYTES = 40;  /**< Number of bytes in an IPv6 packet header: assuming no additional header chunks, of course */

const int UDP_HEADER_SIZE_BYTES  = (4*sizeof(short));  /**< Number of additional bytes in a UDP sub-header (sourceport, destport, length, checksum) */

/** Returns the number of application-payload bytes that we can fit into a UDP packet without causing packet fragmentation. */
const int GetRecommendedUDPPayloadSizeBytes(bool isForIPv6)
{
   const int ipHeaderSizeBytes = isForIPv6 ? IPV6_HEADER_SIZE_BYTES : IPV4_HEADER_SIZE_BYTES;
   return RAW_MTU_SIZE_BYTES - (ipHeaderSizeBytes+UDP_HEADER_SIZE_BYTES+POTENTIAL_EXTRA_HEADERS_SIZE_BYTES);
}

int main(int, char **)
{
   printf("Recommended maximum payload size for an IPv4 packet is %i bytes.\n", GetRecommendedUDPPayloadSizeBytes(false));
   printf("Recommended maximum payload size for an IPv6 packet is %i bytes.\n", GetRecommendedUDPPayloadSizeBytes(true));
   return 0;
}

Upvotes: 2

Views: 268

Answers (1)

SKi
SKi

Reputation: 8466

Because MTU of an interface can be different than 1500, it is not good idea to assume value of MTU.

Usually there is a way to ask MTU of a network interface from OS (SIOCSIFMTU ioctl in Linux).

If there are several links in the path of packets, the path MTU can be smaller than the MTU of the interface. For avoiding fragmentation in the path, you could utilize PATH-MTU discovery.

As ikegami already commented, IPv4 and IPv6 packets may have optional header stuff for making calculation of the optimal payload size even harder.

Upvotes: 3

Related Questions