Supported

RFC 9234 - Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages

Every requirement this repository extracted from RFC 9234, the tests bound to it, and what a reader has verified about them. This summary is enrolled and gated by ./le rfc check.

Overview

Positive

what Ze has

Tested both ways68.4%13 of 19 gated MUSTs

a positive test proves Ze does what the requirement demands and a negative one proves it refuses what the requirement forbids

One polarity plus reason15.8%3 of 19 gated MUSTs

the requirement admits no counter-case, so one polarity plus a recorded reason is the whole proof available for it

One polarity, unexcused0.0%0 of 19 gated MUSTs

one direction is tested, the other is neither tested nor excused, and nothing states which

Partial proof; remaining gap0.0%0 of 19 gated MUSTs

scoped tests exist; the remaining obligation is unmet or unproven, with zero whole-requirement credit

No test at all0.0%0 of 19 gated MUSTs

no test carries the requirement id, whether or not a gap states why

Proven by a recorded break27.3%18 of 66 tagged units

a red was observed once under a recorded procedure, and the unit, the claim and the producer it rested on still hash to what was recorded. The break is not re-run. A test pair is not a proof until one has been observed

Neutral

measures that are neither good news nor bad

Gated MUSTs19of 24 this summary declares

MUST-level requirements the gate HOLDS. A population, not a result: the shares beside it are what says how Ze stands

Out of scope3of 19 gated MUSTs

an obligation that does not bind Ze. A {not-applicable} annotation says it never bound; a {feature-declined} annotation says its condition is an optional feature Ze does not offer, and quotes the RFC sentence that makes it optional. Scope, not coverage: it stays in the denominator every share on this page is taken over

Not applicable15.8%3 of 19 gated MUSTs

a {not-applicable} annotation says the obligation does not bind Ze, so no test is owed for it. It stays in the denominator every share here is taken over

Met below Ze0.0%0 of 19 gated MUSTs

a {lower-layer} annotation says a layer under Ze performs the behavior, on state Ze installs into that layer, and names the producer that installs it. The obligation binds Ze and is met; Ze proves none of it, because its own boundary carries no value the behavior reads

Optional feature declined0.0%0 of 19 gated MUSTs

a {feature-declined} annotation says the obligation is conditional on a feature the RFC makes optional and Ze does not offer, and it quotes the sentence that makes it optional. The condition is false, so nothing is owed and nothing is missing. It stays in the denominator every share here is taken over

The 8 shares marked as a part above are the whole of the 19 gated MUSTs: they add to 100%. Proven by a recorded break is a share of TAGGED UNITS, a different population, so it is not one of them.

How to read the colors

A color names what the measure MEANS, not how well Ze scores on it. Green is a good outcome at any value, red is a bad one, and neither a population nor a scope count is an outcome, so both take no color. The number under the label is what says how far Ze has got.

CardTone hereWhy that color
Gated MUSTs neutral no color: a population is a scale, and a larger one is neither good news nor bad. It is the accounting total
Out of scope neutral no color: an obligation that never bound Ze is neither an achievement nor a failure, and counting it either way would be a claim
Tested both ways ok green at every value: a test pair is the outcome this gate exists to produce, and the share under the label is what says how far Ze has got
One polarity plus reason ok green at every value: where no counter-case exists, one polarity IS the complete answer, and a recorded reason is what the gate demands beside it
One polarity, unexcused ok green at zero, RED above it: half a proof with no reason for the other half
Partial proof; remaining gap ok green at zero, RED above it: a tested clause cannot prove the whole requirement
No test at all ok green at zero, RED above it: a binding obligation nothing exercises is a claim with nothing behind it, whether or not a reason is stated
Not applicable neutral no color: an obligation that never bound Ze is neither an achievement nor a failure, and counting it either way would be a claim
Met below Ze neutral no color: an obligation met below Ze is neither a test Ze wrote nor work Ze owes, and the two green shares above are what says how much Ze proves itself
Optional feature declined neutral no color: an obligation whose condition Ze never meets is neither an achievement nor a failure. The absent FEATURE is disclosed on the RFC's own status row, as an implementation gap a later scope decision can revisit
Proven by a recorded break ok green at every value: an observed break is the outcome the discrimination gate exists to produce. The denominator is TAGGED UNITS, not obligations, so this share is not one of the parts above
Audit verdicts warn RED on the first weak, wrong or unimplemented verdict, amber while a verdict is no longer current or a gated MUST is unjudged, green when every one is judged sound and current

At a glance

FieldValue
Public status Supported
Enrolment Enrolled
Requirements 24
Gated MUST-level 19
Not applicable, so out of scope 3
Declared gaps 0
Declared gaps a test demonstrates 0
Gated with no test 0
Nightly-only evidence 0
Test tags 71
Tagged units 66
Recorded audit verdicts 17
Discrimination records 18
Summary rfc/short/rfc9234.md
Requirement shard rfc/requirements/rfc9234.md
RFC text rfc/full/rfc9234.txt

Enrolment

Enrolled: BGP Open Policy / Roles + Only-To-Customer OTC attribute (RFC 9234): role plugin. 13 MET (Role capability advertise, Table-2 pair correspondence + code-2/subcode-11 Role Mismatch, OTC ingress leak rules for Customer/RS-Client/Peer, ingress/egress stamping, no-propagate-upstream, preserve-unchanged, unicast-only, Gao-Rexford prohibition, malformed-OTC treat-as-withdraw) + 3 single-polarity positive (one Role capability per peer, egress stamp uses internet-facing local AS, OTC procedures non-overridable) + 3 not-applicable (no AS Confederation, no Complex peering)

What the public ledger says

Status: Supported

What the ledger says is covered Role capability negotiation, role mismatch NOTIFICATION, OTC egress stamping, OTC ingress leak detection and treat-as-withdraw, unicast-only (AFI 1/2, SAFI 1) OTC scoping read from MP_REACH_NLRI or, for a withdrawal, MP_UNREACH_NLRI. Both stamping rules are conditioned on the UPDATE advertising reachable NLRI, per Section 5's "if a route is to be advertised" / "if a route is received", so a withdrawal, an MP_UNREACH-only UPDATE and an End-of-RIB marker (both RFC 4724 encodings, which an added attribute would stop being a marker at all) are never stamped (internal/component/bgp/plugins/role/otc.go payloadAdvertisesNLRI, isPayloadUnicast).
What the ledger says remains No known gap. The coverage gap disclosed here until 2026-08-05 is closed: test/plugin/role-otc-fwd-withdraw.ci asserts byte for byte that a withdraw-only UPDATE relayed to a Customer leaves the wire with attrLen=0000 and no attribute of any code, test/plugin/role-otc-rs-withdraw-eor.ci does the same for an End-of-RIB marker, and test/interop/scenarios/bgp-role-otc-withdraw-frr runs a conforming FRR 10.3.1 receiver against the shape RFC 7606 Section 5.2 escalates to "session reset". The producer all three drive is payloadAdvertisesNLRI in internal/component/bgp/plugins/role/otc.go.

Coverage

BucketCountWhat it counts
Positive and negative tests 13 one part of the gated population
Annotated (including scoped evidence) 6 one part of the gated population
One polarity only 0 one part of the gated population
No test and no annotation 0 one part of the gated population
Partial proof; remaining gap (subset of annotated; zero whole-requirement credit) 0 an overlay: each of these is also counted by the part it falls in
Evidence that runs nightly only 0 an overlay: each of these is also counted by the part it falls in
Derived from other rows 0 outside the gated population: each asserts nothing and derives its state from the rows it names, which the parts above already count
Gated MUST-level requirements19every gated MUST falls in exactly one bucket above

Positive and negative tests (13): RFC9234-4.1-1, RFC9234-4.2-1, RFC9234-4.2-2, RFC9234-4.2-3, RFC9234-5-1, RFC9234-5-2, RFC9234-5-3, RFC9234-5-4, RFC9234-5-5, RFC9234-5-6, RFC9234-5-10, RFC9234-3.1-1, RFC9234-5-12

Annotated (including scoped evidence) (6): RFC9234-4.1-2, RFC9234-5-7, RFC9234-5-8, RFC9234-5-9, RFC9234-5-11, RFC9234-6-1

Requirements

RequirementLevelSectionTests
RFC9234-4.1-1If the BGP Role is locally configured, the eBGP speaker MUST advertise the BGP Role Capability in the BGP OPEN message. (S4.1)
MUST 4.1 - BGP Role Capability
RFC9234-4.1-2An eBGP speaker MUST NOT advertise multiple versions of the BGP Role Capability. (S4.1)
MUST NOT 4.1 - BGP Role Capability
negativeno testno negative test

{single-polarity}: parseRoleContainer (internal/component/bgp/plugins/role/config.go:66) reads a single import role per peer and extractRoleCapabilities (config.go:213) emits exactly one CapabilityDecl per peer, so no code path can advertise multiple Role capabilities and only the exactly-one assertion is constructible

RFC9234-4.2-1If the BGP Role Capability is advertised, and one is also received from the peer, the Roles MUST correspond to the relationships in Table 2. (S4.2)
MUST 4.2 - Role Correctness
RFC9234-4.2-2If the Roles do not correspond, the BGP speaker MUST reject the connection using the Role Mismatch Notification (code 2, subcode 11). (S4.2)
MUST 4.2 - Role Correctness
RFC9234-4.2-3If multiple BGP Role Capabilities are received and not all of them have the same value, then the BGP speaker MUST reject the connection using the Role Mismatch Notification (code 2, subcode 11). (§4.2)
MUST 4.2 - Role Correctness
RFC9234-5-1If a route with the OTC Attribute is received from a Customer or an RS-Client, then it is a route leak and MUST be considered ineligible (see Section 3). (S5)
MUST 5 - BGP Only to Customer (OTC) Attribute
positiveunit/verifyTestCheckOTCIngress
negativeunit/verifyTestCheckOTCIngress
RFC9234-5-2If a route with the OTC Attribute is received from a Peer (i.e., remote AS with a Peer Role) and the Attribute has a value that is not equal to the remote (i.e., Peer's) AS number, then it is a route leak and MUST be considered ineligible. (§5)
MUST 5 - BGP Only to Customer (OTC) Attribute
positiveunit/verifyTestOTCIngressFilter
negativeunit/verifyTestOTCIngressFilter
RFC9234-5-3If a route is received from a Provider, a Peer, or an RS and the OTC Attribute is not present, then it MUST be added with a value equal to the AS number of the remote AS. (§5)
MUST 5 - BGP Only to Customer (OTC) Attribute
positiveunit/verifyTestOTCIngressFilter
negativeunit/verifyTestCheckOTCIngress
RFC9234-5-4If a route is to be advertised to a Customer, a Peer, or an RS- Client (when the sender is an RS), and the OTC Attribute is not present, then when advertising the route, an OTC Attribute MUST be added with a value equal to the AS number of the local AS. (§5)
MUST 5 - BGP Only to Customer (OTC) Attribute
positiveunit/verifyTestOTCEgressStampMod
negativeunit/verifyTestOTCEgressNoStampProvider
positivefunctional/verifyrole-otc-fwd-withdraw.ci
positivefunctional/verifyrole-otc-rs-client-dest-stamp.ci
positivefunctional/verifyrole-otc-rs-withdraw-eor.ci
negativefunctional/verifyrole-otc-fwd-withdraw.ci
negativefunctional/verifyrole-otc-rs-withdraw-eor.ci
positiveinterop/nightlycheckRFC7999Blackhole
negativeinterop/nightlycheckRFC7999Blackhole
RFC9234-5-5If a route already contains the OTC Attribute, it MUST NOT be propagated to Providers, Peers, or RSes. (S5)
MUST NOT 5 - BGP Only to Customer (OTC) Attribute
positiveunit/verifyTestOTCEgressWireBytesCheck
negativeunit/verifyTestOTCEgressWireBytesCheck
RFC9234-5-6Once the OTC Attribute has been set, it MUST be preserved unchanged (this also applies to an AS Confederation). (S5)
MUST 5 - BGP Only to Customer (OTC) Attribute
RFC9234-5-7If an OTC Attribute is added on egress from the AS Confederation, its value MUST equal the AS Confederation Identifier. (S5)
MUST 5 - BGP Only to Customer (OTC) Attribute
positiveno testno positive test
negativeno testno negative test

{not-applicable}: ze does not operate as an AS Confederation (no confederation-identifier or member-AS config exists anywhere in config or the role plugin); the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses only dest.LocalAS, so there is no confederation egress boundary at which a confederation identifier could be stamped

RFC9234-5-8Also, on egress from the AS Confederation, an UPDATE MUST NOT contain an OTC Attribute with a value corresponding to any Member-AS Number other than the AS Confederation Identifier. (S5)
MUST NOT 5 - BGP Only to Customer (OTC) Attribute
positiveno testno positive test
negativeno testno negative test

{not-applicable}: ze has no AS Confederation membership (no member-AS or confederation-identifier config); the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses only dest.LocalAS, so an UPDATE never carries a member-AS OTC value at a confederation boundary

RFC9234-5-9On egress from the Internet- facing AS, the OTC Attribute MUST NOT contain a value other than the Internet-facing ASN. (S5)
MUST NOT 5 - BGP Only to Customer (OTC) Attribute
positiveunit/verifyTestOTCEgressStampLocalASN
negativeno testno negative test

{single-polarity}: the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses dest.LocalAS, the effective per-peer internet-facing local AS supplied by the reactor at internal/component/bgp/reactor/peer_forward_facts.go:133, and no code path stamps any other value, so a wrong-ASN negative is not constructible

RFC9234-5-10The described ingress and egress procedures are applicable only for the address families AFI 1 (IPv4) and AFI 2 (IPv6) with SAFI 1 (unicast) in both cases and MUST NOT be applied to other address families by default. (S5)
MUST NOT 5 - BGP Only to Customer (OTC) Attribute
RFC9234-5-11The operator MUST NOT have the ability to modify the procedures defined in this section. (S5)
MUST NOT 5 - BGP Only to Customer (OTC) Attribute
positiveunit/verifyTestOTCEgressWireBytesCheck
negativeno testno negative test

{single-polarity}: checkOTCIngress (internal/component/bgp/plugins/role/otc.go:164) and OTCEgressFilter (otc.go:384) take no operator override, peerRoleConfig (config.go:17) exposes no disable flag, and the wire-bytes OTC suppression at otc.go:384 runs before and independent of the export policy, so the procedures cannot be switched off by configuration and a modifiable negative is not constructible

RFC9234-6-1Roles MUST NOT be configured on an eBGP session with a Complex peering relationship. (S6)
MUST NOT 6 - Additional Considerations
positiveno testno positive test
negativeno testno negative test

{not-applicable}: ze has no representation of a Complex peering relationship; parseRoleContainer (internal/component/bgp/plugins/role/config.go:66) parses one role per peer with no relationship-complexity classification, so there is no ze code path that could place a role on a complex session to guard against

RFC9234-3.1-1Customer: MAY propagate any route learned from a Customer, or that is locally originated, to a Provider. All other routes MUST NOT be propagated. Route Server (RS): MAY propagate any available route to a Route Server Client (RS-Client). Route Server Client (RS-Client): MAY propagate any route learned from a Customer, or that is locally originated, to an RS. All other routes MUST NOT be propagated. Peer: MAY propagate any route learned from a Customer, or that is locally originated, to a Peer. All other routes MUST NOT be propagated. (§3.1)
MUST NOT 3.1 - Peering Relationships
positiveunit/verifyTestOTCEgressFilter
negativeunit/verifyTestOTCEgressFilter
RFC9234-5-12The OTC Attribute is considered malformed if the length value is not 4. An UPDATE message with a malformed OTC Attribute SHALL be handled using the approach of "treat-as-withdraw" [RFC7606]. (§5)
SHALL 5 - BGP Only to Customer (OTC) Attribute
RFC9234-4-1One of the Roles described below SHOULD be configured at the local AS for each eBGP session (see definitions in Section 3) based on the local AS's knowledge of its Role. (§4)
SHOULD 4 - BGP Role
positiveno testno positive test
negativeno testno negative test
RFC9234-4.2-4For backward compatibility, if the BGP Role Capability is sent but one is not received, the BGP Speaker SHOULD ignore the absence of the BGP Role Capability and proceed with session establishment. (§4.2)
SHOULD 4.2 - Role Correctness
positiveno testno positive test
negativeno testno negative test
RFC9234-6-2If multiple eBGP sessions can segregate the Complex peering relationship into eBGP sessions with normal peering relationships, BGP Roles SHOULD be used on each of the resulting eBGP sessions. (§6)
SHOULD 6 - Additional Considerations
positiveno testno positive test
negativeno testno negative test
RFC9234-4.2-5An operator may choose to apply a "strict mode" in which the receipt of a BGP Role Capability from the remote AS is required. When operating in the "strict mode", if the BGP Role Capability is sent but one is not received, the connection is rejected using the Role Mismatch Notification (code 2, subcode 11). (§4.2)
MAY 4.2 - Role Correctness
RFC9234-5-13The BGP Role negotiation and OTC-Attribute-based procedures specified in this document are NOT RECOMMENDED to be used between autonomous systems in an AS Confederation [RFC5065]. (§5)
NOT RECOMMENDED 5 - BGP Only to Customer (OTC) Attribute
positiveno testno positive test
negativeno testno negative test

Gaps and untested MUSTs

RequirementStateReason
RFC9234-5-7 If an OTC Attribute is added on egress from the AS Confederation, its value MUST equal the AS Confederation Identifier. (S5) no test no test carries this requirement id; annotated {not-applicable}: ze does not operate as an AS Confederation (no confederation-identifier or member-AS config exists anywhere in config or the role plugin); the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses only dest.LocalAS, so there is no confederation egress boundary at which a confederation identifier could be stamped
RFC9234-5-8 Also, on egress from the AS Confederation, an UPDATE MUST NOT contain an OTC Attribute with a value corresponding to any Member-AS Number other than the AS Confederation Identifier. (S5) no test no test carries this requirement id; annotated {not-applicable}: ze has no AS Confederation membership (no member-AS or confederation-identifier config); the egress OTC stamp at internal/component/bgp/plugins/role/otc.go:432 uses only dest.LocalAS, so an UPDATE never carries a member-AS OTC value at a confederation boundary
RFC9234-6-1 Roles MUST NOT be configured on an eBGP session with a Complex peering relationship. (S6) no test no test carries this requirement id; annotated {not-applicable}: ze has no representation of a Complex peering relationship; parseRoleContainer (internal/component/bgp/plugins/role/config.go:66) parses one role per peer with no relationship-complexity classification, so there is no ze code path that could place a role on a complex session to guard against

Proof state

A tagged unit reads unproven where no discrimination record exists for it: nothing in this tree has been observed to break it, so the claim its tag makes is unproven.

RFC9234-4.1-1

If the BGP Role is locally configured, the eBGP speaker MUST advertise the BGP Role Capability in the BGP OPEN message. (S4.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Positive on the wire: dynamic-peer-gets-group-role-capability.ci asserts ze's whole OPEN octet for octet ending 09 01 01 (role rs configured); revert record on extractRoleCapabilities, plus a mutant record on extractPeerRoleConfigs for TestExtractRoleCapabilities_ParseBGPConfig. Negative (no, invalid or empty role: no capability 9) is a table case in that same unit, recorded 2026-09-29 by the judge (revert extractRoleCapabilities, observed red).

PolarityTestKind and tierProof state
negative TestExtractRoleCapabilities_ParseBGPConfig unit/verify revert, verified
positive TestExtractRoleCapabilities_ParseBGPConfig unit/verify mutant, verified
positive dynamic-peer-gets-group-role-capability.ci functional/verify revert, verified

RFC9234-4.1-2

An eBGP speaker MUST NOT advertise multiple versions of the BGP Role Capability. (S4.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Single-polarity positive, argument re-checked: parseRoleContainer reads one role per peer and extractRoleCapabilities emits one CapabilityDecl per peer. The .ci now asserts the OPEN ze sends octet for octet, so a second Role capability changes the length fields and goes red; revert record on extractRoleCapabilities. The marker cites config.go line numbers that have shifted; the argument holds.

PolarityTestKind and tierProof state
positive TestExtractRoleCapabilities_ParseBGPConfig unit/verify unproven
positive dynamic-peer-gets-group-role-capability.ci functional/verify revert, verified

RFC9234-4.2-1

If the BGP Role Capability is advertised, and one is also received from the peer, the Roles MUST correspond to the relationships in Table 2. (S4.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. non-compliant: accepting a pair outside Table 2. TestValidateOpenRolePair_InvalidPairs assert.False(output.Accept) over customer/customer, provider/provider, rs/rs, rsclient/rsclient, provider/rs, customer/peer, and TestValidateOpenRolePairRunsForADynamicGroupMember asserts RS/RS refused; positive TestValidateOpenRolePair_ValidPairs assert.True over all five Table 2 pairs

PolarityTestKind and tierProof state
negative TestValidateOpenRolePairRunsForADynamicGroupMember unit/verify unproven
negative TestValidateOpenRolePair_InvalidPairs unit/verify unproven
positive TestValidateOpenRolePair_ValidPairs unit/verify unproven

RFC9234-4.2-2

If the Roles do not correspond, the BGP speaker MUST reject the connection using the Role Mismatch Notification (code 2, subcode 11). (S4.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Positive role-mismatch-notification.ci: ze Provider, ze-peer Provider, first message on the wire is NOTIFICATION 03020B and no EoR; mutant record removing ! from !isValidRolePair (revert cannot discriminate: a crashed plugin also fails closed with 2/11). Negative peer-open-role-complement.ci: same config, ze-peer answers Customer, EoR sent and 03020B rejected; revert record on validateOpenRolePair. Only the peer's role octet differs, so the pair isolates the correspondence check.

PolarityTestKind and tierProof state
negative TestValidateOpenRolePair_ValidPairs unit/verify unproven
negative TestBroadcastValidateOpenAcceptsAPeerWithNoPerPeerPolicy unit/verify unproven
negative peer-open-role-complement.ci functional/verify revert, verified
positive TestValidateOpenRolePairRunsForADynamicGroupMember unit/verify unproven
positive TestValidateOpenRolePair_InvalidPairs unit/verify unproven
positive TestAskOpenValidatorsLeavesASilentPluginPending unit/verify unproven
positive TestBroadcastValidateOpenRefusesAnUnansweredPerPeerPolicy unit/verify unproven
positive role-mismatch-notification.ci functional/verify mutant, verified

RFC9234-4.2-3

If multiple BGP Role Capabilities are received and not all of them have the same value, then the BGP speaker MUST reject the connection using the Role Mismatch Notification (code 2, subcode 11). (§4.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Positive role-multiple-roles-notification.ci: Customer then Peer; Customer alone pairs with ze's Provider, so only the differing second value can refuse; wire 03020B, no EoR; mutant record on len(peerRoles) > 1. Negative role-multiple-same-roles.ci: Customer twice establishes (EoR, 03020B rejected); revert record. The unit pair in validate_test.go stays as plugin-tier cover.

PolarityTestKind and tierProof state
negative TestValidateOpenRolePair_MultipleSameRoles unit/verify unproven
negative role-multiple-same-roles.ci functional/verify revert, verified
positive TestValidateOpenRolePair_MultipleDifferentRoles unit/verify unproven
positive role-multiple-roles-notification.ci functional/verify mutant, verified

RFC9234-5-1

If a route with the OTC Attribute is received from a Customer or an RS-Client, then it is a route leak and MUST be considered ineligible (see Section 3). (S5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. non-compliant: OTC route from Customer or RS-Client accepted. TestCheckOTCIngress reject_customer_with_otc and reject_rs_client_with_otc assert otcRejectLeak; TestOTCIngressGateRunsForADynamicGroupMember asserts accept=false for an RS-Client member; negative accept_provider_has_otc/accept_rs_has_otc assert otcAccept

PolarityTestKind and tierProof state
negative TestCheckOTCIngress unit/verify unproven
positive TestOTCIngressGateRunsForADynamicGroupMember unit/verify unproven
positive TestCheckOTCIngress unit/verify unproven

RFC9234-5-2

If a route with the OTC Attribute is received from a Peer (i.e., remote AS with a Peer Role) and the Attribute has a value that is not equal to the remote (i.e., Peer's) AS number, then it is a route leak and MUST be considered ineligible. (§5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. non-compliant: Peer route whose OTC differs from the Peer's AS accepted. TestOTCIngressFilter reject_peer_otc_mismatch asserts accept=false (OTC 65099 vs PeerAS 65003); negative accept_peer_otc_matches asserts accept=true and no rewrite; TestCheckOTCIngress also pins reject_peer_otc_wrong and zero ASN

PolarityTestKind and tierProof state
negative TestOTCIngressFilter unit/verify unproven
positive TestOTCIngressFilter unit/verify unproven

RFC9234-5-3

If a route is received from a Provider, a Peer, or an RS and the OTC Attribute is not present, then it MUST be added with a value equal to the AS number of the remote AS. (§5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. non-compliant: a route without OTC from Provider, Peer or RS left unstamped or stamped with another ASN. TestOTCIngressFilter stamp_from_provider finds OTC == remote AS 65002 in the rewritten payload; TestCheckOTCIngress stamp_from_provider/peer/rs assert stampASN == remote ASN for each of the three roles. Negatives: Customer/RS-Client not stamped, pure withdrawal and MP_UNREACH-only not stamped

PolarityTestKind and tierProof state
negative TestCheckOTCIngress unit/verify unproven
negative TestOTCIngressNoStampOnMPUnreachOnly unit/verify unproven
negative TestOTCIngressNoStampOnPureWithdrawal unit/verify unproven
positive TestOTCIngressFilter unit/verify unproven

RFC9234-5-4

If a route is to be advertised to a Customer, a Peer, or an RS- Client (when the sender is an RS), and the OTC Attribute is not present, then when advertising the route, an OTC Attribute MUST be added with a value equal to the AS number of the local AS. (§5)

Audit verdict: enforced (the tests do what the requirement demands), shifted: internal/le/interoplab/bgp/check_rfc.go::checkOTCWithdrawal, internal/le/interoplab/bgp/check_rfc.go::checkOTCWithdrawal#2 moved. Positive TestRFC9234OTCStampedToEveryDownstreamDestination: an NLRI-bearing route with no OTC toward Customer, Peer and RS-Client each gets exactly one set op, code 35, value local AS 65000; plus the existing .ci and FRR interop positives. Negatives TestRFC9234OTCNotStampedOutsideTheDownstreamScope: the same NLRI-bearing route toward Provider and RS gets no op (the destination gate refuses, not the empty-NLRI gate), and a route already carrying OTC toward a Customer gets no op. TestOTCEgressNoStampProvider was vacuous (no NLRI, refused before the destination gate) and now carries NLRI (D-15 correction, not a weakening). Revert records on OTCEgressFilter for all three.

PolarityTestKind and tierProof state
negative TestRFC9234OTCNotStampedOutsideTheDownstreamScope unit/verify revert, verified
negative TestOTCEgressNoStampOnMPUnreachOnly unit/verify unproven
negative TestOTCEgressNoStampOnPureWithdrawal unit/verify unproven
negative TestOTCEgressNoStampProvider unit/verify revert, verified
negative checkRFC7999Blackhole interop/nightly unproven
negative role-otc-fwd-withdraw.ci functional/verify unproven
negative role-otc-rs-withdraw-eor.ci functional/verify unproven
positive TestRFC9234OTCStampedToEveryDownstreamDestination unit/verify revert, verified
positive TestOTCEgressStampMod unit/verify unproven
positive TestOTCEgressStampsMixedWithdrawAndAnnounce unit/verify unproven
positive TestOTCEgressStampsToCustomerWhenSourceHasNoRoleConfig unit/verify unproven
positive checkRFC7999Blackhole interop/nightly unproven
positive role-otc-fwd-withdraw.ci functional/verify unproven
positive role-otc-rs-client-dest-stamp.ci functional/verify unproven
positive role-otc-rs-withdraw-eor.ci functional/verify unproven

RFC9234-5-5

If a route already contains the OTC Attribute, it MUST NOT be propagated to Providers, Peers, or RSes. (S5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. non-compliant: an OTC-carrying route sent to a Provider, Peer or RS. TestOTCEgressWireBytesCheck asserts OTCEgressFilter false for each of the three destinations with no source config, true for an OTC route to a Customer and for a no-OTC route to a Provider

PolarityTestKind and tierProof state
negative TestOTCEgressWireBytesCheck unit/verify unproven
positive TestOTCEgressWireBytesCheck unit/verify unproven

RFC9234-5-6

Once the OTC Attribute has been set, it MUST be preserved unchanged (this also applies to an AS Confederation). (S5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. non-compliant: an existing OTC value rewritten. TestOTCAttrModHandlerExistingPreserved plans OTC 65001 from source against a set op of 65000 and asserts the emitted value is 65001. Negative TestOTCAttrModHandlerNewAttr: no prior OTC, so the op's value is emitted. The confederation parenthetical has no ze code path (RFC9234-5-7/5-8 are not-applicable)

PolarityTestKind and tierProof state
negative TestOTCAttrModHandlerNewAttr unit/verify unproven
positive TestOTCAttrModHandlerExistingPreserved unit/verify unproven

RFC9234-5-7

If an OTC Attribute is added on egress from the AS Confederation, its value MUST equal the AS Confederation Identifier. (S5)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC9234-5-7, so no unit is bound to it.

RFC9234-5-8

Also, on egress from the AS Confederation, an UPDATE MUST NOT contain an OTC Attribute with a value corresponding to any Member-AS Number other than the AS Confederation Identifier. (S5)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC9234-5-8, so no unit is bound to it.

RFC9234-5-9

On egress from the Internet- facing AS, the OTC Attribute MUST NOT contain a value other than the Internet-facing ASN. (S5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. single-polarity positive. non-compliant: egress OTC carrying a value other than the local (internet-facing) AS. TestOTCEgressStampLocalASN asserts the stamped value is dest.LocalAS 64999, not src AS 65001 nor dest peer AS 65002

PolarityTestKind and tierProof state
positive TestOTCEgressStampLocalASN unit/verify unproven

RFC9234-5-10

The described ingress and egress procedures are applicable only for the address families AFI 1 (IPv4) and AFI 2 (IPv6) with SAFI 1 (unicast) in both cases and MUST NOT be applied to other address families by default. (S5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. non-compliant: OTC procedures applied to a non AFI1/2 SAFI1 family. Egress stamp: TestOTCEgressUnicastOnly (ipv4 multicast, mods.Len()==0) and TestOTCEgressNonUnicastWithdrawalNotProcessed (VPNv4); egress rule 2: TestOTCNonUnicastWithdrawalSkipsOTCProcedures egress_rule_2_does_not_suppress; ingress rule 1: its ingress_rule_1_does_not_reject subtest; family gate: TestIsPayloadUnicastMPUnreachFamily. Negative TestOTCEgressStampMod stamps IPv4 unicast

PolarityTestKind and tierProof state
negative TestOTCEgressStampMod unit/verify unproven
positive TestIsPayloadUnicastMPUnreachFamily unit/verify unproven
positive TestOTCEgressNonUnicastWithdrawalNotProcessed unit/verify unproven
positive TestOTCEgressUnicastOnly unit/verify unproven
positive TestOTCNonUnicastWithdrawalSkipsOTCProcedures unit/verify unproven

RFC9234-5-11

The operator MUST NOT have the ability to modify the procedures defined in this section. (S5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Single-polarity positive, argument re-checked: peerRoleConfig carries only role, strict and export; TestRFC9234OTCProceduresSurviveOperatorSettings sets strict on and export naming every role on the source configs (the export set the egress filter reads, srcCfg.resolvedExport) and shows ingress still stamps OTC 64500 from a Provider, still refuses an OTC route from a Customer, egress still withholds an OTC route from a Provider and still stamps 65000 toward a Customer. Revert record on checkOTCIngress. The marker's otc.go:164/:384 line citations are stale (now checkOTCIngress and OTCEgressFilter moved); the argument holds.

PolarityTestKind and tierProof state
positive TestRFC9234OTCProceduresSurviveOperatorSettings unit/verify revert, verified
positive TestOTCEgressWireBytesCheck unit/verify unproven

RFC9234-6-1

Roles MUST NOT be configured on an eBGP session with a Complex peering relationship. (S6)

Audit verdict: not audited: no reader has judged these tests

No test carries RFC9234-6-1, so no unit is bound to it.

RFC9234-3.1-1

Customer: MAY propagate any route learned from a Customer, or that is locally originated, to a Provider. All other routes MUST NOT be propagated. Route Server (RS): MAY propagate any available route to a Route Server Client (RS-Client). Route Server Client (RS-Client): MAY propagate any route learned from a Customer, or that is locally originated, to an RS. All other routes MUST NOT be propagated. Peer: MAY propagate any route learned from a Customer, or that is locally originated, to a Peer. All other routes MUST NOT be propagated. (§3.1)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Re-judged 2026-10-14 (independent auditor, D4, owner Q-D4 (a)). RFC 9234 Section 3.1: Customer, RS-Client and Peer "MAY propagate any route learned from a Customer, or that is locally originated" to a Provider, an RS and a Peer, and "All other routes MUST NOT be propagated." Producer OTCEgressFilter (role/otc.go) suppresses when the destination remote role is provider, peer or rs and the source role (our role toward the source) is customer, peer, rs-client or rs. TestOTCEgressFilter asserts suppression for every member of both sets: Provider-learned to Provider, Peer-learned to Peer and RS, RS-learned to Provider, RS-Client-learned to Provider, Peer and RS (the rs case the earlier verdict found propagated now asserts suppression); TestOTCEgressSuppressProviderLearnedWithoutMeta covers the config fallback with nil meta. Negatives: Customer-learned reaches a Provider and a Customer, RS-Client-learned reaches a Customer and an RS-Client, so the suppression is scoped. Each set member is pinned by at least one exact assertion, so dropping a role from either set goes red; not every source-destination pair is asserted, which the set-membership producer makes redundant.

PolarityTestKind and tierProof state
negative TestOTCEgressFilter unit/verify revert, verified
positive TestOTCEgressFilter unit/verify revert, verified
positive TestOTCEgressSuppressProviderLearnedWithoutMeta unit/verify unproven

RFC9234-5-12

The OTC Attribute is considered malformed if the length value is not 4. An UPDATE message with a malformed OTC Attribute SHALL be handled using the approach of "treat-as-withdraw" [RFC7606]. (§5)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Positive TestRFC9234OTCOfAnyLengthButFourIsTreatedAsWithdraw: OTC lengths 0, 5 and 8 from a Provider (attributes ORIGIN + OTC only, isolated) move 10.0.0.0/24 to withdrawn, clear the attributes and keep the message. Negative TestRFC9234OTCOfLengthFourIsNotTreatedAsWithdraw: length 4 accepted unchanged. Revert records on findOTC for both.

PolarityTestKind and tierProof state
negative TestRFC9234OTCOfLengthFourIsNotTreatedAsWithdraw unit/verify revert, verified
negative TestCheckOTCIngress unit/verify unproven
positive TestRFC9234OTCOfAnyLengthButFourIsTreatedAsWithdraw unit/verify revert, verified
positive TestOTCIngressMalformedTreatAsWithdraw unit/verify unproven

RFC9234-4.2-5

An operator may choose to apply a "strict mode" in which the receipt of a BGP Role Capability from the remote AS is required. When operating in the "strict mode", if the BGP Role Capability is sent but one is not received, the connection is rejected using the Role Mismatch Notification (code 2, subcode 11). (§4.2)

Audit verdict: enforced (the tests do what the requirement demands), fresh. Positive role-strict-enforcement.ci: strict true, ze-peer drops capability 9, first message is 03020B; mutant record cfg.strict -> false turns it red, so strict mode is what refuses. Negative TestValidateOpenRolePair_NoPeerRole_NoStrict: non-strict accepts a missing role; revert record. Note: the .ci session is iBGP (asn 1/1); the strict sentence is not eBGP-scoped in RFC 9234, so this does not void it. The .ci has a 10s budget and flaked once (journal row).

PolarityTestKind and tierProof state
negative TestValidateOpenRolePair_NoPeerRole_NoStrict unit/verify revert, verified
positive TestValidateOpenStrictModeRefusesADynamicGroupMemberWithNoRole unit/verify unproven
positive role-strict-enforcement.ci functional/verify mutant, verified

Extraction sign-off

FieldValue
Reviewer ze-work agent, spec-rfcgate-6 phase 3, rfc9234
Signed off 2026-08-31
Register rfc2119
Source rfc/full/rfc9234.txt
Source fingerprint 34079d5254c6a473
Record rfc/extraction/rfc9234.json
Mapped sentences 19
Declined as scope 2
Relocated to a spec, which Ze OWES 0
Unclassified 0

Sections

SectionNameSitesDispositionReason
front not stated 0 skipped (front-matter) Title block, Status of This Memo, Copyright Notice, Abstract and Table of Contents. The Abstract restates section 1 and directs no speaker.
1 Introduction 0 walked Introduction. Indicative prose: what a route leak is, with RFC 7908 named for the taxonomy, why configuration-based prevention is unchecked, and what this document adds. Its one modal, "An eBGP speaker may require the use of this capability and confirmation of the BGP Role with a neighbor for the BGP OPEN to succeed", is lowercase, so under this document's own section 2 it carries no RFC 2119 level; it previews the strict mode that section 4.2 states and that rfc/short/rfc9234.md carries as RFC9234-4.2-5.
2 Requirements Language 0 walked Requirements Language. The BCP 14 key-words paragraph, which states that the key words bind only when they appear in all capitals. It tells a reader how to read the other sections and binds no speaker, which is why the derivation excludes it from the site inventory.
3 Terminology 0 walked Terminology. Defines "local AS" and "remote AS", and imports RFC 4271's meaning for "route is ineligible" ("ineligible to be installed in Loc-RIB and will be excluded from the next phase of route selection"). Definitions, no directive. That imported meaning is what the ingress leak rejection owes: checkOTCIngress (internal/component/bgp/plugins/role/otc.go) answers otcRejectLeak rather than dropping the session.
3.1 Peering Relationships 3 walked Peering Relationships. Five role bullets giving the Gao-Rexford propagation rules. Three identical sentences, "All other routes MUST NOT be propagated.", close the Customer, the RS-Client and the Peer bullet; rfc/short/rfc9234.md states one row, RFC9234-3.1-1, whose text covers all three roles, so the first site maps it and the two later ones are duplicates of it. The Provider and RS bullets, and every "MAY propagate" clause, are permissions rather than obligations. "A BGP speaker may apply policy to reduce what is announced", "Violation of the route propagation rules listed above may result in route leaks" and the closing pointer to section 5 are lowercase and indicative.
4 BGP Role 0 walked BGP Role. No capitalised MUST-level site. Its one directive is the SHOULD to configure a Role at the local AS for each eBGP session, with the Complex peering exception, carried as the unsourced id below. The five allowed Role definitions are terminology, and "BGP Roles are mutually confirmed using the BGP Role Capability" is a pointer to sections 4.1 and 4.2.
4.1 BGP Role Capability 2 walked BGP Role Capability. Capability Code 9, Length 1 and Table 1's role values 0 through 4 with 5-255 unassigned are value assignments, stated indicatively, and are carried by the Wire Formats and Constants tables of rfc/short/rfc9234.md rather than by a requirement row. Two capitalised sites, mapped below to RFC9234-4.1-1 and RFC9234-4.1-2. The closing sentence, "The error handling when multiple BGP Role Capabilities are received is described in Section 4.2", is a pointer.
4.2 Role Correctness 3 walked Role Correctness. Three capitalised sites, mapped below to RFC9234-4.2-1 through RFC9234-4.2-3, plus Table 2's allowed pairs, which the sites reference rather than state. Three sentences the site scan cannot see: the backward-compatibility SHOULD to ignore a missing Role Capability and proceed (unsourced id below); the "strict mode" paragraph, written indicatively ("the connection is rejected using the Role Mismatch Notification") and carried as the MAY row RFC9234-4.2-5, whose local behaviour is the strict leaf defaulting to false in internal/component/bgp/plugins/role/yang/ze-role.yang; and "If an eBGP speaker receives multiple but identical BGP Role Capabilities with the same value in each, then the speaker considers them to be a single BGP Role Capability and proceeds [RFC5492]", which states no RFC 2119 level and defers the merge to RFC 5492, so it adds no obligation of this document.
5 BGP Only to Customer (OTC) Attribute 12 walked BGP Only to Customer (OTC) Attribute. The document's main normative section: twelve capitalised MUST-level sites, all mapped below. Its remaining sentences are definition ("an optional transitive Path Attribute of the UPDATE message with Attribute Type Code 35 and a length of 4 octets", and "The OTC Attribute is considered malformed if the length value is not 4", which supplies the condition site 5:6 acts on), rationale (the leak prevention and detection paragraphs, and the early-adopter paragraph observing that the OTC value is the same whether the remote AS or the local AS sets it), and the NOT RECOMMENDED sentence about AS Confederations, which is the unsourced id below. Two lead-ins scope the sites rather than add a requirement: "The following ingress procedure applies to the processing of the OTC Attribute on route receipt" and "The following egress procedure applies to the processing of the OTC Attribute on route advertisement". Both are indicative, and both are why payloadAdvertisesNLRI (internal/component/bgp/plugins/role/otc.go) gates the two stamping rules on the UPDATE carrying reachable NLRI: an UPDATE that only withdraws, and an End-of-RIB marker, are neither a route received nor a route advertised.
6 Additional Considerations 1 walked Additional Considerations. One capitalised site, mapped below to RFC9234-6-1. Its one further directive is the SHOULD to use Roles on each session once a Complex relationship is segregated, the unsourced id below. The rest is commentary: per-prefix policy as an alternative with no in-band check, the effect of an incorrect Role or OTC value, AS migration under RFC 7705 where a router sets OTC to the ASN it currently represents, and a pointer to RFC 7606 section 6 for the negative impacts of treat-as-withdraw.
7 IANA Considerations 0 skipped (iana) IANA Considerations. Records Capability Code 9, the new "BGP Role Value" subregistry with Table 3, OPEN Message Error subcode 11 "Role Mismatch", the deprecation of subcodes 8-10, and Path Attribute code 35. Binds IANA, not a speaker.
8 Security Considerations 0 walked Security Considerations. States that the RFC 4271 and RFC 4272 considerations apply, describes what a misconfigured Role does to prefix propagation, discourages strict mode as a default in lowercase ("Implementations with such default behavior are strongly discouraged"), and describes OTC removal by an on-path attacker and OTC addition by a Customer as threats BGPsec does not cover. No capitalised keyword and no countermeasure directed at a speaker. The discouraged default is met: the strict leaf defaults to false (internal/component/bgp/plugins/role/yang/ze-role.yang).
9 References 0 skipped (references) References. The heading only; its entries are in 9.1 and 9.2.
9.1 not stated 0 skipped (references) Normative References: RFC 2119, RFC 4271, RFC 5065, RFC 5492, RFC 7606, RFC 7908, RFC 8126, RFC 8174.
9.2 not stated 0 skipped (references) Informative References: GAO-REXFORD, RFC 4272, RFC 7705, RFC 7938, RFC 8205. The Acknowledgments, Contributors and Authors' Addresses blocks that close the document fall in this section's body and state no obligation.

Excluded sentences

SiteExcluded kindReasonQuote
3.1:2 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The same sentence closing the RS-Client bullet. It restates for the RS-Client Role the prohibition RFC9234-3.1-1 already carries for all three Roles, and site 3.1:1 maps that id. OTCEgressFilter (internal/component/bgp/plugins/role/otc.go) enforces all three in one expression: a destination resolving to Provider, Peer or RS is refused a route whose source resolves to Customer, Peer or RS-Client. All other routes MUST NOT be propagated.
3.1:3 duplicate-of
never bound Ze
the same obligation is already captured under another requirement id
The same sentence closing the Peer bullet. It restates for the Peer Role the prohibition RFC9234-3.1-1 already carries for all three Roles, and site 3.1:1 maps that id. All other routes MUST NOT be propagated.

Superseded

No document obsoletes RFC 9234, so its obligations are stated where they were written.