~/posts/bgp-roles-and-otc-route-leak-prevention-on-vyos

BGP Roles and OTC: Route Leak Prevention Built Into BGP

4 min read

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.