VyOSXXVII · BGP Best PathBest path
The 11-step BGP best-path algorithm — how FRR decides which route wins
What you'll learn
- Walk the eleven-step BGP best-path algorithm in evaluation order
- Explain why each step exists and which attribute it consumes
- Predict the winning path for a prefix with multiple peers from `show ip bgp` alone
- Identify which step a tie-break decision came from by reading the output flags
- Recognise the production failure modes where the wrong path wins
- Attach the route-maps that feed the algorithm using the 1.5 neighbour address-family tree
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) · 2026-08-19
The BGP best-path algorithm is the eleven-step decision process FRR runs for every prefix in the BGP table when more than one candidate path exists. The process is strictly ordered: step 1 is always evaluated first, and the first step that produces a difference is the one that decides the winner. The remaining steps are not evaluated for that prefix. An operator who understands the order can predict which path will win by reading show ip bgp <prefix>; an operator who does not is at the mercy of BGP defaults and router-ID tiebreaks.
This lesson walks the eleven steps in order, explains what attribute each step consumes, and shows the evidence each step leaves in the output. The goal is not memorisation — the goal is the ability to read a show ip bgp output and immediately say “this path won at step 6, MED, because all five earlier steps were equal”.
Why eleven steps and not one
BGP is a policy protocol. The decision process encodes the trust hierarchy: attributes the local operator controls (Weight, Local Preference) are evaluated first; attributes the peer can influence (AS Path, MED, Origin) come later; the IGP cost to the next-hop is the local operator’s view of the path again; the router-ID and neighbour IP are deterministic tiebreakers that guarantee a single winner.
The eleven steps are not arbitrary. They were chosen by the protocol designers to reflect how Internet operators reason about route selection: “I prefer my own policy (Weight), then my AS’s policy (Local Preference), then my own routes (Locally Originated), then the shortest path (AS Path), then the origin (how the route was injected), then the peer’s hint (MED), then the boundary-vs-interior preference (eBGP over iBGP), then the cost to reach the next-hop (IGP), then determinism (router-ID, cluster list length, neighbour IP)”.
flowchart TD
S1["Step 1: Highest Weight<br/>(Cisco-proprietary)"]
S2["Step 2: Highest Local Preference"]
S3["Step 3: Locally Originated<br/>(network, aggregate, redistribute)"]
S4["Step 4: Shortest AS Path"]
S5["Step 5: Lowest Origin<br/>(IGP < EGP < Incomplete)"]
S6["Step 6: Lowest MED<br/>(only between paths from same AS)"]
S7["Step 7: eBGP over iBGP"]
S8["Step 8: Lowest IGP cost to next-hop"]
S9["Step 9: Keep the current best<br/>(external stability)"]
S10["Step 10: Lowest router-id<br/>(or originator-id via a reflector)"]
S11["Step 11: Shortest cluster list,<br/>then lowest neighbour IP"]
S1 -->|tie| S2
S2 -->|tie| S3
S3 -->|tie| S4
S4 -->|tie| S5
S5 -->|tie| S6
S6 -->|tie| S7
S7 -->|tie| S8
S8 -->|tie| S9
S9 -->|tie| S10
S10 -->|tie| S11
S11 -->|tie| WIN["Single winner guaranteed"]
The terminal node is always a single winner; the algorithm cannot return two equal-best paths. If two operators see different > winners for the same prefix on two different routers in the same AS, one of them is wrong (stale BGP table, broken iBGP, or a difference in policy).
The minimal show ip bgp reading skill
Before walking the steps, the operator needs to read show ip bgp fluently. The relevant fields:
$ show ip bgp 198.51.100.0/24BGP routing table entry for 198.51.100.0/24
Paths: (3 available, best #2, table default)
65001
192.0.2.2 from 192.0.2.2 (10.255.0.1)
Origin IGP, metric 50, localpref 100, valid, external
Community: 64512:100
65002
198.51.100.1 from 198.51.100.1 (10.255.0.2)
Origin IGP, metric 20, localpref 200, valid, external, best (Local Pref)
65003
203.0.113.5 from 10.0.0.5 (10.255.0.5)
Origin incomplete, metric 0, localpref 100, valid, internalIllustrative output
The fields the operator reads in order:
- Paths — total candidate paths for this prefix (3 in the example).
- best #2 — the algorithm selected the second path listed.
- The bare ASN line above each path (
65001,65002,65003) — the AS path, step 4 input. A locally originated path showsLocalhere instead. - Path source (192.0.2.2, 198.51.100.1, 203.0.113.5) — the next-hop the path uses.
- From (10.255.0.1, 10.255.0.2, 10.255.0.5) — the BGP router-id of the peer that sent the route.
- Origin IGP / EGP / incomplete — step 5 input.
- metric — step 6 input (MED).
- localpref — step 2 input.
- weight — step 1 input. FRR prints it on the flags line when it is not the default; a path with no weight shown is a path at weight 0.
- valid, external/internal — step 7 input (eBGP vs iBGP).
The last field on the winning path is the one worth learning first.
FRR does not just mark the best path — it names the step that chose
it, in parentheses after best. best (Local Pref) is step 2;
best (AS Path) is step 4; best (MED) is step 6; best (Router ID)
and best (Neighbor IP) are the deterministic tail. When that string
is present it replaces the entire manual walk-through below: the
router has already told you which comparison was decisive.
Treat it as the answer and the walk-through as the explanation of why that answer is the one you got. The string is a diagnostic convenience, not part of the protocol, so its exact wording is an FRR implementation detail rather than something to build a script around.
The eleven steps in order
Step 1 — Highest Weight
Weight is a Cisco-proprietary attribute that is local to the router and not propagated to any peer. The default is 0 for every path. The operator who configures a route-map to set weight on a peer’s routes can make that peer’s paths preferred regardless of any other attribute.
On VyOS 1.5 LTS, Weight is emulated via route-map:
set policy route-map WEIGHT-PEER-A rule 10 action 'permit'
set policy route-map WEIGHT-PEER-A rule 10 set weight '200'
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast route-map import 'WEIGHT-PEER-A'
The attachment moved in 1.4. The direction is no longer a trailing
in / out keyword on the neighbour: it is route-map import or
route-map export under the neighbour’s address family, and the
ASN is no longer part of the path. A 1.3-era ... neighbor 192.0.2.2 route-map WEIGHT-PEER-A in is rejected at commit on 1.5.
The set weight 200 clause (compiled to FRR’s set weight 200 in the BGP route-map) gives every path from 192.0.2.2 a weight of 200. All other paths retain weight 0. Step 1 makes the 192.0.2.2 path the winner of any tiebreak.
Evidence in show ip bgp: the weight field on the path. The operator who sees weight 200 on a path and weight 0 on the others knows step 1 decided the prefix.
Step 2 — Highest Local Preference
Local Preference is well-known discretionary, propagated throughout the local AS, and ignored by eBGP peers. The default is 100. Higher wins.
set policy route-map LP-PEER-A rule 10 action 'permit'
set policy route-map LP-PEER-A rule 10 set local-preference '200'
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast route-map import 'LP-PEER-A'
The operator who sets local-preference 200 on routes from peer A and leaves the default 100 on routes from peer B guarantees that the local AS prefers peer A for outbound traffic (subject to AS Path being equal at step 4).
Evidence in show ip bgp: the localpref field. The path with the highest localpref wins step 2.
Step 3 — Locally Originated
A route that the local router injected into BGP via network, aggregate-address, or redistribute wins over a route learned from any peer. The reasoning: the local router should prefer its own routes, not transit copies of them.
A locally-injected route is shown with > (best) and the next-hop is the local router (0.0.0.0 or the local interface). The path is also marked as locally originated in the BGP table — the operator sees the absence of any peer’s IP in the next-hop field.
Step 4 — Shortest AS Path
The AS Path is the path-vector that gives BGP its name. The shortest AS Path wins. The count is the number of ASes in the path, not the number of path segments.
A path with AS Path 64512 65001 has length 2 (two AS hops). A path with AS Path 64512 65001 65002 65003 has length 4. The path with length 2 wins at step 4.
Evidence in show ip bgp: the Path field at the end of the line. The path with the fewest ASNs before the i/e/? origin code wins.
The operator who configures AS Path prepending on outbound advertisements (covered in vyos-xxvii-03-as-path-prepending) is influencing step 4 — making their own AS path artificially longer so upstreams prefer the other AS path.
Step 5 — Lowest Origin
Origin is the well-known mandatory attribute that says how the route entered the originating AS. Three values:
| Origin code | Meaning | Preference |
|---|---|---|
IGP (i) | The route was injected via network or aggregate | Preferred |
EGP (e) | The route was learned from an EGP (legacy; rarely seen) | Middle |
Incomplete (?) | The route was learned via redistribution | Least preferred |
IGP < EGP < Incomplete. The ordering is fixed by RFC 4271; the operator cannot change it.
Evidence in show ip bgp: the Origin field. The path with Origin IGP wins over Origin incomplete.
The production consequence: the operator who distributes OSPF into BGP via redistribute ospf advertises routes with Origin incomplete. The operator who uses network gets Origin IGP. Internet peers that prefer Origin IGP will deprioritise the redistributed routes — sometimes correctly (the route is more suspect), sometimes incorrectly (the operator intended the route to be preferred).
Step 6 — Lowest MED
MED (Multi-Exit Discriminator) is the optional non-transitive attribute that lets one AS hint to a neighbouring AS “please send me traffic via this link”. Lower MED wins. MED is only compared between paths from the same neighbouring AS — comparing MED across paths from different ASes violates the standard and many implementations (including FRR) refuse to do it.
set policy route-map MED-LOW rule 10 action 'permit'
set policy route-map MED-LOW rule 10 set metric '50'
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast route-map export 'MED-LOW'
The operator sets MED 50 on routes advertised to peer 192.0.2.2 and MED 100 on routes advertised to peer 198.51.100.1. The peer sees both routes and prefers the lower MED (50) — assuming the peer does the comparison, which is the default in most implementations but changed globally with set protocols bgp parameters always-compare-med (the standard is to NOT compare MED across ASes, and this knob is a router-wide setting rather than a per-peer one).
Evidence in show ip bgp: the metric field. The path with the lowest metric wins step 6, only if all paths are from the same AS.
Step 7 — eBGP over iBGP
A route learned from an eBGP peer is preferred over a route learned from an iBGP peer (all other steps equal). The reasoning: eBGP is “closer to the source” — the next-hop is in another AS, the path is external, and the operator wants to leave the AS as soon as possible.
Evidence in show ip bgp: the valid, external vs valid, internal flag. The path marked external wins step 7.
Step 8 — Lowest IGP cost to next-hop
When all the above tie, the algorithm picks the path whose next-hop is reachable via the lowest-cost IGP path inside the local AS. This is the cost to reach the BGP next-hop in the routing table — the IGP metric from the local router to the next-hop.
Evidence in show ip bgp: the path with the lowest IGP cost to its next-hop wins. The cost is not shown directly in show ip bgp; the operator correlates the next-hop with show ip route <next-hop> and reads the metric.
Step 9 — Keep the path that is already best (external stability)
When two external paths are still tied at step 9, FRR prefers the one that is currently selected. This is a stability rule, not a preference rule: it stops the table churning every time a session flaps and re-learns an equally good path, at the cost of making the outcome depend on arrival order rather than on anything in the configuration.
That is exactly the property that makes a tie hard to reproduce — two routers with identical policy can settle on different winners because they learned the paths in a different order. The knob that trades stability back for determinism is:
set protocols bgp parameters bestpath compare-routerid
With it set, FRR skips the stability rule for external paths and goes straight to comparing router-ids, so both routers reach the same answer from the same inputs.
Step 10 — Lowest Router-ID
The first genuinely deterministic tiebreaker: the BGP identifier of the router that sent the path. Lower wins. For a path that arrived through a route reflector, the comparison uses the ORIGINATOR_ID the reflector attached, which is the identifier of the client that actually originated it — not the reflector’s own.
Evidence in show ip bgp: the parenthesised identifier in from 10.0.0.5 (10.255.0.5). The path with the lowest value wins step 10.
Step 11 — Shortest cluster list, then lowest neighbour IP
Two remaining comparisons, in this order.
First, the shortest CLUSTER_LIST. Every route reflector that passes a route prepends its cluster-id, so the cluster list length is a count of reflector hops. Preferring the shorter one prefers the path that took fewer reflections — the reflected equivalent of a shorter AS path. It only distinguishes anything inside a reflected iBGP topology; outside one, every path has an empty cluster list.
Then the neighbour’s IP address, lowest wins. This is the floor of the algorithm: two paths cannot share a peer address, so a winner always exists. A tie decided here carries no meaning at all — it means the configuration expressed no preference and the router had to pick something.
Evidence in show ip bgp: the from <peer-ip> field, and the Cluster list: line on paths that passed through a reflector.
The eleven-step walk with a real example
The operator is debugging a prefix with three candidate paths. The output is:
$ show ip bgp 198.51.100.0/24Paths: (3 available, best #2, table default)
65001
192.0.2.2 from 192.0.2.2 (10.255.0.1)
Origin IGP, metric 50, localpref 100, valid, external
65002
198.51.100.1 from 198.51.100.1 (10.255.0.2)
Origin IGP, metric 20, localpref 200, valid, external, best (Local Pref)
65003
203.0.113.5 from 10.0.0.5 (10.255.0.5)
Origin incomplete, metric 0, localpref 100, valid, internalIllustrative output
Walk the steps:
- Step 1 — Weight. All paths have weight 0. Tie.
- Step 2 — Local Preference. Path 2 has localpref 200; paths 1 and 3 have 100. Path 2 wins.
Done. The algorithm never evaluates steps 3-11 for this prefix because step 2 produced a difference — and FRR agrees with you in writing, on the flags line: best (Local Pref).
Now change one thing and follow it through, because this is where the MED rule bites. Raise Local Preference on path 1 to 200 so it matches path 2. Step 2 now ties, and the walk continues:
- Step 3 — Locally Originated. Neither path is local. Tie.
- Step 4 — AS Path. Path 1 is
65001, path 2 is65002; both length 1. Tie. - Step 5 — Origin. Both IGP. Tie.
- Step 6 — MED. Path 1 has metric 50, path 2 has metric 20. It looks decisive, and it is not: the two paths come from different neighbouring ASes (65001 and 65002), so FRR does not compare their MEDs at all. Step 6 is skipped, not won.
- Step 7 — eBGP over iBGP. Both external. Tie.
- Step 8 — IGP cost to next-hop. Whichever next-hop is cheaper in the IGP wins here.
The instinct to read “metric 20 beats metric 50” is the single most common misreading of this output. The metric column is only meaningful when the paths above and below it share a neighbouring AS. If the operator genuinely wants that comparison across ASes, it takes set protocols bgp parameters always-compare-med, and that is a router-wide behaviour change with consequences for every other prefix.
Confirm the reasoning rather than trusting it: if FRR prints best (MED) on the winner, the comparison did happen; if it prints best (IGP Metric), step 6 was skipped exactly as described.
The operator who can predict the walkthrough is the operator who can debug the best-path decision without changing configuration.
How the result is validated
show ip bgp
show ip bgp 198.51.100.0/24
show ip bgp 198.51.100.0/24 bestpath
show ip bgp regexp _65001_
show ip route 198.51.100.0/24
show ip bgp summary
The second command is the canonical single-prefix view and the one that carries the best (...) reason. The third narrows it to the selected path alone. The fourth is the AS-path filtered view. The fifth is the check that the winning BGP path also made it into the FIB — a path can be best in BGP and still not be installed, usually because its next-hop does not resolve.
VyOS op mode passes these through to vtysh, so show ip bgp and vtysh -c 'show ip bgp' return the same text. Reach for vtysh when you need an FRR subcommand VyOS has not wrapped, not because the VyOS form is a lesser view of the same data.
How it fails
The production failure modes the engineer must recognise:
- Step 1 silently overruling step 2. A route-map set weight on a single router wins against a Local Preference of 200 set on the upstream. The operator who configures Local Preference expecting it to win gets a surprise because weight is evaluated first.
- Step 4 counting differently than expected under
bestpath as-path confed. With the knob set, the confederation sub-AS hops count toward AS-path length; without it they do not. Two routers configured differently rank the same paths differently, and neither is “wrong”. - Step 5 (Origin) being a non-configurable tiebreaker. The operator who redistributes OSPF into BGP gets
Origin incompleteand the prefix is less preferred thanOrigin IGPfrom a peer. The fix is to usenetworkinstead ofredistribute. - Step 6 (MED) being incomparable across ASes. The operator sets MED on peer A and expects it to be weighed against peer B’s. It is not, because they are different ASes — the metric column is present and simply not consulted.
set protocols bgp parameters always-compare-medis what enables the comparison, and it changes selection for every prefix on the router, not just the one being debugged. - Step 7 (eBGP over iBGP) choosing the wrong egress. A confederation sub-AS treats eBGP and iBGP paths differently. The operator who reorganises into a confederation sees the best-path winners change.
- Step 9 (stability) making a tie unreproducible. Two routers with identical policy select different winners because they learned the paths in a different order, and each is keeping the path it already had. Nothing in the configuration explains the difference.
set protocols bgp parameters bestpath compare-routeridmakes both converge on the same answer. - Step 11 (neighbour IP) deciding the prefix. All earlier steps are tied and the lowest neighbour IP wins. Adding a peer with a lower address silently moves traffic, because the outcome was never expressing a preference in the first place — it was expressing the absence of one.
Rollback
Best-path changes are configuration changes. The standard rollback path applies:
compareto see the diff beforecommit.commit-confirm 5for any remote change: it commits, starts a five-minute timer, and reverts to the previously saved configuration unlessconfirmis entered inside the window.rollback 1to go back to the previous revision. This is not a one-word undo — VyOS prompts before it applies the revision, and the prompt is worth reading on a remote router.load /config/archive/<known-good-file>followed bycommitto return to a specific snapshot.
The operator who changes the best-path algorithm must also know how to roll back the change. Production discipline is: every change has a tested rollback path before the change is committed.
Production discipline
Cross-course references
The Linux course’s XIX-Linux-NetFoundations covers the FIB. The OPNsense course’s XXX-OPNsense-DynamicRouting covers the equivalent FRR-managed BGP path selection on the firewall side. The Observability course’s XII-Observability-HostAgents covers scraping the show ip bgp output for monitoring. The BGP lessons vyos-xxvi-01-local-preference, vyos-xxvi-02-as-path, vyos-xxvi-04-med, and vyos-xxvi-05-community cover the individual attributes that feed into the eleven steps; the lesson vyos-xxvii-06-best-path-troubleshoot walks the debugging of wrong-path-wins failures.
Quiz
Knowledge check · 5 questions
Q1. Three candidate paths for a prefix have weight 0, localpref 200, Origin IGP, metric 50, external; weight 0, localpref 100, Origin IGP, metric 20, external; weight 0, localpref 100, Origin incomplete, metric 0, internal. Which step decides the winner?
Q2. The MED (metric) is compared across all candidate paths for a prefix, regardless of which AS they came from.
Q3. On VyOS 1.5, how is an inbound route-map attached to BGP neighbour 192.0.2.2 for IPv4 unicast?
Q4. An operator sets a route-map with `set weight 500` on routes from peer A. The peer B routes have Local Preference 200 from the upstream. The operator expected Local Preference to win. Why does peer A win?
The operator configured a route-map with `set weight 500` attached as `set protocols bgp neighbor <peer-A> address-family ipv4-unicast route-map import WEIGHT-PEER-A`, and a route-map with `set local-preference 200` attached the same way on peer B. The BGP table shows peer A's path winning despite the lower localpref.
Q5. An operator redistributes OSPF into BGP and sees the redistributed routes being less preferred than the same routes from a peer. The operator expected redistribution to be transparent. What is the most likely cause and fix?
The operator has `set protocols ospf redistribute bgp` and `set protocols bgp address-family ipv4-unicast redistribute ospf`. The redistributed BGP routes have `Origin incomplete` and lose to peer routes with `Origin IGP`.
Passing score: 75%. Answers are checked in this browser.