docs: name the RFC deviation, correct the Kubernetes Service claim - #14
Merged
Merged
Conversation
Two corrections prompted by pion/turn#284, the still-open request for the single-port mode uTURN implements. Both verified against the sources. The shared relay address is a spec deviation, not a missing feature. RFC 5766 Section 5: "Both the relayed transport address and the 5-tuple MUST be unique across all allocations, so either one can be used to uniquely identify the allocation." RFC 8656 Section 6 keeps the requirement for the relayed transport address. uTURN honours the 5-tuple half and gives up the other, and everything else in the docs follows from that - it is why pairing must be inferred from ICE ufrags at all. Listing "no per-allocation relay address" under out-of-scope made a design decision look like a gap. The pion thread also sketches the workaround uTURN took, so it is cited. Several replicas behind one address do not work, and the README said the opposite. It claimed the exposed surface is "a single 3478/udp Service". All allocation state is in-process (AllocationTable's DashMaps, no shared store) and client-to-client resolves both parties inside one instance, so every participant of a call must reach the same process. Kubernetes Services "select a backend Pod at random" by default, and sessionAffinity: ClientIP - what STUNner sets on its Gateway Services - only pins each client individually: two clients have two source IPs and can land on two pods, where neither sees the other's ufrag registration. Documented as one replica per Service, scale out by instance. Note this bounds the STUNner comparison rather than the reverse: STUNner scales out fine here, because its dataplane relays to a backend reachable from any pod. Docs only; no behaviour change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two docs corrections prompted by pion/turn#284 — the still-open request for exactly the single-port mode uTURN implements. Both claims verified against primary sources before writing.
1. The shared relay address is a spec deviation, not a missing feature
ARCHITECTURE.mdlisted "per-allocation relay addresses" under deliberately out of scope, which reads like an unimplemented nicety. It is a deviation from a MUST:RFC 8656 §6 carries the requirement forward for the relayed transport address.
uTURN honours the 5-tuple half — a client is still identified by its source address — and gives up the other half. That is worth stating plainly because everything else in the docs follows from it: one relayed transport address shared by every allocation is precisely why a packet cannot be attributed by its destination, why the pairing must come from the payload's ICE ufrag, and why both parties must be ICE agents. Naming the cause makes the constraints read as consequences instead of a list of quirks.
The pion thread is cited because it contains both the objection (
renandincer's analysis of what a single 2-tuple cannot disambiguate) and the sketch of the way out that uTURN took: "keep track of the ICE connectivity check STUN packets over the TURN server and somehow tie the third party peer into the mix."2. Several replicas behind one Service do not work — the README claimed they do
Introduced by me in #13: the STUNner section said the exposed surface is "a single
3478/udpService". That is true for one replica and wrong beyond it.AllocationTable'sDashMaps, no shared store — and client-to-client relaying resolves both parties inside one instance. Every participant of a call must therefore reach the same process.sessionAffinitydefaults toNone).sessionAffinity: ClientIPis a partial fix only. It pins each client to a pod, which keeps one client's allocation intact — but two clients have two source IPs and can still be pinned to two different pods, and neither would see the other's ufrag registration. This is the harder half and affinity cannot solve it.Documented as: one replica per Service, scale out by adding instances and steering a whole call to one of them.
Worth noting which way this cuts: it bounds uTURN, not STUNner. STUNner scales its dataplane out fine, because its pods relay to a backend any of them can reach over pod networking — and STUNner does set
sessionAffinity: ClientIPon the Services exposing its Gateways, for the client-pinning half. Sorg0now's remark in the thread ("You cannot expose a media server over a Kubernetes Service anyway") is too absolute as stated, but the underlying point applies squarely to uTURN.Verification
sessionAffinitysemantics (defaultNone,clientIP.timeoutSecondsdefault 10800) from the Kubernetes docs source.sessionAffinity: ClientIPusage from its owndocs/GATEWAY.md.src/lookup/table.rs(no redis/etcd/cluster dependency anywhere insrcorCargo.toml).cargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test(65 passed) clean. Docs only; no behaviour change.Note on release
This lands after
v0.3.3was tagged and pushed. Nothing in the release is wrong as shipped — the code is unchanged — but the README as tagged carries the replica claim. Worth av0.3.4docs release if you want the published docs to match, otherwise it rides along with the next release.🤖 Generated with Claude Code