Part XIV - UDP

16. UDP Deep Dive

Datagram sockets, batching, worker sharding, checksum trade-offs, offloads, fragmentation, RTP, and DTLS media stacks.

1. 16.1 - UDP Header and Socket Model

UDP deliberately exposes a tiny transport header: ports for demultiplexing, a length field, and a checksum. There is no sequence number, acknowledgment, retransmission timer, congestion window, stream ID, or connection state. Any reliability, pacing, encryption, or session model must be added by the application or a protocol above UDP.

A UDP socket can be unconnected, where every sendto and recvfrom carries peer addressing, or connected, where connect pins the remote tuple and lets the process use send and recv. Connected UDP also gives the kernel a specific socket for ICMP error delivery.

  • Use SO_BROADCAST before sending to limited or subnet broadcast addresses.
  • Use IP_ADD_MEMBERSHIP and IP_MULTICAST_IF for multicast receive and interface selection.
  • Set unicast TTL with IP_TTL and multicast scope with IP_MULTICAST_TTL.

2. 16.2 - recvmmsg and sendmmsg

High-rate UDP services spend real CPU just crossing the user/kernel boundary. Linux recvmmsg and sendmmsg pass an array of mmsghdr entries so one syscall receives or sends a batch of datagrams. DNS servers, telemetry collectors, packet gateways, and QUIC stacks use this to keep packet rate from turning into syscall rate.

MSG_WAITFORONE is the latency compromise: return after at least one message while still allowing a short batch to form. It is useful when tail latency matters but empty syscalls are too expensive.

Minimal C Demo - sendmmsg Throughput

sendmmsg Throughput — C Demo
stdin (optional)

3. 16.3 - SO_REUSEPORT

SO_REUSEPORT lets multiple UDP sockets bind the same address and port. Instead of many workers contending on one shared socket, the kernel chooses a socket in the reuseport group, normally by hashing the packet tuple. This preserves flow locality for many workloads and scales receive queues across CPU cores.

Modern connection-oriented UDP protocols often need stronger affinity than the default tuple hash. A reuseport BPF selector can parse early bytes, such as a QUIC connection ID, and steer all packets for that connection to the same worker even if NAT rebinding changes the source port.

Minimal C Demo - SO_REUSEPORT Load Distribution

SO_REUSEPORT Load Distribution — C Demo
stdin (optional)

4. 16.4 - UDP-Lite

UDP-Lite replaces all-or-nothing checksum coverage with partial checksum coverage. The sender protects the protocol header and the most important bytes, while later payload bytes may be delivered even if corrupted. This only makes sense for media codecs that can conceal damage better than they can conceal packet loss.

On Linux the socket uses IPPROTO_UDPLITE, with UDPLITE_SEND_CSCOV and UDPLITE_RECV_CSCOV controlling checksum coverage. It is specialized and rarely appropriate for general application data.

5. 16.5 - GSO, GRO, and Zerocopy

UDP GSO and GRO reduce per-packet overhead without changing the wire protocol. With UDP_SEGMENT, the sender can hand a larger buffer to the kernel and request late segmentation into MTU-sized UDP datagrams. With UDP_GRO, the receiver can coalesce compatible datagrams before delivering them up the stack.

This is especially important for QUIC because the transport logic is in user space. MSG_ZEROCOPY can also reduce copy cost on large sends, but applications must handle completion notifications before reusing buffers.

6. 16.6 - UDP Fragmentation Risks

A UDP datagram larger than the path MTU can be fragmented by IPv4 when DF is clear. Reassembly happens only at the destination, and losing one fragment loses the entire datagram. Middleboxes also struggle because only the first fragment contains the UDP header, so later fragments lack the ports needed for normal policy and NAT lookup.

Robust UDP protocols usually avoid fragmentation: keep payloads below path MTU, set DF with IP_MTU_DISCOVER / IP_PMTUDISC_DO, process ICMP fragmentation-needed errors, or use packetization-layer PMTUD.

UDP is also common in reflection attacks because an attacker can spoof the victim as the source of a small query and cause a much larger response from an open reflector. TCP's handshake makes that source spoofing pattern much harder before data is sent.

Minimal C Demo - Fragment Loss

UDP Fragment Loss — C Demo
stdin (optional)

7. 16.7 - RTP, RTCP, DTLS, and Jitter

RTP adds the media timing UDP lacks. Sequence numbers detect loss and reordering, timestamps drive playout synchronization, and SSRC identifies a media source. The receiver uses a jitter buffer to trade a small amount of delay for smooth audio or video playback.

RTCP runs beside RTP and reports sender timing, receiver loss, jitter, and source descriptions. In WebRTC, ICE finds a UDP path, DTLS authenticates the peers and derives SRTP keys, SRTP protects media packets, and RTCP feeds quality feedback back to the sender.

8. Interview Prep

QuestionAnswer checkpoint
Why is UDP's 8-byte header insufficient for reliable delivery?It has no sequence numbers, ACKs, retransmission timers, flow control, or congestion control, so applications must add those if needed.
How does SO_REUSEPORT distribute UDP datagrams?A reuseport group contains multiple bound sockets; Linux picks one with a tuple hash unless a BPF selector overrides the choice.
Why does sendmmsg matter for QUIC?It batches many datagrams per syscall, reducing user/kernel crossings and CPU cost at high packet rates.
What makes UDP amplification attacks practical?UDP has no handshake, so spoofed-source requests can trigger larger replies toward a victim from reflectors.
How does GRO help QUIC receive performance?It coalesces compatible UDP datagrams before user-space delivery, reducing per-packet stack and syscall pressure.