Understanding UDP MTU (65535) vs Ethernet Frame Size (1500): Fragmentation in Network Protocols


1 views

When working with UDP sockets, developers often encounter this puzzling scenario: The theoretical maximum UDP datagram size is 65,535 bytes (including 8-byte header), yet standard Ethernet frames only support 1,500 bytes maximum transmission unit (MTU). This apparent contradiction stems from how network protocols handle packet fragmentation.

Let's examine the key components involved:

  • UDP Layer: Maximum payload size = 65,507 bytes (65,535 - 8 byte header - 20 byte IP header)
  • IP Layer: Handles fragmentation when packets exceed MTU
  • Ethernet Layer: 1,500 byte MTU (typically 1,472 bytes payload after headers)

The IP protocol automatically handles fragmentation when sending large UDP packets:

// Sender creates large UDP packet (65,507 bytes payload)
char buffer[65507];
send(socket_fd, buffer, sizeof(buffer), 0);

// Network stack automatically:
// 1. Fragments into multiple IP packets
// 2. Each fits within Ethernet MTU
// 3. Reassembles at receiver

Here's how to verify fragmentation behavior programmatically:

// Sender test code
int main() {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    char buf[65507];
    
    // Test various sizes
    for (int size = 1; size <= 65507; size += 1000) {
        int sent = sendto(sock, buf, size, 0, ...);
        printf("Sent %d/%d bytes\\n", sent, size);
    }
    return 0;
}

// Receiver code
int main() {
    char buf[65507];
    while (1) {
        int received = recvfrom(sock, buf, sizeof(buf), 0, ...);
        printf("Received %d bytes\\n", received);
    }
}
  • IP header contains fragmentation flags and offsets
  • Don't assume all fragments will arrive - UDP is connectionless
  • Path MTU discovery may reduce effective maximum size
  • Setsockopt options like IP_MTU_DISCOVER affect behavior

While fragmentation works, it's often better to:

  1. Design applications to use smaller packets
  2. Implement application-level segmentation
  3. Consider TCP for large data transfers
  4. Handle retransmission at application layer if needed

When working with UDP sockets in C, many developers encounter this curious behavior:

char buffer[100000];
for(int i=1; i<100000; i++) {
    int len = send(socket_id, buffer, i, 0);
    if(len == -1) {
        printf("Failed at %d: %s\n", i, strerror(errno));
        break;
    }
    printf("Sent %d bytes\n", len);
}

The code fails when trying to send packets larger than 65507 bytes (65535 - 20 - 8), yet Ethernet's maximum frame size is only 1500 bytes. This apparent contradiction involves several networking layers.

Modern networking operates through protocol layers, each with its own size limitations:

  • UDP Layer: Theoretical maximum of 65535 bytes (including headers)
  • IP Layer: Handles fragmentation when packets exceed MTU
  • Ethernet Layer: 1500 byte MTU (1518 byte frame including headers)

When your application sends a large UDP packet:

// This appears as one operation to the application
send(socket_id, large_buffer, 50000, 0);

The IP layer automatically fragments this into smaller packets that fit within the MTU:

// What actually gets sent at Ethernet level:
// Packet 1: 1480 bytes payload (1500 total with headers)
// Packet 2: 1480 bytes payload
// ...
// Packet N: remaining bytes

While fragmentation works, it's often better to handle chunking at the application level:

#define CHUNK_SIZE 1472

void send_large_data(int socket, const char* data, size_t length) {
    size_t sent = 0;
    while(sent < length) {
        size_t chunk = (length-sent > CHUNK_SIZE) ? CHUNK_SIZE : length-sent;
        send(socket, data+sent, chunk, 0);
        sent += chunk;
    }
}

The maximum UDP payload is calculated as:

Maximum UDP Payload = 65535 (max IP packet size)
                   - 20 (IPv4 header)
                   - 8 (UDP header)
                   = 65507 bytes

This explains why your send() fails beyond this size - it's hitting the UDP protocol limit, not the Ethernet limit.

Large UDP packets have several drawbacks:

  • Increased likelihood of packet loss (losing one fragment drops entire packet)
  • Memory overhead for reassembly buffers
  • Potential for fragmentation attacks in insecure environments

For most applications, keeping UDP packets below the path MTU (often 1500 bytes) provides better performance and reliability.