Skip to main content
RunBook Academy

← All labs in VyOS

Lab · advanced · ~96 min

Lab: BGP Prefix Filtering and Traffic Engineering

B · Nested virtualisationC · Simulation

Objectives

  • Extend the Lab 10 topology to two upstreams that also peer with each other, and observe what an unfiltered AS announces
  • Identify a route leak from the peer view rather than from your own configuration, then stop it with an export prefix-list
  • Refuse a more-specific of your own address space on import, and show what accepting it does to your own forwarding table
  • Apply and revise an inbound filter without dropping the session, using route-refresh, and know what soft-reconfiguration costs
  • Replace a yes/no prefix-list with a route-map that filters and tags, producing the community that Lab 12 consumes

Prerequisites

Objective

By the end of this lab you will have produced a genuine route leak in your own topology, found it from a peer’s point of view, stopped it with a filter you can explain rule by rule, and then done the harder half of the job: refusing what an upstream sends you. You will finish by replacing a filter that can only say yes or no with one that also records why the answer was yes — the tag Lab 12 uses to make routing decisions.

The order matters. Most filtering material starts with the filter. This lab starts with the damage, because a prefix-list you wrote to stop something you watched happen is a prefix-list you will still understand in six months.

Architecture

Lab 10’s two routers plus a second upstream, and — this is the part that makes the leak possible — a link between the two upstreams. Without it, AS 65001 has nothing to leak to.

                      AS 65001  site1
                      router-id 192.0.2.101
                      dum0 198.51.100.1/24
                        /                \
      eth1 192.0.2.1/30                   eth2 192.0.2.5/30
         (vmbr90)                            (vmbr91)
            /                                      \
  eth1 192.0.2.2/30                          eth1 192.0.2.6/30
   AS 65010  isp-a                            AS 65020  isp-b
   router-id 192.0.2.102                      router-id 192.0.2.103
   dum0 203.0.113.1/25                        dum0 203.0.113.129/25
        \                                          /
      eth2 192.0.2.9/30 ------------------- eth2 192.0.2.10/30
                            (vmbr92)

Three ASes, three eBGP sessions, one triangle. site1 is a small end-site with two transit providers. isp-a and isp-b peer with each other. Each AS originates exactly one prefix, and the two upstreams split 203.0.113.0/24 between them so that every prefix in the topology has one legitimate origin and two possible paths.

That triangle is the smallest topology in which the most common eBGP misconfiguration in the world is reproducible. An end-site is not supposed to carry traffic between its two upstreams. Nothing in the default configuration prevents it from offering to.

Requirements

  • The completed Lab 10 topology, or 15 minutes to rebuild it. This lab adds one router and two bridges to it.
  • 6 GB RAM and 24 GB disk in total across three VMs.
  • VyOS 1.5 LTS on all three routers, with FRR 10.x underneath. The direction keywords used here — prefix-list import and prefix-list export — are the 1.4/1.5 spelling. Older VyOS and FRR’s own CLI use in and out, so material you find elsewhere will not paste cleanly.
  • Console access to all three VMs. Task 5 shuts a session down on purpose. Management stays on eth0 and is never touched.
  • Roughly 100 minutes, of which about 25 is the topology extension.

Scenario

site1 has been running on one transit provider since Lab 10. The site has just turned up a second, isp-b, for resilience. The two providers also peer with each other directly, which is normal and none of the site’s business.

Nobody has written a single line of routing policy. The sessions came up, the prefixes arrived, traffic flows, and the change is about to be closed as successful. Your job is to find out what the site is advertising before somebody else does.

Tasks

Task 1: Extend the topology and turn everything up unfiltered

Add two more isolated bridges on the hypervisor host. As in Lab 10, these are stanzas for /etc/network/interfaces, not commands:

auto vmbr91
iface vmbr91 inet manual
    bridge-ports none
    bridge-stp off
    bridge-fd 0

auto vmbr92
iface vmbr92 inet manual
    bridge-ports none
    bridge-stp off
    bridge-fd 0

Apply with ifreload -a, then attach the new NICs and build the third router:

# Run on the Proxmox host.
# Substitute the ISO volume ID exactly as `pvesm list local` prints it.
ISO=local:iso/vyos-1.5-lts-amd64.iso
STORE=local-lvm

# site1 gains a link to isp-b; isp-a gains a link to isp-b.
qm set 210 --net2 "virtio,bridge=vmbr91,firewall=0"
qm set 211 --net2 "virtio,bridge=vmbr92,firewall=0"

qm create 212 \
  --name isp-b \
  --memory 2048 --cores 2 --sockets 1 \
  --net0 "virtio,bridge=vmbr0,firewall=0" \
  --net1 "virtio,bridge=vmbr91,firewall=0" \
  --net2 "virtio,bridge=vmbr92,firewall=0" \
  --scsihw virtio-scsi-single \
  --scsi0 "$STORE:8" \
  --ide2 "$ISO,media=cdrom" \
  --boot order=ide2 \
  --ostype l26

qm start 212

Install VyOS on isp-b from the console with install image, then switch its boot order to the disk and detach the ISO. Reboot site1 and isp-a so they enumerate their new interface.

Now the configuration. On site1, add the second upstream:

configure
set interfaces ethernet eth2 address 192.0.2.5/30
set interfaces ethernet eth2 description "transit to isp-b"
set protocols bgp neighbor 192.0.2.6 remote-as 65020
set protocols bgp neighbor 192.0.2.6 description "isp-b transit, lab session"
commit
save /config/pre-lab-11.boot
save

On isp-a, change its origin to the half of 203.0.113.0/24 it owns and add the peering session to isp-b. The delete line is a no-op if you built isp-a fresh from the block above, and VyOS will say so rather than failing the commit:

configure
delete interfaces dummy dum0 address 203.0.113.1/24
set interfaces dummy dum0 address 203.0.113.1/25
set interfaces dummy dum0 description "AS 65010 address space"
set interfaces ethernet eth2 address 192.0.2.9/30
set interfaces ethernet eth2 description "peering to isp-b"
set protocols bgp address-family ipv4-unicast network 203.0.113.0/25
set protocols bgp neighbor 192.0.2.10 remote-as 65020
set protocols bgp neighbor 192.0.2.10 description "isp-b peering"
commit
save /config/pre-lab-11.boot
save

On isp-b, the full baseline:

configure
set system host-name isp-b
set interfaces ethernet eth0 address dhcp
set interfaces ethernet eth0 description "management - not part of the lab"
set interfaces ethernet eth1 address 192.0.2.6/30
set interfaces ethernet eth1 description "transit to site1"
set interfaces ethernet eth2 address 192.0.2.10/30
set interfaces ethernet eth2 description "peering to isp-a"
set interfaces dummy dum0 address 203.0.113.129/25
set interfaces dummy dum0 description "AS 65020 address space"
set service ssh
set protocols bgp system-as 65020
set protocols bgp parameters router-id 192.0.2.103
set protocols bgp parameters log-neighbor-changes
set protocols bgp address-family ipv4-unicast network 203.0.113.128/25
set protocols bgp neighbor 192.0.2.5 remote-as 65001
set protocols bgp neighbor 192.0.2.5 description "site1 customer"
set protocols bgp neighbor 192.0.2.9 remote-as 65010
set protocols bgp neighbor 192.0.2.9 description "isp-a peering"
commit
save /config/pre-lab-11.boot
save

Confirm all three sessions on each router with show bgp summary before continuing. Every neighbour should show a numeric prefix count.

Task 2: Find out what you are announcing

Do not look at site1’s configuration. Look at what isp-b received, because that is what the rest of the world sees.

Read-only / Safeisp-b
$ show bgp ipv4 unicast 203.0.113.0/25
BGP routing table entry for 203.0.113.0/25
Paths: (2 available, best #1, table default)
65010
  192.0.2.9 from 192.0.2.9 (192.0.2.102)
    Origin IGP, valid, external, best (Shorter AS-Path)
65001 65010
  192.0.2.5 from 192.0.2.5 (192.0.2.101)
    Origin IGP, valid, external

Illustrative output

Read the second path. isp-b has been told that it can reach isp-a’s address space through AS 65001 — through a small end-site with two transit links and no business carrying anyone’s traffic but its own. That is a route leak, and site1 created it by doing nothing at all.

Confirm it from the other direction so you know it is not an artefact of one router’s view:

Read-only / Safesite1
$ show ip bgp neighbors 192.0.2.6 advertised-routes
BGP table version is 4, local router ID is 192.0.2.101
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
             i internal, r RIB-failure, S Stale, R Removed
Origin codes:  i - IGP, e - EGP, ? - incomplete

 Network          Next Hop            Metric LocPrf Weight Path
*> 198.51.100.0/24  0.0.0.0                  0         32768 i
*> 203.0.113.0/25   192.0.2.1                0             0 65010 i

Total number of prefixes 2

Illustrative output

Two prefixes, and the site only owns one of them. Write both captures into the journal. This pair — “what the peer holds” and “what I am sending” — is the evidence a provider will ask you for when they call about a leak, and it is worth being able to produce in under a minute.

Task 3: Stop the leak with an export filter

The rule you want is the narrowest one that is true: this AS originates 198.51.100.0/24 and announces nothing else, ever, to anybody.

configure
set policy prefix-list ONLY-MINE rule 10 action permit
set policy prefix-list ONLY-MINE rule 10 prefix 198.51.100.0/24
set policy prefix-list ONLY-MINE rule 10 description "AS 65001 allocation - the only prefix this AS originates"
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast prefix-list export ONLY-MINE
set protocols bgp neighbor 192.0.2.6 address-family ipv4-unicast prefix-list export ONLY-MINE
commit-confirm 5

Confirm the commit, then re-run the Task 2 captures. isp-b should now hold exactly one path for 203.0.113.0/25, and site1 should be advertising exactly one prefix to each upstream.

Read-only / Safesite1
$ show ip bgp neighbors 192.0.2.6 advertised-routes
BGP table version is 6, local router ID is 192.0.2.101
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
             i internal, r RIB-failure, S Stale, R Removed
Origin codes:  i - IGP, e - EGP, ? - incomplete

 Network          Next Hop            Metric LocPrf Weight Path
*> 198.51.100.0/24  0.0.0.0                  0         32768 i

Total number of prefixes 1

Illustrative output

The filter has one rule. The rule that did the work is not in it.

A prefix-list ends with an implicit deny: a route matching no rule is rejected. 203.0.113.0/25 matched nothing, so it was dropped, and the line responsible appears nowhere in show configuration. This is the single most important property of a prefix-list and the one that surprises operators in both directions — people who expect the list to be additive are surprised when everything else vanishes, and people who forget the implicit deny exists are surprised when adding one narrow permit rule to an existing list silently blocks the rest.

Task 4: Refuse what the upstream sends you

Export policy protects everyone else from you. Import policy protects you from everyone else, and it is the direction most sites get wrong, because its failure mode is not an angry phone call.

Simulate a misconfigured upstream. On isp-a, originate a more-specific of site1’s own allocation — the shape of both an accidental mis-assignment and a deliberate hijack:

configure
set interfaces dummy dum1 address 198.51.100.129/25
set interfaces dummy dum1 description "LAB ONLY - simulated mis-origination of a customer prefix"
set protocols bgp address-family ipv4-unicast network 198.51.100.128/25
commit

Now look at what it did to site1 — not to site1’s BGP table, but to site1’s forwarding:

Read-only / Safesite1
$ show ip route 198.51.100.128/25
Routing entry for 198.51.100.128/25
Known via "bgp", distance 20, metric 0, best
Last update 00:00:24 ago
* 192.0.2.1, via eth1, weight 1

Illustrative output

Read-only / Safesite1
$ ip route show table 254 198.51.100.128/25
198.51.100.128/25 nhid 24 via 192.0.2.1 dev eth1 proto bgp metric 20

Illustrative output

site1 has a connected /24 covering that space and has just installed a /25 on top of it. Longest-prefix match does not care which route is connected and which is learned — the /25 is more specific, so it wins. Traffic originated by site1 for the upper half of its own LAN now goes out the transit link to isp-a.

Prove it from the data plane and keep the capture:

Read-only / Safesite1
$ ip route get 198.51.100.200
198.51.100.200 via 192.0.2.1 dev eth1 src 192.0.2.1 uid 1000
  cache

Illustrative output

Now build the import filter. Four rules, in order, each with a stated job:

configure
set policy prefix-list UPSTREAM-SANE rule 10 action deny
set policy prefix-list UPSTREAM-SANE rule 10 prefix 198.51.100.0/24
set policy prefix-list UPSTREAM-SANE rule 10 le 32
set policy prefix-list UPSTREAM-SANE rule 10 description "never accept our own space back from anyone"
set policy prefix-list UPSTREAM-SANE rule 20 action deny
set policy prefix-list UPSTREAM-SANE rule 20 prefix 0.0.0.0/0
set policy prefix-list UPSTREAM-SANE rule 20 le 7
set policy prefix-list UPSTREAM-SANE rule 20 description "reject absurdly short prefixes"
set policy prefix-list UPSTREAM-SANE rule 30 action deny
set policy prefix-list UPSTREAM-SANE rule 30 prefix 0.0.0.0/0
set policy prefix-list UPSTREAM-SANE rule 30 ge 25
set policy prefix-list UPSTREAM-SANE rule 30 description "reject anything longer than a /24"
set policy prefix-list UPSTREAM-SANE rule 40 action permit
set policy prefix-list UPSTREAM-SANE rule 40 prefix 0.0.0.0/0
set policy prefix-list UPSTREAM-SANE rule 40 le 24
set policy prefix-list UPSTREAM-SANE rule 40 description "accept everything else up to /24"
commit

Before you attach it, walk it. Write the answer for each candidate in your journal before running anything:

Candidate prefixWhich rule matches, and what happens
198.51.100.128/25?
203.0.113.0/25?
203.0.113.128/25?
0.0.0.0/0?

The first is denied by rule 10: the leading 24 bits match 198.51.100.0, and le 32 extends the rule to lengths 24 through 32. The second and third are denied by rule 30, because 0.0.0.0/0 ge 25 matches any prefix of length 25 or more — and that is the trap in this list. Rule 30 does exactly what its description says, and what its description says is wrong for this topology, because both upstreams legitimately originate /25s.

The fourth, 0.0.0.0/0, is denied by rule 20: a length of 0 is within le 7. That is a policy choice, not an accident. A site taking full tables from both upstreams does not want a default route as well, because a default silently repairs any hole your own filters create and makes a missing prefix look like a working one. A site that does want a default from one upstream must permit it explicitly, before rule 20.

That is not an error in the lab. It is the most common way a correctly-written filter causes an outage: a rule that encodes a reasonable industry default (do not accept prefixes longer than /24 from the global table) applied to a link where the default does not hold. Correct it before attaching, and note in your journal that you caught it on paper rather than in production:

set policy prefix-list UPSTREAM-SANE rule 30 ge 26
set policy prefix-list UPSTREAM-SANE rule 30 description "reject anything longer than a /25 - upstreams here originate /25s"
set policy prefix-list UPSTREAM-SANE rule 40 le 25
set policy prefix-list UPSTREAM-SANE rule 40 description "accept everything else up to /25"
commit

Now attach it to both upstream sessions, and take the safety net with you:

set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast prefix-list import UPSTREAM-SANE
set protocols bgp neighbor 192.0.2.6 address-family ipv4-unicast prefix-list import UPSTREAM-SANE
commit-confirm 5

Confirm, then verify that the hijacked /25 is gone from the RIB and from the kernel:

Read-only / Safesite1
$ show ip route 198.51.100.128/25
% Network not in table

Illustrative output

And confirm that the routes you do want survived — this is the check people skip, and it is the one that catches an over-broad deny rule:

Read-only / Safesite1
$ show bgp ipv4 unicast
BGP table version is 9, local router ID is 192.0.2.101, vrf id 0
Default local pref 100, local AS 65001
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
             i internal, r RIB-failure, S Stale, R Removed
Origin codes:  i - IGP, e - EGP, ? - incomplete

 Network          Next Hop            Metric LocPrf Weight Path
*> 198.51.100.0/24  0.0.0.0                  0         32768 i
*> 203.0.113.0/25   192.0.2.1                0             0 65010 i
*> 203.0.113.128/25 192.0.2.5                0             0 65020 i

Displayed 3 routes and 3 total paths

Illustrative output

Task 5: Revise a filter without dropping the session, and bound the damage

Changing an inbound filter raises a question BGP has to answer: the peer already sent its routes, and the ones your old filter rejected are gone. FRR’s default answer is route-refresh (RFC 2918) — ask the peer to send everything again. The capability was negotiated when the session came up; you saw it in Lab 10 as Route refresh: advertised and received.

clear ip bgp 192.0.2.2 in

The session is not reset. No prefixes are withdrawn from anywhere else, no hold timer restarts, and the peer does the work. Confirm the session uptime in show bgp summary did not reset — that is the whole point.

The alternative is soft-reconfiguration inbound, which keeps a local unfiltered copy of everything the peer sent so filters can be re-applied without asking:

configure
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast soft-reconfiguration inbound
commit

It costs roughly a second copy of the peer’s table in memory. In this lab that is three routes; on a session carrying a full table it is hundreds of megabytes, and the course’s guidance is to rely on route-refresh and enable soft-reconfiguration only when the peer does not support it. Enable it here anyway, for one specific reason: it is what makes the pre-filter view available.

Read-only / Safesite1
$ show ip bgp neighbors 192.0.2.2 received-routes
BGP table version is 9, local router ID is 192.0.2.101
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
             i internal, r RIB-failure, S Stale, R Removed
Origin codes:  i - IGP, e - EGP, ? - incomplete

 Network          Next Hop            Metric LocPrf Weight Path
 198.51.100.128/25 192.0.2.1               0             0 65010 i
*> 203.0.113.0/25   192.0.2.1                0             0 65010 i
*> 203.0.113.128/25 192.0.2.1                0             0 65010 65020 i

Total number of prefixes 3

Illustrative output

Compare that against show ip bgp neighbors 192.0.2.2 routes, which is the post-filter view. The difference between the two lists is your filter, expressed as data rather than as configuration. Without soft-reconfiguration, received-routes has nothing to read and FRR says so — that error message is not a broken command, it is the memory bill arriving.

Finally, the backstop. Filters are written by people, and the failure you cannot filter for is the one where your filter is wrong:

configure
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast maximum-prefix 1
commit

One is deliberately below what isp-a legitimately sends after your import filter has run, so the limit fires within seconds. Watch it:

Read-only / Safesite1
$ show bgp neighbor 192.0.2.2
BGP neighbor is 192.0.2.2, remote AS 65010, local AS 65001, external link
BGP state = Idle (PfxCt)
Last reset 00:00:12,   Peer over prefix limit
Maximum prefixes allowed 1

Illustrative output

Idle (PfxCt) is the state to recognise: the session is administratively down because this router decided the peer was sending too much. It stays down until you clear it. Raise the limit to something realistic and bring it back:

configure
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast maximum-prefix 100
commit
clear ip bgp 192.0.2.2

VyOS exposes further sub-options on the same node — a warning-only mode that logs instead of shutting down, a threshold percentage for the early warning, and an automatic restart timer. Check the exact spelling with tab completion on your build before writing any of them into a change record. The lesson on maximum-prefix recommends starting a new session in warning-only mode, watching the real prefix count for a week, and enforcing only once you know what normal looks like.

Task 6: Replace the yes/no filter with one that says why

UPSTREAM-SANE answers one question: accept or reject. That is all a prefix-list can do. The moment you want to treat routes differently based on where they came from — which is Lab 12’s entire subject — you need a mechanism that can attach information as well as make a decision.

Build a route-map that reuses the prefix-list as its match condition and adds a tag:

configure
set policy route-map FROM-ISP-A rule 10 action permit
set policy route-map FROM-ISP-A rule 10 description "accept sane prefixes from isp-a and record the source"
set policy route-map FROM-ISP-A rule 10 match ip address prefix-list UPSTREAM-SANE
set policy route-map FROM-ISP-A rule 10 set community 65001:1010 additive

set policy route-map FROM-ISP-B rule 10 action permit
set policy route-map FROM-ISP-B rule 10 description "accept sane prefixes from isp-b and record the source"
set policy route-map FROM-ISP-B rule 10 match ip address prefix-list UPSTREAM-SANE
set policy route-map FROM-ISP-B rule 10 set community 65001:1020 additive

delete protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast prefix-list import
delete protocols bgp neighbor 192.0.2.6 address-family ipv4-unicast prefix-list import
set protocols bgp neighbor 192.0.2.2 address-family ipv4-unicast route-map import FROM-ISP-A
set protocols bgp neighbor 192.0.2.6 address-family ipv4-unicast route-map import FROM-ISP-B
commit-confirm 5

Confirm, then read the tag back:

Read-only / Safesite1
$ show bgp community 65001:1010
BGP table version is 12, local router ID is 192.0.2.101, vrf id 0
Default local pref 100, local AS 65001
Status codes:  s suppressed, d damped, h history, * valid, > best, = multipath,
             i internal, r RIB-failure, S Stale, R Removed
Origin codes:  i - IGP, e - EGP, ? - incomplete

 Network          Next Hop            Metric LocPrf Weight Path
*> 203.0.113.0/25   192.0.2.1                0             0 65010 i

Displayed 1 routes and 1 total paths

Illustrative output

Three details are worth writing down.

The route-map’s match ip address prefix-list UPSTREAM-SANE reuses the filter rather than duplicating it, so there is exactly one place to change the accepted set. Duplicating the prefix logic into the route-map is the mistake that produces two filters which agree today and diverge in eight months.

additive appends. Without it, set community replaces every community already on the path, silently discarding whatever an upstream attached — including well-known values other routers act on. Use additive unless you have decided to erase, and record that decision.

A route-map is also an allow-list. A path matching no permit rule is denied, exactly as with a prefix-list, so FROM-ISP-A filters and tags in one pass. Attaching both a prefix-list and a route-map to the same neighbour and direction makes the outcome harder to reason about; pick one mechanism per direction and let the route-map do both jobs. That is why the commands above delete the prefix-list attachment rather than leaving it in place.

Validation

  • show ip bgp neighbors 192.0.2.6 advertised-routes on site1 returns exactly one prefix, 198.51.100.0/24.
  • show bgp ipv4 unicast 203.0.113.0/25 on isp-b shows one path, via AS 65010, with no path traversing 65001.
  • show ip route 198.51.100.128/25 on site1 returns % Network not in table, and your journal contains the earlier capture proving it was in the kernel FIB before the filter existed.
  • show bgp ipv4 unicast on site1 shows exactly three prefixes: its own /24 and one /25 from each upstream.
  • Your rule-by-rule walk of UPSTREAM-SANE is written down, including the reason rule 30 had to change from ge 25 to ge 26.
  • show bgp community 65001:1010 and show bgp community 65001:1020 each return the prefixes learned from the corresponding upstream, and neither returns the other’s.
  • show bgp summary on site1 shows both sessions with an uptime longer than the time since your last filter change — proving the filter revisions used route-refresh rather than a session reset.
  • Your community registry exists and has two rows.

Expected Outcome

site1 announces its own allocation and nothing else, to either upstream. It accepts from each upstream only prefixes that are neither its own space, nor absurdly short, nor longer than a /25, and it tags each accepted path with the session that admitted it. A prefix limit is in place on the isp-a session as a backstop for a filter mistake.

isp-a still carries the simulated mis-origination of 198.51.100.128/25. Leave it: Lab 12 uses it, and a filter that is only tested against traffic that was never going to be blocked has not been tested.

Troubleshooting

commit fails referencing a policy that does not exist. VyOS validates references at commit time. Define the prefix-list or route-map in the same commit as the neighbour statement that references it, or in an earlier one — the commands above are ordered that way deliberately.

All routes from an upstream disappear after attaching an import filter. A deny rule matched earlier than you expected, or the permit rule at the end does not cover what you thought. Read the pre-filter list with received-routes (soft-reconfiguration must be on) and compare it against routes. vtysh -c 'show ip prefix-list UPSTREAM-SANE' prints the compiled list with its sequence numbers.

The export filter had no effect. Check the direction keyword. On VyOS 1.4 and 1.5 the words are import and export; in and out belong to FRR’s own CLI and to VyOS 1.3. Also check you attached it to the neighbour you meant — an export filter on the wrong session is invisible until somebody looks at the peer view.

A filter change appears to do nothing. The peer’s routes were sent before the change and the new filter has not been applied to them. Run clear ip bgp <peer> in, substituting the peer address, to trigger a route-refresh.

The session is stuck in Idle (PfxCt). The prefix limit fired. It does not recover on its own unless a restart timer is configured. Raise or remove the limit, then clear ip bgp the peer.

received-routes returns an error rather than a list. Soft-reconfiguration inbound is not enabled on that neighbour. That is the default and usually the right default; enable it deliberately, for as long as you need it.

Cleanup

Nothing here needs restoring for safety — the whole topology is on isolated bridges and management was never touched. The goal is a reproducible starting state.

Step 1. If you are continuing to Lab 12, stop here. Lab 12 begins from exactly this state: three routers, filters in place, communities being set on import, and isp-a still mis-originating 198.51.100.128/25.

Step 2. Otherwise, restore each router to the baseline saved in Task 1:

configure
load /config/pre-lab-11.boot
compare
commit
save

compare before commit shows precisely what the load will change. Note that this returns each router to the unfiltered state — which means the leak comes back. That is the correct baseline for re-running the lab, and a good reminder of what “no policy” actually means.

On isp-a, also remove the simulated mis-origination:

configure
delete interfaces dummy dum1
delete protocols bgp address-family ipv4-unicast network 198.51.100.128/25
commit
save

Step 3. To remove the topology entirely, destroy the three VMs and then the three bridges.

# Run on the Proxmox host, after confirming these IDs with `qm list`.
for VMID in 210 211 212; do
  qm stop "$VMID"
  qm destroy "$VMID" --purge
done

Then remove the vmbr90, vmbr91 and vmbr92 stanzas from /etc/network/interfaces and run ifreload -a.

What You Learned

  • An unfiltered AS offers transit between its upstreams. You watched isp-b learn isp-a’s space through a stub site, and nothing had gone wrong — BGP has no concept of a customer, a peer or an upstream. Those are policy, and policy is the export filter.
  • The rule that does the work in a prefix-list is the one you cannot type. One permit rule stopped the leak because everything else hit the implicit deny. That is why every list needs its intent recorded in a description.
  • An accepted more-specific of your own space breaks your own forwarding. The /25 beat your connected /24 on longest-prefix match and went into the kernel FIB. No log entry, no alarm, and the first symptom is that half your LAN is unreachable from your own router.
  • The right time to find the wrong rule is on paper. Writing the rule-by-rule walk before attaching UPSTREAM-SANE is what caught ge 25 rejecting both upstreams’ legitimate /25s.
  • Route-refresh changes a filter without touching the session. You revised inbound policy repeatedly with no session reset and no withdrawal storm, and you now know what soft-reconfiguration buys and what it costs.
  • A route-map filters and records; a prefix-list only filters. The communities you set here are not decoration. They are the input to every routing decision in Lab 12.

Deliverables

  • · A lab journal with the before/after peer-view captures for the leak
  • · The ONLY-MINE export prefix-list and the UPSTREAM-SANE import prefix-list, with a description on every rule
  • · A written rule-by-rule walk of UPSTREAM-SANE against four candidate prefixes
  • · Evidence that the more-specific of your own space was installed in the kernel FIB before the filter existed
  • · The FROM-ISP-A route-map, with the community it attaches recorded in a one-page community registry

Verification status

Executed end to end
not yet run on hardware

The commands and configuration here have been reviewed against the verified software versions, but nobody has run this lab start to finish on a system meeting its prerequisites. Treat the Expected Outcome as the intended result rather than an observed one, and keep the Cleanup section to hand.