Skip to main content
RunBook Academy

VyOSXXVII · BGP Best PathBest path

The Weight attribute — a local-only tie-breaker, per-neighbour and per-prefix

Advanced⏱ ~18 minset protocols bgp neighbor address-family ipv4-unicast weightset policy route-map rule set weightset protocols bgp neighbor address-family ipv4-unicast route-map importshow bgp ipv4 unicastshow bgp ipv4 unicast summaryshow policy route-mapvtysh -c show route-map

What you'll learn

  • Explain why Weight is the first step in the best-path algorithm
  • Configure Weight on VyOS 1.5 LTS both per-neighbour and per-prefix
  • Distinguish Weight (per-router) from Local Preference (per-AS)
  • Apply Weight to override an upstream's MED preference on a single router
  • Recognise the production failure modes where Weight was the wrong tool

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)

Not yet marked complete on this device.

Weight is the first step in the BGP best-path algorithm and the only step whose value never leaves the router. It is not a BGP protocol attribute: no UPDATE message carries a Weight field, RFC 4271 does not define one, and nothing a peer does can set it. It is a local implementation concept — one that originated on Cisco routers and that FRR implements with the same semantics — and its scope is exactly one router.

That scope is the single most important property of Weight, and the reason it is the right tool for some problems and the wrong tool for others. A Weight set on R1 has no effect whatsoever on R2, even when R1 and R2 are iBGP peers in the same AS.

Why Weight is evaluated first

The best-path algorithm evaluates the attributes the local operator controls before those a peer influences. Local Preference is the next step, but Local Preference is propagated across iBGP — it is the operator’s policy for a whole AS. Weight is more local still: the operator’s policy for this one router. The algorithm honours that hierarchy by evaluating Weight first.

The practical consequence is a trade. Setting Weight on a single router to override an upstream’s MED gets the override at the price of breaking AS-wide consistency. If the policy needs to flow to other iBGP speakers, Local Preference is the right tool. If the policy is deliberately local to one border router, Weight is.

flowchart LR
  subgraph "Router R1 (the only one with Weight set)"
    W1["Weight 500 on routes from peer A"]
    LP1["Local Preference 100 (default)"]
  end
  subgraph "Router R2 (no Weight set)"
    W2["Weight 0 everywhere"]
    LP2["Local Preference 100 (default)"]
  end
  subgraph "Peer A"
    A["192.0.2.2"]
  end
  subgraph "Peer B"
    B["198.51.100.1"]
  end
  A --> W1
  B --> LP1
  A --> W2
  B --> LP2
  W1 -->|"decided at step 1"| R1["R1 chooses peer A"]
  LP2 -->|"tie, falls through"| R2["R2 compares AS_PATH<br/>and later steps"]

R1 has a reason to prefer peer A — perhaps it is the border router for a site with a commercial preference for that upstream. R2 does not have that reason. With Weight set on R1 only, R1 decides at step 1 and R2 falls through to Local Preference, AS_PATH and the rest.

Configuring Weight on VyOS 1.5 LTS

VyOS 1.5 exposes Weight in two places, and choosing between them is the first design decision.

Per neighbour, for every route that peer sends. This is a leaf under the neighbour’s address family, and it is the simpler of the two:

configure
set protocols bgp system-as 64512
set protocols bgp neighbor 192.0.2.2 remote-as 65001
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast weight 500
commit
save

Every prefix learned from 192.0.2.2 in the IPv4 unicast family is stored with weight 500. There is no matching, no route-map, and nothing to keep in sync. The accepted range on this leaf is 1-65535.

Per prefix, via a route-map. When only some of a peer’s routes should be weighted, the weight is set in a route-map applied on import:

set policy prefix-list CUSTOMER-ROUTES rule 10 action permit
set policy prefix-list CUSTOMER-ROUTES rule 10 prefix 198.51.100.0/24
set policy prefix-list CUSTOMER-ROUTES rule 10 description 'Customer edge routes'

set policy route-map WEIGHT-CUSTOMER rule 10 action permit
set policy route-map WEIGHT-CUSTOMER rule 10 match ip address prefix-list CUSTOMER-ROUTES
set policy route-map WEIGHT-CUSTOMER rule 10 set weight 600

set policy route-map WEIGHT-CUSTOMER rule 20 action permit

set protocols bgp neighbor 203.0.113.5 address-family ipv4-unicast route-map import WEIGHT-CUSTOMER

Only routes matching 198.51.100.0/24 from 203.0.113.5 get weight 600; everything else from that peer keeps weight 0. The route-map leaf accepts a wider range than the neighbour leaf does (0 to 4294967295), which is occasionally useful and mostly a trap — see the failure modes.

Rule 20 is not optional. A route-map denies anything that matches no entry, so a map with only rule 10 would reject every prefix outside the prefix-list. The empty permit at the end is what makes this an annotating map rather than a filtering one.

Reading the weight back

Read-only / Safeweight visible on the path
$ show bgp ipv4 unicast 198.51.100.0/24
BGP routing table entry for 198.51.100.0/24
Paths: (2 available, best #1, table default)
65001
  192.0.2.2 from 192.0.2.2 (10.255.0.1)
    Origin IGP, metric 0, localpref 100, weight 500, valid, external, best (Weight)
65002
  198.51.100.1 from 198.51.100.1 (10.255.0.2)
    Origin IGP, metric 0, localpref 100, valid, external

Illustrative output

Two details are worth reading carefully. The weight 500 field appears on the first path and the best-path reason in parentheses names the step that decided it — best (Weight) is FRR telling you the decision was made at step 1 and nothing further was compared. The second path shows no weight field at all, because FRR omits a weight of zero rather than printing it.

If you need the same view without the VyOS operational wrapper, vtysh -c 'show bgp ipv4 unicast 198.51.100.0/24' produces it directly.

The canonical Weight use cases

1. Override an upstream’s MED on a single border router. The upstream sends the same prefix with MED 50 from peer A and MED 100 from peer B. Left alone the router prefers the lower MED. If this router should egress via peer B — because it is the backup border and should not carry primary traffic — a weight on peer B settles it at step 1, long before MED is looked at.

2. Engineering a per-router egress for a specific prefix. A prefix should leave via peer A on R1 and via peer B on R2, with AS-wide Local Preference identical on both. A route-map weight on each router’s preferred peer gives exactly that asymmetry, and gives it deliberately.

3. Validating a policy before deploying it AS-wide. A new preference is easier to test as a weight on one router than as a Local Preference change that propagates. The blast radius is one device and the rollback is one delete.

4. Defending against a peer you do not control. A peer sends routes with an implausibly short AS_PATH or an unhelpfully low MED and will not change. Weight on the other peer’s routes raises them above the problem without arguing about it.

5. Deliberate, documented asymmetry. Sometimes two border routers should choose differently, and the difference should be visible in the configuration rather than emerging from a metric accident. Weight makes that intent explicit.

Note what is missing from that list: anything AS-wide. “Prefer this upstream for the whole AS” is a Local Preference job, and reaching for Weight there is the root of every failure below.

The canonical “wrong tool” failures

1. AS-wide policy accidentally per-router. An operator sees weight 500 in a configuration and reads it as an AS-wide preference. It is not. A change made in that belief moves one router and leaves the rest of the AS where it was.

2. Two operators, two answers. Two people in the same AS run the same show command against the same prefix and see different winners. One router has a weight and the other does not. The asymmetry is invisible until somebody finds the route-map.

3. Traffic leaves by the wrong border. The router carrying the weight is not the router the operator pictured, so traffic egresses somewhere unexpected. The fix is to remove the weight and express the intent as Local Preference.

4. Drift between routers. R1 has weight 500 on peer A; R2 was given 600 during an incident and never reverted. The two borders now disagree permanently, and nothing in either configuration says why.

5. A test weight that outlived the test. A weight added to validate a change is never removed. It silently wins step 1 against every Local Preference the AS configures afterwards, so the AS-wide policy is correct and ineffective at the same time.

6. A weight above the neighbour leaf’s range. The route-map leaf accepts values up to 4294967295 while the per-neighbour leaf stops at 65535. A number chosen for one and pasted into the other is rejected at commit — the good outcome — but the same mismatch across two routers produces a preference no reviewer can explain from the numbers alone. Pick one small scale, write it down, and stay on it.

Weight vs Local Preference — the decision matrix

QuestionUse WeightUse Local Preference
Should the policy apply to one router or many?One routerMany routers in the AS
Should the policy reach iBGP peers?No — it cannotYes
Will the neighbouring AS ever see it?NoNo, but iBGP does
Is it a per-router override of an AS-wide policy?Yes, the canonical caseNo
Is it scoped to one prefix?Either worksEither works
Is it scoped to one peer?Either worksEither works
Should a reviewer be able to see the intent on one router?YesNo — the intent is distributed

Filling in the matrix before configuring is what prevents the wrong-tool failures above.

Removing Weight

Removing a per-neighbour weight is a single delete:

configure
delete protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast weight
commit
save

Removing a route-map weight is two, and the order is worth keeping:

configure
delete protocols bgp neighbor 203.0.113.5 address-family ipv4-unicast route-map import
delete policy route-map WEIGHT-CUSTOMER
commit
save

Detach first, then delete the definition. compare before commit shows both deletions; an operator who reads that diff catches the case where the map was detached but left defined — a zombie that a future change can silently re-attach to a different peer, complete with its original weight.

How the result is validated

show bgp ipv4 unicast 198.51.100.0/24
show bgp ipv4 unicast summary
show policy route-map
show configuration commands | match weight

The first confirms the weight is attached to the path you meant and shows which step decided the best path. The second confirms the session is still Established — a route-map that denies everything looks very much like a peer that went down. The third confirms the map is defined as you think. The fourth is the audit line: every weight on the router, in one screen, which is the artefact to diff against the other border.

For per-rule hit counters, drop to FRR:

vtysh -c 'show route-map WEIGHT-CUSTOMER'

A rule with a zero counter after a soft-clear is a rule that is not matching, which is a different problem from a rule that matches and sets the wrong value.

How it fails

  • Applied on export instead of import. route-map export runs on what this router advertises. Weight belongs to a stored path, so the map commits cleanly and changes nothing.
  • The match never fires. A prefix-list that does not cover the prefix means set weight never runs. vtysh -c 'show route-map ...' shows a zero counter on the rule.
  • A missing trailing permit. A route-map with only the matching rule denies everything else. The symptom is not “the weight is wrong” but “most of the peer’s prefixes vanished”.
  • The map denies instead of permitting. action deny on the matching rule drops the route rather than weighting it. Again the symptom is a missing prefix, not a wrong preference.
  • Applied to the wrong peer. The weight lands on peer B’s routes. Traffic egresses via B, the operator looks at A’s configuration, and the two never meet.
  • Detached but not deleted. The map is removed from the peer and left in policy. Nothing is wrong today. Something is wrong the day it is re-attached.

Rollback

Weight changes are ordinary configuration changes, so the ordinary rollback path applies:

  • compare before commit to see exactly what is being added.
  • commit-confirm <minutes> for any change made over the path it affects.
  • rollback 1, commit, save to return to the previous revision.
  • load /config/archive/<known-good-file>, commit, save to return to a specific archived snapshot.

The previous revision had no weight, so rollback 1 removes it completely — including, importantly, the route-map definition, which a hand-written delete of the attachment would have left behind.

Production discipline

Cross-course references

The Linux course’s XIX-Linux-NetFoundations covers the kernel FIB that receives whichever path wins. The OPNsense course’s XXX-OPNsense-DynamicRouting covers the same FRR route-map machinery on the firewall side. vyos-xxvi-01-local-preference covers step 2 and the AS-wide alternative to everything here; vyos-xxvii-01-best-path-algorithm covers the full ordering; vyos-xxvii-06-best-path-troubleshoot walks the debugging of wrong-path-wins failures.

Quiz

Knowledge check · 4 questions

  1. Q1. What is the scope of the Weight attribute?

  2. Q2. The Weight attribute is propagated to iBGP peers along with the route.

  3. Q3. An operator applies a route-map with `set weight 500` on import from peer A, expecting peer A's routes to win. `show bgp ipv4 unicast <prefix>` confirms weight 500 on peer A's path, but peer B's path is still best. Diagnose it.

    The route-map is defined, attached with `route-map import` on peer A's IPv4 unicast address family, and the weight is visibly attached to the path. The best-path marker is nevertheless on peer B's path, and the best-path reason in the FRR output names Weight as the deciding step.

  4. Q4. An operator wants the whole AS to prefer peer A over peer B for outbound traffic. They set a weight on peer A on one border router. The other border router still uses peer B. What was the wrong tool, and what should they do instead?

    The operator expected the preference to flow from R1 to R2 over iBGP. Weight does not flow - it is not carried in BGP at all - so R2 is unaffected and the AS now has two border routers making different egress decisions for the same prefix.

Passing score: 75%. Answers are checked in this browser.