VyOSXXVII · BGP Best PathBest path
AS Path prepending — making your own AS path look longer to influence inbound traffic
What you'll learn
- Explain why AS Path prepending is the canonical inbound traffic-engineering tool
- Configure AS Path prepending on VyOS 1.5 LTS via an export route-map
- Predict how many AS hops the peer actually sees, including FRR's own eBGP prepend
- Apply the canonical three-prepend pattern to a backup upstream
- Recognise the production failure modes where prepending did not work
Prerequisites
Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling)
AS Path prepending is the canonical tool for inbound traffic engineering on a multihomed site. The operator artificially inflates the AS path length on routes advertised to one upstream so that upstream’s selection process (step 4 of the best-path algorithm) ranks the route lower. The other upstream, seeing the unmodified AS path, ranks the route normally. The result: inbound traffic flows preferentially through the upstream that received the unmodified advertisement.
RFC 4271 defines the AS_PATH attribute as an ordered sequence of AS numbers that the route has traversed. AS Path prepending is the operator’s deliberate manipulation of that sequence — the operator inserts their own AS multiple times in the advertised path. Prepending is not a violation of the protocol; it is a sanctioned expression of policy.
The topology used throughout this lesson
One local AS with two transit providers:
- AS 64512 — the local AS. It originates
203.0.113.0/24. - Upstream A — AS 65001, peer address
192.0.2.2. The primary. Nothing is prepended towards A. - Upstream B — AS 65002, peer address
198.51.100.1. The backup. Three prepends are applied towards B.
flowchart LR
subgraph LOCAL["AS 64512 — originates 203.0.113.0/24"]
BR["Border router"]
end
subgraph A["Upstream A — AS 65001 (primary)"]
UA["receives AS_PATH 64512<br/>length 1"]
end
subgraph B["Upstream B — AS 65002 (backup)"]
UB["receives AS_PATH 64512 64512 64512 64512<br/>length 4"]
end
BR -->|"no export route-map"| UA
BR -->|"export route-map: 3 prepends"| UB
UA -->|"the wider internet prefers this path"| BR
UB -.->|"used only when A is unavailable"| BR
Why AS Path prepending works
The best-path algorithm’s step 4 evaluates the AS Path length, and the shorter path wins. Every router downstream of both upstreams eventually compares the two copies of 203.0.113.0/24: one that arrived through AS 65001 with a short path, one that arrived through AS 65002 with a long one. Path length is the tie-break that decides which copy becomes best, so traffic towards 203.0.113.0/24 converges on the path through A.
The prepended path is not a different route; it is the same route with a longer AS path. Upstream B still installs the route and still uses it if A’s path disappears — which is exactly what makes prepending a backup mechanism rather than a shutdown.
Why prepend your own AS, not someone else’s
The prepend clause should only ever repeat the operator’s own AS number: set as-path prepend '64512 64512 64512'. The local AS is the only AS the operator has authority to appear in a path they originate. Inserting a peer’s AS would claim “the route traversed this AS” when it did not — a forgery, detectable by anyone reading the path, and the shape of several well-known hijacks.
FRR does not police this for you. The AS numbers in a prepend clause are validated as numbers, not as numbers you are entitled to use. Discipline is the only control.
Configuring AS Path prepending on VyOS 1.5 LTS
Prepending is a set clause in a route-map, and the route-map is attached to the neighbour’s address family in the export direction:
configure
set policy route-map PREPEND-UPSTREAM-B rule 10 action 'permit'
set policy route-map PREPEND-UPSTREAM-B rule 10 set as-path prepend '64512 64512 64512'
set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast route-map export 'PREPEND-UPSTREAM-B'
commit
save
Two details in that last line are 1.5-specific and both matter. The neighbour is a direct child of protocols bgp — the local ASN lives under system-as, not in the path to every neighbour. And the map is bound inside an address family, so this binding shapes IPv4 unicast only; the IPv6 advertisements to the same peer are untouched until an equivalent binding is made under address-family ipv6-unicast.
A targeted version, prepending one prefix and continuing to advertise the rest untouched:
configure
set policy prefix-list CUSTOMER-PREFIX rule 10 action 'permit'
set policy prefix-list CUSTOMER-PREFIX rule 10 prefix '203.0.113.0/24'
set policy route-map PREPEND-SPECIFIC rule 10 action 'permit'
set policy route-map PREPEND-SPECIFIC rule 10 match ip address prefix-list 'CUSTOMER-PREFIX'
set policy route-map PREPEND-SPECIFIC rule 10 set as-path prepend '64512 64512 64512'
set policy route-map PREPEND-SPECIFIC rule 20 action 'permit'
set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast route-map export 'PREPEND-SPECIFIC'
commit
save
Rule 10 prepends 203.0.113.0/24. Rule 20 is the catch-all: it permits everything rule 10 did not match, with no set clause, so the remaining prefixes go out unchanged. Delete rule 20 and this map stops advertising every prefix except 203.0.113.0/24.
The canonical “three prepends” is not a magic number. The count is a trade-off:
- One prepend shifts the difference by one. Frequently lost to a local-preference or MED policy somewhere upstream, and the operator concludes prepending “does not work”.
- Two prepends is marginal for the same reason.
- Three prepends is the operator consensus for “backup upstream”. It is a clear difference at step 4 while leaving the route plainly acceptable.
- Ten prepends is where it stops helping and starts hurting. Networks that filter on maximum AS path length exist,
bgpd’s ownbgp max-med-style guards exist, and a path that looks pathological invites somebody to write a filter against it. The extra copies buy nothing once the difference is already decisive.
Showing what each peer is being advertised
The local check is a comparison, not a count. Ask the router what it is advertising to each peer and look for the difference:
vyos@R1:~$ show ip bgp neighbors 198.51.100.1 advertised-routes Network Next Hop Metric LocPrf Weight Path
*> 203.0.113.0/24 0.0.0.0 0 100 32768 64512 64512 64512 iIllustrative output
vyos@R1:~$ show ip bgp neighbors 192.0.2.2 advertised-routes Network Next Hop Metric LocPrf Weight Path
*> 203.0.113.0/24 0.0.0.0 0 100 32768 iIllustrative output
Both blocks are illustrative — the column layout is what FRR renders, the values are chosen for the example. Read them as a pair: the B row carries the three copies the route-map added, the A row carries none. That difference of three is the evidence the change did what it was configured to do.
What these blocks do not settle is the number the peer sees. advertised-routes is rendered after outbound policy but the mandatory eBGP prepend is added as the UPDATE is built, so the local view can legitimately show one fewer hop than the peer records. To confirm the far side, look at the route from outside: a public looking glass, a route-collector, or the provider’s own portal will show the AS_PATH as it arrived.
An AS-path regex is the fastest way to find every route carrying a repeated AS on this router:
show ip bgp regexp _64512_64512_
The canonical inbound traffic-engineering pattern
A multihomed site with two upstreams and one primary:
configure
set protocols bgp system-as 64512
set protocols bgp parameters router-id '203.0.113.1'
set protocols bgp address-family ipv4-unicast network '203.0.113.0/24'
# Upstream A (primary) — no export map, advertise as-is
set protocols bgp neighbor 192.0.2.2 remote-as '65001'
set protocols bgp neighbor 192.0.2.2 description 'Upstream A (primary)'
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast soft-reconfiguration inbound
# Upstream B (backup) — prepend on export so A is preferred
set policy route-map PREPEND-B rule 10 action 'permit'
set policy route-map PREPEND-B rule 10 set as-path prepend '64512 64512 64512'
set protocols bgp neighbor 198.51.100.1 remote-as '65002'
set protocols bgp neighbor 198.51.100.1 description 'Upstream B (backup)'
set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast route-map export 'PREPEND-B'
commit
save
The effect:
- Upstream A receives
203.0.113.0/24with AS_PATH64512— one hop. - Upstream B receives it with
64512 64512 64512 64512— four hops.
Inbound traffic to 203.0.113.0/24 converges on upstream A wherever path length is the deciding step.
The pattern is “prepend the backup, never the primary”. An operator who prepends the primary and leaves the backup untouched has configured the exact inverse of their intent, and the configuration looks correct at a glance because both routers have a prepend route-map somewhere.
Selective prepending with communities
The flexible version tags prefixes with a community and exempts the tagged ones from the prepend. The rule order is the whole mechanism:
set policy community-list NO-PREPEND rule 10 action 'permit'
set policy community-list NO-PREPEND rule 10 community '64512:99'
# Rule 10: the exemption. Permit, no set clause.
set policy route-map PREPEND-DEFAULT rule 10 action 'permit'
set policy route-map PREPEND-DEFAULT rule 10 match community community-list 'NO-PREPEND'
# Rule 20: everything else, prepended.
set policy route-map PREPEND-DEFAULT rule 20 action 'permit'
set policy route-map PREPEND-DEFAULT rule 20 set as-path prepend '64512 64512 64512'
set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast route-map export 'PREPEND-DEFAULT'
A route-map is evaluated in ascending rule order and stops at the first rule whose match clauses all succeed. Rule 10 has a match, so only community-tagged routes stop there — and because it permits without setting anything, those routes are advertised with their path untouched. Everything else falls through to rule 20, which has no match, matches unconditionally, and prepends.
Reverse the two rule numbers and the map silently prepends everything: the unconditional rule would match first and rule 10 would never be reached. The exemption must always be numbered below the default.
This is the canonical “prepend by default, exempt by community” pattern. The lesson vyos-xxix-02-community-config covers the tagging side; this lesson covers the prepend.
How the result is validated
show ip bgp neighbors 192.0.2.2 advertised-routes
show ip bgp neighbors 198.51.100.1 advertised-routes
show ip bgp regexp _64512_64512_
show policy route-map PREPEND-B
The first two, read as a pair, prove the route-map is attached to the peer the operator meant and is adding the number of copies they meant. The regex finds any route on this router whose path already repeats the local AS — useful when an inherited configuration prepends somewhere nobody remembers. The fourth prints the route-map as VyOS holds it, which is where a typo in a match clause becomes visible.
For the peer’s view there is no local command that can answer honestly. Use a looking glass, a route collector, or ask the provider.
How it fails
The production failure modes the engineer must recognise:
- Prepending on the wrong neighbour. The map is attached to A, the primary, instead of B. Inbound traffic moves to B. Both peers have route-maps, so the configuration reads as intentional; only
advertised-routeson each peer shows the inversion. - The route-map has a
matchand no catch-all. Only the matched prefixes are advertised at all; everything else is dropped by the route-map’s implicit deny. This is an outage, not a tuning problem, and it is the most damaging mistake on this page. - The exemption rule is numbered above the default rule. The unconditional rule matches first, evaluation stops, and every prefix is prepended including the ones that were meant to be exempt.
- The map is bound in the wrong direction.
route-map importinstead ofroute-map exportapplies the map to what the provider sends you. Your advertisements are unchanged, and you have quietly started rewriting the AS paths of inbound routes. - The map is bound in the wrong address family. IPv4 advertisements are prepended, IPv6 advertisements are not, and inbound v6 traffic keeps arriving on the backup.
- Prepending someone else’s AS. The path claims a transit relationship that does not exist. Networks running path validation or simple sanity filters may discard the route entirely.
- The upstream does not care. Local-preference at the upstream, or anywhere downstream of it, is evaluated before AS path length. The prepends are correct, applied, visible on the wire, and have no effect. This is not a misconfiguration; it is the limit of the tool.
Rollback
Prepending changes are configuration changes. The standard rollback path applies:
comparebeforecommitto see the route-map addition and the neighbour binding together.commit-confirm 5for any change made over the path it might affect.rollback 1thencommitandsaveto return to the previous revision.load /config/archive/config.boot.<timestamp>thencommitandsaveto return to a specific archived snapshot.
Removing the binding is the fast, surgical revert: delete protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast route-map export leaves the route-map defined but detaches it, so the next advertisement to B carries the unmodified path.
Production discipline
Cross-course references
The Linux course’s XIX-Linux-NetFoundations covers the kernel FIB. The OPNsense course’s XXX-OPNsense-DynamicRouting covers the same FRR route-map pattern on the firewall side. The BGP lessons vyos-xxvi-02-as-path (the AS_PATH attribute in detail) and vyos-xxvii-01-best-path-algorithm (the full ordering) cover the broader context. The lesson vyos-xxix-02-community-config covers the community mechanism that allows selective prepending; the lesson vyos-xxvii-06-best-path-troubleshoot walks the debugging of wrong-path-wins failures.
Quiz
Knowledge check · 5 questions
Q1. What is the purpose of AS Path prepending?
Q2. On VyOS 1.5, the prepend route-map is bound with `route-map import` under the neighbour's address family so the upstream sees the prepended path.
Q3. AS 64512 originates 203.0.113.0/24 and exports it to eBGP peer AS 65002 through a route-map containing `set as-path prepend '64512 64512 64512'`. How many AS hops does the peer record in the AS_PATH?
Q4. An operator configures three prepends towards upstream A (the primary), expecting inbound traffic to prefer A. Inbound traffic is now arriving through upstream B instead. What went wrong?
The route-map is `set policy route-map PREPEND-A rule 10 action permit` with `set as-path prepend '64512 64512 64512'`, bound with `set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast route-map export 'PREPEND-A'`. 192.0.2.2 is upstream A, the primary. Upstream B at 198.51.100.1 has no export map. The intent was to prefer A; the effect is the exact inverse.
Q5. An operator types `set policy route-map PREPEND-B rule 10 set as-path prepend '198.51.100.1 198.51.100.1'`, confusing the peer's IP address with its AS number. What happens, and where does the operator find out?
The intent was three copies of the local AS 64512. What was entered is the peer's IPv4 address, twice. The operator expects to discover the mistake from the upstream's behaviour.
Passing score: 75%. Answers are checked in this browser.