Skip to content

Send prflx type preference in PRIORITY attribute - #1026

Merged
JoTurk merged 2 commits into
pion:mainfrom
ilay-decart:prflx-priority-attr
Oct 12, 2026
Merged

JoTurk merged 2 commits into
pion:mainfrom
ilay-decart:prflx-priority-attr

Conversation

@ilay-decart

Copy link
Copy Markdown
Contributor

Description

Binding requests sent PriorityAttr(local.Priority()): the local candidate's own priority, with the host type preference (126) for a host candidate. RFC 8445 §7.1.1 requires the PRIORITY attribute to be computed "for the local candidate, but with the candidate type preference of peer-reflexive candidates", which is what libwebrtc sends (Connection::prflx_priority()).

Since #877 a receiving agent assigns a discovered peer-reflexive candidate the request's PRIORITY (§7.3.1.3). With the sender bug, a pion peer that reaches a pion agent through NAT gets a peer-reflexive candidate with host priority; when the agent can also validate the peer's signalled host candidate, the two pairs tie, getBestValidCandidatePair keeps the earlier peer-reflexive pair, and nomination waits PrflxAcceptanceMinWait (1 s) although the host pair succeeded within milliseconds. Before #877 the host pair outranked the peer-reflexive pair (126 vs 110) and was nominated immediately.

This change:

  • adds Candidate.prflxPriority(): the candidate's priority with the top byte replaced by the peer-reflexive type preference (TCP offset applied as for TypePreference), keeping local preference and component, including for candidates with a priority override, as libwebrtc does;
  • uses it in controllingSelector.PingCandidate, controllingSelector.nominatePair, controlledSelector.PingCandidate and Agent.sendNominationRequest;
  • adds TestBindingRequestPriorityAttr, which decodes the sent request and checks the attribute for the controlling ping, the controlled ping, the nomination and the renomination request. Against main the test fails at all four assertions.

Compatibility: receivers without #877 ignore the attribute. Receivers with #877 now rank peer-reflexive candidates discovered from pion peers as they ranked them before #877, and as they already rank the ones discovered from browsers.

Observed in production with a LiveKit SFU (livekit/ice v4.4.0 fork) and Go SDK participants in the same VPC: moving the SFU from v4.2.2 to v4.4.0 took 75-90% of those connects from ~0.01 s to ~1.0 s, browsers unaffected. A v4 backport is on ilay-decart/ice branch prflx-priority-attr-v4 and applies cleanly to v4; happy to open it as a PR if wanted.

go test -race ./... and golangci-lint run (v2.10.1) pass locally.

Resolves #1025

Co-authored-by: Claude Fable 5.1 noreply@anthropic.com

RFC 8445 Section 7.1.1 requires the PRIORITY attribute of a Binding
request to carry the local candidate's priority computed with the type
preference of peer-reflexive candidates. The selectors and the
renomination path sent Candidate.Priority() instead, so a host candidate
announced itself with the host type preference (126).

Since pion#877 a remote agent assigns a newly discovered peer-reflexive
candidate the priority from the request (Section 7.3.1.3). When a pion
peer behind a NAT reaches a pion agent whose signalled host candidate is
also validated, the peer-reflexive pair now ties the host pair, the
older peer-reflexive pair stays the best valid pair and nomination waits
PrflxAcceptanceMinWait (1 s) although the host pair succeeded within
milliseconds. libwebrtc sends the peer-reflexive type preference here
(Connection::prflx_priority), so this also aligns the priorities pion
peers advertise with what browsers advertise.

Add Candidate.prflxPriority, use it for every Binding request, and test
that the controlling, controlled and nomination requests carry it.

Resolves pion#1025

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@JoTurk

JoTurk commented Oct 4, 2026 •

Copy link
Copy Markdown
Member

Just one correction #877 didn't introduce this, it just made the bug more visible with pion to pion connections. also ai descriptions are banned per our contributions guide please write a manual description next time

@codecov

codecov Bot commented Oct 4, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.76%. Comparing base (54863cd) to head (46cc3b0).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1026      +/-   ##
==========================================
+ Coverage   91.73%   91.76%   +0.02%     
==========================================
  Files          45       45              
  Lines        5447     5450       +3     
==========================================
+ Hits         4997     5001       +4     
+ Misses        450      449       -1     
Flag Coverage Δ
go 91.76% <100.00%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cnderrauber

Copy link
Copy Markdown
Member

Thank you for fixing this! Can we merge this PR now?

@ilay-decart

Copy link
Copy Markdown
Contributor Author

Thank you for fixing this! Can we merge this PR now?

Of course!

@JoTurk

JoTurk commented Oct 12, 2026

Copy link
Copy Markdown
Member

I'll cherry pick it to v4

@JoTurk
JoTurk merged commit c7d4ccc into pion:main Oct 12, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

PRIORITY attribute carries the local type preference, not peer-reflexive (RFC 8445 7.1.1): 1 s prflx wait between pion peers since #877

3 participants