~/posts/bgp-roles-and-otc-route-leak-prevention-on-vyos
BGP Roles and OTC: Route Leak Prevention Built Into BGP
Back in 2020 I wrote about a route leak that sent a large part of European traffic through China Telecom. Six years later, leaks like that still happen regularly. RPKI (covered earlier) does not help here: in a leak the origin AS is usually correct, the route just travels along a path it should never have taken.
Most leaks have the same cause: a network learns routes from one provider or peer and announces them to another provider or peer. On paper that is easy to prevent with filters, and in the community scheme post I showed how to do it with communities. But filters are configuration, and configuration can be wrong or missing, especially on a new session at 2 a.m.
RFC 9234 moves this protection into the protocol itself.
Roles
With RFC 9234, both sides of an eBGP session declare their role in the OPEN message:
| Your role | Neighbor’s role | Relationship |
|---|---|---|
customer |
provider |
They sell you transit |
provider |
customer |
You sell them transit |
peer |
peer |
Settlement-free peering (bilateral) |
rs-client |
rs-server |
You peer with an IX route server |
rs-server |
rs-client |
You are the route server |
The roles have to match. If you say customer and the other side also says customer, the session is rejected with a Role Mismatch notification. That alone catches a whole category of mistakes: the relationship is no longer only in someone’s head or in a wiki, it is negotiated by the routers.
Only to Customer (OTC)
The second part is a new route attribute: Only to Customer (OTC). It marks a route that may only travel downwards, to customers. The routers set and check it automatically based on the session role:
- A route learned from a provider, peer or route server gets an OTC attribute with the neighbor’s ASN (if it doesn’t have one yet).
- A route that carries OTC is never sent to a provider, peer or route server. It can still go to customers.
- A route that arrives from a customer or RS client with OTC already set is a leak and is not accepted as a normal route.
The result: when a customer accidentally announces their transit provider’s full table to you, those routes carry OTC and are dropped. And when you make a mistake in your export policy, the routes from your upstream still carry OTC and don’t leave your network towards other peers or transit.
Because OTC is a transitive attribute, this keeps working across multiple ASes, as long as the networks along the path support it.
On VyOS
VyOS uses FRR, which supports BGP roles. You configure the role per neighbor (or per peer group):
set protocols bgp neighbor 192.0.2.1 description 'Transit A'
set protocols bgp neighbor 192.0.2.1 local-role 'customer'
set protocols bgp neighbor 198.51.100.1 description 'IX route server'
set protocols bgp neighbor 198.51.100.1 local-role 'rs-client'
set protocols bgp neighbor 203.0.113.7 description 'Bilateral peer'
set protocols bgp neighbor 203.0.113.7 local-role 'peer'
commit
Note that local-role is your role on the session, not the neighbor’s. Towards a transit provider, you are the customer.
Then check what was negotiated:
show bgp neighbors 192.0.2.1
Among other things, the output shows the local role and the role the neighbor sent. If the neighbor doesn’t support roles yet, you’ll see that there as well.
Strict mode
By default, a session with a neighbor that doesn’t support roles simply comes up without them. You only get OTC handling for the routes the router can classify. With strict, the session is refused unless the neighbor also sends a role:
set protocols bgp neighbor 203.0.113.7 local-role 'peer' strict
My advice: use strict mode only when you know for sure the other side supports roles, for example between two of your own ASes or with a peer you’ve agreed this with. For transit and IX sessions, enable roles without strict. You get the benefit wherever the other side supports it, and nothing breaks where it doesn’t.
Not a replacement for filters
BGP roles are a safety net, not a replacement for your routing policy. Keep your prefix filters on customer sessions, your RPKI validation and your community-based export rules. What roles add is a second, independent layer that doesn’t depend on whether your route-maps are correct.
The more networks enable this, the more effective it gets, because OTC is passed on across AS boundaries. It costs one line per session. Turn it on.