Search code examples
c++udpmtu

How much data can I send in one UDP packet and still avoid fragmentation?


I have C++ classes that handles sending and receiving UDP packets. So far I used those to send signals (PING, WAKEUP, ...) in other words, very small packets and never had a problem.

Now I'd like to send large blocks of data (i.e. 0.5Mb), but to optimize the possibility of packet losses, I want to be able to do my own fragmentation. First I wrote a function that gives me the MTU size:

int udp_server::get_mtu_size() const
{
    if(f_mtu_size == 0)
    {
        struct ifreq ifr;
        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, "eth0", sizeof(ifr.ifr_name));
        if(ioctl(f_socket, SIOCGIFMTU, &ifr) == 0)
        {
            f_mtu_size = ifr.ifr_mtu;
        }
        else
        {
            f_mtu_size = -1;
        }
    }

    return f_mtu_size;
}

Note: I know about PMTUD which this function ignores. As mentioned below, this is to work on a controlled network so the MTU path won't just change on us.

This function is likely to return 1500 under Linux.

What is really not clear and seems contradictory between many answers is that this 1,500 bytes size would not be just my payload. It would possibly include some headers over which I have no control (i.e. Ethernet header + footer, IPv4 header, UDP header.)

From some other questions and answers, it feels like I can send 1,500 bytes of data without fragmentation, assuming all my MTUs are 1,500.

So... Which is true?

  1. My data buffer can have a size equal to MTU

  2. My data buffer must be MTU - sizeof(various-headers/footers)

P.S. The network is a LAN that we control 100%. The packets will travel from one main computer to a set of slave computers using UDP multicast. There is only one 1Gbps switch in between. Nothing more.


Solution

  • The size is very clearly defined in RFC-8085: UDP Usage Guidelines.

    https://www.rfc-editor.org/rfc/rfc8085#section-3.2

    There is the relevant bit about the size calculation for the payload.

    To determine an appropriate UDP payload size, applications MUST subtract the size of the IP header (which includes any IPv4 optional headers or IPv6 extension headers) as well as the length of the UDP header (8 bytes) from the PMTU size. This size, known as the Maximum Segment Size (MSS), can be obtained from the TCP/IP stack [RFC1122].

    So in C/C++, this becomes:

    #include <netinet/ip.h> // for iphdr
    #include <netinet/udp.h> // for udphdr
    
    int mss(udp.get_mtu_size());
    mss -= sizeof(iphdr);
    mss -= sizeof(udphdr);
    

    WARNING: The size of the IP header varies depending on options. If you use options that will increase the size, your MSS computation must take that in account.

    The size of the Ethernet header and footer are not included here because those are transparent to the UDP packet.