Import policy
Right now R1 accepts anything its neighbors send. That's how real outages happen: a neighbor leaks a private range, a hijacked prefix, your own prefix back to you, or a full table onto a session that should carry a hundred routes. Import policy has four jobs:
- Drop bogons. Private, reserved and multicast space should never appear in global BGP. The
BOGONSprefix list matches each range and everything inside it (le 32), so a /24 out of 10.0.0.0/8 is caught too. - Drop your own prefixes. Nobody else should ever announce 198.51.100.0/24 or any part of it to you. If they do, it's a leak or a hijack, and accepting it could pull your own traffic away.
OUR-PREFIXES-ANYmatches the /24 and anything more specific. - Prefer the IX. Everything that survives gets a Local Preference (LOCAL_PREF): 150 from the IX, 100 from transit. Higher wins, so if a member's prefix arrives both ways, R1 uses the cheap, direct IX path. (Local preference is the second step of best-path selection, straight after weight; see the BGP fundamentals lesson.)
- Cap the prefix count.
maximum-prefixtears the session down if a neighbor sends more than the limit. Set it comfortably above what you expect: here a default plus a few routes from transit, and a handful from the IX. With a full table from transit, you'd use something like 1,100,000.
A route-map stops at the first rule that matches, so the order matters: the two deny rules come before the final permit.
What the production config had that this lab doesn't
- TCP-MD5 passwords (
neighbor … password). Almost every provider and IX requires them. VyOS supports them, but the FRR containers playing the upstream couldn't: Docker Desktop's kernel lacks TCP-MD5 support, so FRR refused the setting. On real hardware, add the password your provider gives you. Both sides must match exactly, or the session never comes up. - A "too specific" rule. Real bogon lists usually end with
0.0.0.0/0 ge 25, which drops anything longer than /24: the internet's agreed minimum size for a globally routed IPv4 prefix. This lab uses /25 and /26 prefixes to stand in for "the internet", so that rule had to go. Keep it in production. - The documentation ranges. 192.0.2.0/24, 198.51.100.0/24 and 203.0.113.0/24 belong in a production bogon list too. This lesson uses them as if they were real address space, so they can't be filtered here.
- More bogons. A complete list also covers 192.0.0.0/24, 198.18.0.0/15 and the other ranges in the IANA special-purpose registry, plus bogon ASNs (private and reserved AS numbers in the path). RPKI Route Origin Validation (ROV) is the next layer; see the RPKI lesson.
set policy prefix-list BOGONS rule 10 action 'permit'
set policy prefix-list BOGONS rule 10 prefix '0.0.0.0/8'
set policy prefix-list BOGONS rule 10 le '32'
set policy prefix-list BOGONS rule 20 action 'permit'
set policy prefix-list BOGONS rule 20 prefix '10.0.0.0/8'
set policy prefix-list BOGONS rule 20 le '32'
set policy prefix-list BOGONS rule 30 action 'permit'
set policy prefix-list BOGONS rule 30 prefix '100.64.0.0/10'
set policy prefix-list BOGONS rule 30 le '32'
set policy prefix-list BOGONS rule 40 action 'permit'
set policy prefix-list BOGONS rule 40 prefix '127.0.0.0/8'
set policy prefix-list BOGONS rule 40 le '32'
set policy prefix-list BOGONS rule 50 action 'permit'
set policy prefix-list BOGONS rule 50 prefix '169.254.0.0/16'
set policy prefix-list BOGONS rule 50 le '32'
set policy prefix-list BOGONS rule 60 action 'permit'
set policy prefix-list BOGONS rule 60 prefix '172.16.0.0/12'
set policy prefix-list BOGONS rule 60 le '32'
set policy prefix-list BOGONS rule 70 action 'permit'
set policy prefix-list BOGONS rule 70 prefix '192.168.0.0/16'
set policy prefix-list BOGONS rule 70 le '32'
set policy prefix-list BOGONS rule 80 action 'permit'
set policy prefix-list BOGONS rule 80 prefix '224.0.0.0/3'
set policy prefix-list BOGONS rule 80 le '32'
set policy prefix-list OUR-PREFIXES-ANY rule 10 action 'permit'
set policy prefix-list OUR-PREFIXES-ANY rule 10 prefix '198.51.100.0/24'
set policy prefix-list OUR-PREFIXES-ANY rule 10 le '32'
set policy route-map TRANSIT-IN rule 10 action 'deny'
set policy route-map TRANSIT-IN rule 10 match ip address prefix-list 'BOGONS'
set policy route-map TRANSIT-IN rule 20 action 'deny'
set policy route-map TRANSIT-IN rule 20 match ip address prefix-list 'OUR-PREFIXES-ANY'
set policy route-map TRANSIT-IN rule 30 action 'permit'
set policy route-map TRANSIT-IN rule 30 set local-preference '100'
set policy route-map IX-IN rule 10 action 'deny'
set policy route-map IX-IN rule 10 match ip address prefix-list 'BOGONS'
set policy route-map IX-IN rule 20 action 'deny'
set policy route-map IX-IN rule 20 match ip address prefix-list 'OUR-PREFIXES-ANY'
set policy route-map IX-IN rule 30 action 'permit'
set policy route-map IX-IN rule 30 set local-preference '150'
set protocols bgp neighbor 203.0.113.0 address-family ipv4-unicast route-map import 'TRANSIT-IN'
set protocols bgp neighbor 203.0.113.0 address-family ipv4-unicast maximum-prefix '1000'
set protocols bgp neighbor 192.0.2.1 address-family ipv4-unicast route-map import 'IX-IN'
set protocols bgp neighbor 192.0.2.1 address-family ipv4-unicast maximum-prefix '100'- Lines 1–24: Each bogon range with
le 32: the range itself and anything more specific inside it. - Lines 25–27: Our /24 and anything inside it. Different from OUR-PREFIXES (exact match), which is what we announce.
- Lines 28–33: Transit import: drop bogons, drop our own space, accept the rest at local preference 100.
- Lines 34–39: IX import: the same filters, but local preference 150 so IX paths beat transit.
- Lines 40–43: Apply the import maps and prefix limits to each neighbor.
# FRR on the upstream, when its config contained "password CHANGE-ME":
% Error while applying TCP-Sig to session(s)
line 25: Failure to communicate[13] to bgpd, line: neighbor 203.0.113.1 password CHANGE-ME- Lines 2–3: Docker Desktop's kernel can't do TCP-MD5, so FRR refused the password. On real routers, configure the provider's password on both ends.
vyos@R1:~$ show ip bgp
BGP table version is 16, local router ID is 198.51.100.1, vrf id 0
Default local pref 100, local AS 64500
Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 0.0.0.0/0 203.0.113.0 0 100 0 64496 i
*> 198.51.100.0/24 0.0.0.0 0 32768 i
*> 203.0.113.64/26 192.0.2.40 0 150 0 64502 i
*> 203.0.113.128/25 203.0.113.0 0 100 0 64496 i
Displayed 4 routes and 4 total paths
vyos@R1:~$ show ip bgp neighbors 192.0.2.1 received-routes
BGP table version is 16, local router ID is 198.51.100.1, vrf id 0
Default local pref 100, local AS 64500
Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 10.99.0.0/16 192.0.2.40 0 0 64502 i
*> 198.51.100.0/24 192.0.2.25 0 0 64500 i
*> 203.0.113.64/26 192.0.2.40 0 0 64502 i
Total number of prefixes 3 (2 filtered)
vyos@R1:~$ show ip bgp neighbors 192.0.2.1 routes
BGP table version is 16, local router ID is 198.51.100.1, vrf id 0
Default local pref 100, local AS 64500
Status codes: s suppressed, d damped, h history, u unsorted, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
Network Next Hop Metric LocPrf Weight Path
*> 203.0.113.64/26 192.0.2.40 0 150 0 64502 i
Displayed 1 routes and 4 total paths
vyos@R1:~$ show bgp ipv4 203.0.113.64/26
BGP routing table entry for 203.0.113.64/26, version 15
Paths: (1 available, best #1, table default)
Not advertised to any peer
64502
192.0.2.40 from 192.0.2.1 (192.0.2.1)
Origin IGP, metric 0, localpref 150, valid, external, best (First path received)
Last update: Fri Oct 16 22:26:10 2026
vyos@R1:~$ show ip route 203.0.113.64/26
Routing entry for 203.0.113.64/26
Known via "bgp", distance 20, metric 0, best
Last update 00:00:15 ago
Flags: Selected
Status: Installed
* 192.0.2.40, via eth1, weight 1- Line 11: Transit routes now carry local preference 100…
- Line 13: …and the IX route 150. The bogon is gone from the table.
- Lines 27–29:
received-routesstill shows everything the route server sent, thanks to soft-reconfiguration… - Line 31: …and counts how many were filtered: the bogon and our own prefix.
- Line 42:
routesshows only what was accepted. - Lines 50–51: Next hop 192.0.2.40, learned from the route server 192.0.2.1.
- Line 59: Installed in the routing table, out eth1 to the member.
Check your understanding
Why does the IX import map deny OUR-PREFIXES-ANY rather than OUR-PREFIXES?
- They're the same list
- So that a more specific route inside our /24, such as a hijacked /25, is also rejected
- Because route-maps can only match lists with le
- To stop us announcing our own prefix to the IX
Check your understanding
Real bogon lists include 0.0.0.0/0 ge 25. What does that rule catch?
- The default route
- Any IPv4 prefix longer than /24, which isn't globally routable by convention
- Only private ranges
- Multicast