Skip to main content
RunBook Academy

VyOSXXV · BGP Route AdvertisementAdvertisement

BGP conditional advertisement — advertise-map and non-exist-map

Advanced⏱ ~24 minvyosvtyshset policy route-mapset policy prefix-listshow ip bgpshow ip bgp neighbors advertised-routes

What you'll learn

  • Configure a per-neighbour advertise-map with an exist-map or non-exist-map on VyOS 1.5
  • Explain what the conditional is evaluated against, and on what timer
  • Recognise the backup-path use case and its withdraw-on-failure inverse
  • Diagnose why a conditional advertisement never fires, using the evidence VyOS and FRR actually give you

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

Not yet marked complete on this device.

BGP conditional advertisement is the operator’s tool for reactive advertisement: advertise this prefix to this peer only when some other prefix is — or is not — in the local BGP table.

Three facts shape everything else in this lesson, and getting them straight first saves a lot of confusion:

  1. It is per neighbour and outbound. There is no global “conditional advertisement” object. The configuration hangs off one neighbour’s address family and changes what that neighbour is sent.
  2. The condition is evaluated against the local BGP table, not against interface state, not against a peer’s session state.
  3. It runs on a periodic scanner, not on events. Failover is bounded by that timer, which is why this is a policy mechanism and not a fast-failover mechanism.

The two maps

The mechanism uses two route-maps with different jobs, and the naming does not make the difference obvious.

  • advertise-map — names the prefixes whose advertisement to this neighbour is placed under conditional control. Its permit rules select what is conditionally advertised.
  • non-exist-map — names the prefixes whose absence from the BGP table makes the condition true. When they are gone, the advertise-map’s prefixes are advertised.
  • exist-map — the inverse. When the named prefixes are in the BGP table, the advertise-map’s prefixes are advertised.

You use advertise-map with exactly one of the other two.

flowchart TB
  T["Local BGP table"] --> C{"Condition route-map<br/>matches a prefix in the table?"}
  C -->|"non-exist-map: no match"| ADV["Advertise the advertise-map<br/>prefixes to this neighbour"]
  C -->|"non-exist-map: match found"| WD["Withdraw them from<br/>this neighbour"]
  C -->|"exist-map: match found"| ADV
  C -->|"exist-map: no match"| WD
  ADV --> P["Neighbour"]
  WD --> P

The backup-path use case

The canonical use is a second address block that should only appear when the first one is gone.

flowchart LR
  AS["AS 64512"]
  P1["Provider A<br/>(primary)"]
  P2["Provider B<br/>(backup)"]
  PR["Primary prefix<br/>192.0.2.0/24"]
  BK["Backup prefix<br/>198.51.100.0/24"]

  PR --> AS
  BK --> AS
  AS -- "always advertises 192.0.2.0/24" --> P1
  AS -- "advertises 198.51.100.0/24 only<br/>when 192.0.2.0/24 has gone" --> P2
  • While 192.0.2.0/24 is in the local BGP table, the condition (non-exist) is false and 198.51.100.0/24 is not advertised to Provider B.
  • When 192.0.2.0/24 leaves the BGP table, the condition becomes true on the next scanner run and 198.51.100.0/24 is advertised.
  • When it comes back, the backup is withdrawn again.

Note what the condition is watching: the BGP table, not the link and not the session. If the primary prefix is locally originated, it disappears only when the router stops originating it. That is the single most common reason this design does not behave the way its author expected, and the quiz returns to it.

The VyOS configuration

Route-maps and prefix-lists first, because the commit will reject a neighbour that names a route-map which does not exist:

set policy prefix-list PRIMARY-PFX rule 10 action 'permit'
set policy prefix-list PRIMARY-PFX rule 10 prefix '192.0.2.0/24'

set policy prefix-list BACKUP-PFX rule 10 action 'permit'
set policy prefix-list BACKUP-PFX rule 10 prefix '198.51.100.0/24'

set policy route-map ADVERTISE-BACKUP rule 10 action 'permit'
set policy route-map ADVERTISE-BACKUP rule 10 match ip address prefix-list 'BACKUP-PFX'

set policy route-map WATCH-PRIMARY rule 10 action 'permit'
set policy route-map WATCH-PRIMARY rule 10 match ip address prefix-list 'PRIMARY-PFX'

Then the origination and the conditional, on the neighbour that should receive the backup:

set protocols bgp system-as 64512
set protocols bgp address-family ipv4-unicast network '192.0.2.0/24'
set protocols bgp address-family ipv4-unicast network '198.51.100.0/24'

set protocols bgp neighbor 198.51.100.1 remote-as '65002'
set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast conditionally-advertise advertise-map 'ADVERTISE-BACKUP'
set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast conditionally-advertise non-exist-map 'WATCH-PRIMARY'

Three things to read off that:

  • The conditional lives under one neighbour, inside one address family. A second peer that needs the same behaviour needs its own copy; an IPv6 session needs its own maps and its own address-family ipv6-unicast block.
  • ADVERTISE-BACKUP selects what is conditionally advertised.
  • WATCH-PRIMARY is the condition, and it is matched against the local BGP table.

The scanner timer

FRR does not re-evaluate the condition on every UPDATE. It runs a conditional-advertisement scanner periodically, and 60 seconds is the default. The consequence is blunt: after the primary prefix leaves the table, the backup can take up to a minute to be advertised, plus propagation.

The period is adjustable within a range (FRR accepts 5 to 240 seconds):

set protocols bgp parameters conditional-advertisement timer '20'

Shortening it costs CPU — every run walks the table for every neighbour with a conditional — and buys you a smaller worst case, not a fast one.

exist-map versus non-exist-map

The two express opposite intents and are easy to swap by accident:

IntentCondition mapBehaviour
Advertise a backup when the primary is gonenon-exist-mapAdvertise while the watched prefix is absent
Advertise only while an upstream is presentexist-mapAdvertise while the watched prefix is present

The exist-map form is the withdraw-on-failure pattern: keep attracting traffic from this peer only while you have a working path onward, so you stop being a blackhole when you do not.

set policy prefix-list UPSTREAM-A-PFX rule 10 action 'permit'
set policy prefix-list UPSTREAM-A-PFX rule 10 prefix '203.0.113.0/24'

set policy route-map WATCH-UPSTREAM-A rule 10 action 'permit'
set policy route-map WATCH-UPSTREAM-A rule 10 match ip address prefix-list 'UPSTREAM-A-PFX'

set policy route-map ADVERTISE-MINE rule 10 action 'permit'
set policy route-map ADVERTISE-MINE rule 10 match ip address prefix-list 'PRIMARY-PFX'

set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast conditionally-advertise advertise-map 'ADVERTISE-MINE'
set protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast conditionally-advertise exist-map 'WATCH-UPSTREAM-A'

Pick the watched prefix carefully. A prefix that upstream A originates and nobody else does is a decent proxy for “A is reachable”; a prefix that arrives from three upstreams tells you nothing about A at all.

Validation

1. The configuration is where you think it is.

show configuration commands | match conditionally-advertise

2. The condition prefix’s presence in the table. This is the input to the decision:

show ip bgp 192.0.2.0/24

Present means a non-exist-map condition is false. Absent means it is true.

3. What the neighbour is actually being sent. This is the output, and it is the real evidence:

Read-only / Safethe prefix list this peer receives
vyos@r1:~$ show ip bgp neighbors 198.51.100.1 advertised-routes

4. Exercise it. Remove the primary origination, wait past the scanner period, and look again:

configure
delete protocols bgp address-family ipv4-unicast network 192.0.2.0/24
commit

Then, after at least one scanner interval, repeat step 3. The backup prefix should now appear in the advertised list. Put the primary back and it should disappear again.

5. Confirm from the peer’s side if you can. The definitive check is what the neighbour has in its table. Your advertised-routes is what you sent; their show ip bgp is what they kept, and an inbound filter on their side can make those differ.

Failure modes

The condition never becomes true

Almost always because the watched prefix has not actually left the BGP table. Work through it in this order:

  1. Is the watched prefix still there? show ip bgp 192.0.2.0/24. If the answer is yes, everything else is a distraction — the mechanism is behaving correctly and the input is wrong.
  2. Why is it still there? The common cases: it is locally originated by a network statement or a redistribution that does not care about the failure; or it is being learned from a second peer as well as the one that failed; or the session you expected to drop is still Established because the hold timer has not expired.
  3. Has a scanner interval elapsed? Up to 60 seconds by default. Do not diagnose inside the first minute.
  4. Does the condition route-map match the prefix? A prefix-list entry of 192.0.2.0/24 does not match 192.0.2.0/25. If you need it to, use le and ge deliberately.
  5. Is outbound policy dropping the backup anyway? If the condition is true and the prefix still does not appear in advertised-routes, the conditional has fired and something else is filtering. Read the neighbour’s outbound route-map.

The advertisement flaps

The watched prefix is itself unstable, so the condition alternates on successive scanner runs and the backup is advertised and withdrawn repeatedly. Every cycle is a real UPDATE to the peer and propagates outward.

The fix is upstream of the conditional: make the watched prefix a stable signal. Watch something you originate, or something with a single stable source, rather than a prefix that arrives over a flapping session. Lengthening the timer hides the flap rather than fixing it, and doubles the worst-case failover at the same time.

The intent and the map are inverted

The configuration works exactly as written, and what it does is the opposite of what was wanted. exist-map advertises while the watched prefix is present; non-exist-map advertises while it is absent. The tell is that the behaviour is consistent and deterministic — it always does the wrong thing, rather than sometimes.

Audit against the intent in words before you audit the syntax: “advertise the backup when the primary is gone” is non-exist-map; “stop attracting traffic when my upstream is gone” is exist-map.

The conditional was applied to the wrong neighbour or family

It is per neighbour, per address family. Applied to the wrong peer, the intended peer sees the prefix unconditionally and the wrong one sees it appear and disappear. Applied under address-family ipv6-unicast when the maps match IPv4 prefixes, the condition can never be true. The rendered FRR block shows both mistakes at a glance, which is why step 1 of validation is worth the keystrokes.

Rollback

delete protocols bgp neighbor 198.51.100.1 address-family ipv4-unicast conditionally-advertise
commit

Removing the conditional does not make the prefix disappear — it returns it to unconditional advertisement, subject to normal outbound policy. That is usually the safe direction, but say it out loud before you do it in an incident: the backup block is about to be advertised permanently, and if the reason it was conditional was that advertising it always causes a problem, you have just caused that problem.

If the safer outcome is “advertise nothing extra”, remove the origination instead:

delete protocols bgp address-family ipv4-unicast network 198.51.100.0/24
commit

For a planned change, commit-confirm 10 protects the session you are working over, compare shows what is about to change, and rollback 1 then commit returns to the previous revision.

Production discipline

Cross-course references

  • vyos-xxv-01-bgp-network-statement covers the origination the condition and the advertisement both depend on.
  • vyos-xxv-03-bgp-redistribute-static covers the alternative origination path, and why a redistributed prefix may not vanish when you expect it to.
  • XXXIII-VyOS-RoutePolicy covers the route-map and prefix-list primitives used here, including le and ge matching.
  • The BGP session parts cover hold timers, BFD and next-hop tracking — the mechanisms that decide when the watched prefix actually leaves the table.

Quiz

Knowledge check · 4 questions

  1. Q1. A neighbour carries `advertise-map ADVERTISE-BACKUP non-exist-map WATCH-PRIMARY`. ADVERTISE-BACKUP matches 198.51.100.0/24; WATCH-PRIMARY matches 192.0.2.0/24. What does this neighbour receive?

  2. Q2. BGP conditional advertisement is re-evaluated on every BGP UPDATE, so the backup path is advertised the instant the watched prefix leaves the table.

  3. Q3. R1 has a non-exist-map watching 192.0.2.0/24. The operator shuts the link to Provider A and waits five minutes. The backup 198.51.100.0/24 is never advertised. Diagnose it.

    R1 originates both blocks with `set protocols bgp address-family ipv4-unicast network 192.0.2.0/24` and `... network 198.51.100.0/24`, and both prefixes are in the local BGP table. The conditional is configured on the Provider B neighbour with `advertise-map ADVERTISE-BACKUP non-exist-map WATCH-PRIMARY`. After the link to Provider A is shut, `show ip bgp neighbors 198.51.100.1 advertised-routes` still lists only 192.0.2.0/24.

  4. Q4. An operator wanted to advertise a backup block when the primary path failed, and configured `exist-map` instead of `non-exist-map`. Describe the behaviour they get, how they would recognise it, and the fix.

    The neighbour carries `advertise-map ADVERTISE-BACKUP exist-map WATCH-PRIMARY`. ADVERTISE-BACKUP matches the backup block 198.51.100.0/24 and WATCH-PRIMARY matches the primary block 192.0.2.0/24. Both blocks are in the local BGP table under normal conditions, and the peer is receiving both.

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