Quantifying Bandwidth and Processing Overhead in TURN Relays
By Nadia Ferrante
Wire Overhead and the Framing Penalty
Traversal Using Relays around NAT (TURN), specified in RFC 8656, solves symmetric NAT traversal by anchoring both signaling and media legs to an intermediate public IP address. The specification accomplishes address virtualization cleanly, but it introduces wire expansion that is frequently omitted during edge capacity planning.
"A TURN server is also a STUN server, so all TURN messages are STUN messages." — RFC 8656
Because all control interactions are Session Traversal Utilities for NAT (STUN) transactions, engineers often assume the data-plane encapsulation overhead matches the control plane. It does not. The wire overhead depends entirely on whether the client negotiates a channel binding or falls back to indication primitives.
ChannelData Versus Indication Framing
A standard conversational voice stream typically deploys the Opus codec operating with a 20 ms packetization interval (ptime), generating exactly 50 packets per second (pps). At an application target bitrate of 32 kbps, the raw audio frame is 80 bytes. Under standard Real-time Transport Protocol (RFC 3550) framing, the media layer adds a 12-byte RTP fixed header, yielding a 92-byte payload.
When routed directly between peers via UDP, the transport adds an 8-byte UDP header and a 20-byte IPv4 header (or 40 bytes under IPv6). The un-relayed packet on the wire is 120 bytes. At 50 pps, the layer-3 throughput is 48.0 kbps per direction.
When relayed over a TURN allocation using the Send and Data indications defined in RFC 8656 Section 6 and Section 7, overhead balloons. A Send Indication is a full STUN message:
- 20-byte STUN message header.
XOR-PEER-ADDRESSattribute: 4-byte attribute header plus 8 bytes of value for IPv4 (12 bytes total).DATAattribute: 4-byte attribute header plus 92 bytes of RTP payload (96 bytes total).
The resulting STUN message is 128 bytes. Wrapped in UDP (8 bytes) and IPv4 (20 bytes), the wire footprint hits 156 bytes per packet. Throughput climbs to 62.4 kbps—a 30% expansion over direct peer-to-peer transport for the exact same 32 kbps encoded payload.
To reduce this bloat, clients issue a ChannelBind request. A successful binding assigns a 16-bit channel number (ranging from 0x4000 to 0x7FFF) to a specific peer transport address. Once established, media transfers use ChannelData framing:
- Channel Number: 2 bytes.
- Length: 2 bytes (signaling the size of the inner payload, here 92 bytes).
- Inner Payload: 92 bytes.
- Padding: 0 bytes (92 is already a multiple of 4; RFC 8656 requires padding to a 4-byte boundary).
The ChannelData header is precisely 4 bytes. Added to the 92-byte RTP packet, the payload is 96 bytes. Encapsulated in UDP and IPv4, the packet size becomes 124 bytes. At 50 pps, wire rate is 49.6 kbps. While this represents only a 3.3% increase over direct UDP framing, you must multiply this cost across both legs of the relay.
Multi-Leg Amplification Across Edge Networks
A TURN relay does not simply pass packets through an internal routing table; it terminates two distinct transport legs. For an allocation serving two endpoints communicating through the server:
1. Client to Relay: 124 bytes per packet (IPv4 + UDP + ChannelData + RTP). 2. Relay to Peer: 120 bytes per packet (IPv4 + UDP + RTP).
The relay node ingests 124 bytes and egresses 120 bytes for a single directional frame, handling 244 bytes of aggregate network traffic per 20 ms interval. In a bidirectional conversation, both participants send at 50 pps. The TURN node handles 200 packet operations per second for one single-channel call, processing 488 bytes every 20 ms.
Scaled to 10,000 concurrent two-party calls where both sides rely on the relay, the relay infrastructure must process 2,000,000 packets per second (2 Mpps) and switch 195.2 Mbps of sustained, symmetric throughput. If IPv6 is deployed on the client leg, add 20 bytes per packet. If clients fall back to TURN over TLS (typically on port 443 to bypass restrictive enterprise firewalls), TLS record framing (5 bytes) plus TCP framing (20–60 bytes) and MAC-layer framing destroy any expectation of wire efficiency.
Operating System State and Kernel Dispatch Costs
Bandwidth exhaustion is rarely what degrades a TURN relay at scale. Packet rate and kernel socket operations fail first.
Context Switches and epoll Boundary Overhead
A TURN server operating in userspace relies on epoll (or kqueue on BSD variants) to register readiness across thousands of file descriptors. In standard configurations, each allocation allocates at least one relayed socket bound to an ephemeral port allocated from the range configured by the operator.
At 2 Mpps, dispatching individual packets via recvfrom() and sendto() invokes 4,000,000 system calls per second. The CPU spends the majority of its execution budget servicing kernel-to-userspace transitions, copying packet buffers, and updating virtual memory page tables. Using recvmmsg() and sendmmsg() mitigates system call frequency by batching up to 32 or 64 messages per call, but it introduces a trade-off: batching holds packets in kernel buffers until the batch size or timeout is reached, which artificially injects jitter into time-sensitive audio streams.
` +--------------------------------------------------------------+
| Userspace TURN Daemon |
|---|
| +---------------------+ +----------------------+ |
| 5-Tuple Hash Table | Channel/Perm Table |
| +----------+----------+ +----------+-----------+ |
| Linux Kernel |
| v v |
| [ UDP Socket Buffer ] [ UDP Socket Buffer ] |
| ^ |
| Core Network v |
| Client Ingress (pps) Peer Egress (pps) |