Route Filtering with BGP, EIGRP, OSPF and Static: Three Protocols, Three Different Answers
Route filtering is not one topic. It is three, because distance-vector protocols, link-state protocols, and path-vector protocols expose fundamentally different amounts of control over what they advertise. EIGRP will filter anything, in any direction, on any interface, because it advertises routes and a route not advertised simply does not exist downstream. BGP will filter anything per neighbour per direction, for the same reason. OSPF will filter almost nothing inside an area, because every router in an area must hold an identical link-state database — that is not an implementation limitation but the property that makes SPF produce consistent results.
The consequence catches people repeatedly. distribute-list in configured under OSPF looks like it filters, is accepted without complaint, and does something quite different from what the same command does under EIGRP: it prevents routes from being installed in the local routing table while the LSAs continue to flood normally to every other router. The prefix disappears from show ip route on that router and remains in show ip ospf database everywhere including there. Engineers who learned filtering on EIGRP and apply the same reflex to OSPF produce a router that cannot reach a destination the rest of the network can, which is a black hole for anything transiting it and is invisible from anywhere else.
This article covers where each protocol can filter and what each mechanism actually does. Section one maps the three protocol families onto the control each provides. Section two covers distance-vector filtering, which is the straightforward case. Section three explains why OSPF is different and enumerates the five places it does allow filtering. Section four covers BGP and redistributed statics. Section five is the failure catalogue, dominated by filters that did not filter and filters that black-holed more than intended. Throughout, the recurring question is whether a given command stops propagation or merely stops installation, because those two look identical on the router you configured and completely different everywhere else.
distribute-list in means "do not install this route" under OSPF and "do not accept this route" under EIGRP, and treating those as the same command is the single most productive misunderstanding in route filtering.
Where Can Each Protocol Actually Filter?
What determines the difference?
Whether the protocol advertises routes or advertises topology. EIGRP and RIP advertise routes — a neighbour is told "I can reach this prefix at this metric" — so declining to send one, or declining to accept one, removes it from the downstream view entirely. OSPF advertises link-state information that every router in the area must hold identically in order to compute a consistent shortest-path tree; removing an LSA from one router's database would make its tree disagree with its neighbours', which is exactly the condition link-state routing is designed to prevent. BGP advertises paths per neighbour and has always been a policy protocol, so filtering is a first-class feature in both directions.
A Deeper Dive into the Three Models
The three families compared
| Capability | EIGRP / RIP | OSPF | BGP |
|---|---|---|---|
| Filter inbound from a neighbour | Yes — route never enters the topology table | RIB only — LSDB and flooding unaffected | Yes |
| Filter outbound to a neighbour | Yes | No within an area | Yes |
| Filter at an area or domain boundary | Not applicable | Yes — ABR filter-list, area range | Yes — per neighbour |
| Filter what is redistributed in | Yes | Yes | Yes |
| Suppress by summarisation | Yes — per interface | Yes — at ABR or ASBR | Yes — aggregate-address |
| Block whole route classes | No | Yes — stub and NSSA area types | No |
| Push a filter to the peer | No | No | Yes — ORF |
Why the link-state constraint is not negotiable
SPF computes a tree from a database. If two routers in an area hold different databases, they compute different trees, and two routers with different trees can forward a packet to each other indefinitely. The requirement that every router in an area sees every LSA is therefore the loop-prevention mechanism, not an implementation detail — and any command that appeared to remove an LSA from one router's database while leaving it in another's would be introducing precisely the failure mode the protocol exists to avoid.
That is why OSPF's filtering points are all at boundaries. An ABR sits between two areas and can decide what crosses; an ASBR sits between OSPF and something else and can decide what enters. Within an area there is no boundary and therefore no place to filter. Understanding that as an architectural property rather than a missing feature is what stops the search for a command that would do it.
! Proof that OSPF's distribute-list does not stop flooding
R2(config-router)# distribute-list prefix BLOCK-THIS in
!
! On R2, the route is gone from the RIB
R2# show ip route 10.7.0.0
% Network not in table
!
! But still present in R2's own database...
R2# show ip ospf database | include 10.7.0.0
10.7.0.0 3.3.3.3 412 0x80000004 0x00A2B1
!
! ...and on every other router in the area, unaffected
R5# show ip route 10.7.0.0 | include Known via
Known via "ospf 1", distance 110, metric 30
! ^ R2 filtered itself, and nothing else.
What each filter object can match
| Object | Matches | Used by | Notes |
|---|---|---|---|
| Standard ACL | Network address only | All protocols | Cannot match the mask; avoid |
| Extended ACL | Network and mask as source and destination | Distance-vector, OSPF distribute-list | Awkward syntax; legacy |
| Prefix-list | Prefix and length range | All protocols | The default choice |
| Route-map | Anything, and can set attributes | All protocols | Required where a tag is set |
| AS-path access-list | AS_PATH regular expression | BGP only | Via filter-list or match as-path |
| Community list | BGP communities | BGP only | Standard and expanded forms |
| Route tag | A 32-bit tag on the route | All IGPs | Cross-protocol; survives redistribution |
permit 10.1.0.0 0.0.255.255 matches 10.1.0.0/16 and also 10.1.0.0/24 and 10.1.0.0/30. That ambiguity is a source of filters that pass more than intended. A prefix-list expresses the length explicitly and is readable, and there is no situation in modern configuration where an ACL is the better tool for route filtering. The one exception worth knowing is an extended ACL used with a distribute-list, where the source and destination fields express prefix and mask together — a legacy idiom that still appears in older configurations and is worth recognising rather than writing.How Do I Filter in a Distance-Vector Protocol?
What are the options in EIGRP?
A distribute-list applied inbound or outbound, globally for the address family or scoped to one interface, referencing a prefix-list, an ACL, or a route-map. In named mode these live under topology base for the process-wide form and under af-interface for the per-interface form. Beyond that, summarisation on an interface replaces a set of specifics with one prefix, which is filtering with a replacement, and an offset-list raises a route's metric without removing it, which is filtering by discouragement. A route-map distribute-list additionally allows matching on tag, which is how cross-protocol filtering is expressed.
A Deeper Dive into Distance-Vector Filtering
The four forms
! ===== Named mode: process-wide, both directions =====
ip prefix-list NO-LAB seq 5 deny 10.99.0.0/16 le 32
ip prefix-list NO-LAB seq 10 permit 0.0.0.0/0 le 32
!
router eigrp CORP
address-family ipv4 unicast autonomous-system 100
topology base
distribute-list prefix NO-LAB in
distribute-list prefix NO-LAB out
exit-af-topology
exit-address-family
!
! ===== Named mode: scoped to one interface =====
router eigrp CORP
address-family ipv4 unicast autonomous-system 100
af-interface GigabitEthernet0/2
distribute-list prefix BRANCH-ONLY out
exit-af-interface
exit-address-family
!
! ===== Classic mode =====
router eigrp 100
distribute-list prefix NO-LAB in GigabitEthernet0/1
distribute-list prefix BRANCH-ONLY out GigabitEthernet0/2
Filtering by tag, which crosses protocols
A distribute-list referencing a route-map can match on a route tag, which is what makes a filter portable across a redistribution boundary. A route tagged when it entered EIGRP from OSPF can be excluded from an outbound advertisement toward a particular branch without listing a single prefix, and the filter stays correct as prefixes are added.
! Do not advertise OSPF-sourced routes toward this branch
route-map NO-OSPF-ROUTES deny 10
match tag 110
route-map NO-OSPF-ROUTES permit 20
!
router eigrp CORP
address-family ipv4 unicast autonomous-system 100
af-interface GigabitEthernet0/2
distribute-list route-map NO-OSPF-ROUTES out
exit-af-interface
exit-address-family
!
! Verify from the branch side
R-BRANCH# show ip route eigrp | count ^D EX
Number of lines which match regexp = 0
Summarisation as filtering
Replacing a set of specifics with a summary removes them from the downstream view as thoroughly as a filter does, and adds a route that maintains reachability. Where the requirement is "the branch does not need to see every core subnet", a summary is usually better than a distribute-list: it is one line, it maintains connectivity, and it does not need editing when a new subnet appears inside the summarised range.
! One summary replaces every specific inside it, on this interface
router eigrp CORP
address-family ipv4 unicast autonomous-system 100
af-interface GigabitEthernet0/2
summary-address 10.1.0.0 255.255.0.0
exit-af-interface
exit-address-family
!
! And a default, where even the summary is more than needed
af-interface GigabitEthernet0/3
summary-address 0.0.0.0 0.0.0.0
exit-af-interface
!
! A local discard route appears, which is expected
R1# show ip route 10.1.0.0 255.255.0.0 | include Null0
* directly connected, via Null0
passive-interface, which is filtering at the adjacency layer
Before filtering routes, consider whether the adjacency should exist at all. A passive-interface stops the protocol sending hellos on an interface while still advertising that interface's subnet, which is the correct configuration for every interface facing hosts rather than routers. It removes an entire class of exposure — a rogue device forming an adjacency, a misconfigured neighbour injecting routes — and it does so without any prefix list.
The opt-in form, passive-interface default with explicit exceptions, is stronger still: interfaces peer only where somebody decided they should, and show ip eigrp interfaces becomes an accurate list of intended adjacencies rather than an accident of which subnets a network statement happened to cover.
! Opt-in adjacencies: nothing peers unless named
router eigrp CORP
address-family ipv4 unicast autonomous-system 100
af-interface default
passive-interface
exit-af-interface
af-interface GigabitEthernet0/1
no passive-interface
exit-af-interface
network 10.0.0.0
exit-address-family
!
! The interface list is now a statement of intent
R1# show ip eigrp interfaces
EIGRP-IPv4 VR(CORP) Address-Family Interfaces for AS(100)
Interface Peers Xmit Queue Mean SRTT
Gi0/1 1 0/0 4
! ^ One interface, one peer. Anything else would be a finding.
Offset-list, which discourages rather than removes
! Raise the metric of matched routes instead of dropping them
access-list 10 permit 10.5.0.0 0.0.255.255
!
router eigrp CORP
address-family ipv4 unicast autonomous-system 100
topology base
offset-list 10 in 5120 GigabitEthernet0/1
exit-af-topology
exit-address-family
! ^ Still reachable via this interface, but only if nothing better
! exists. Useful where a filter would black-hole.
show ip route for the unreachable destination returns nothing, and the missing prefix appears in the filter's deny range. Fix: use a summary or a default route instead of a deny, so reachability is preserved while the detail is removed. An outbound deny should be reserved for prefixes that genuinely must not be reachable, not for prefixes that are merely unwanted detail.Why Can't I Filter Inside an OSPF Area?
What can OSPF filter, and where?
Five places, all of them boundaries. At an ABR, area filter-list controls which Type 3 summaries cross into or out of an area, and area range not-advertise suppresses a range of them. At an ASBR, summary-address not-advertise suppresses Type 5 externals, and a route-map on the redistribute statement controls what becomes an external in the first place. And the area types — stub, totally stubby, NSSA, totally NSSA — block whole classes of LSA at the area boundary. Inside an area, between routers in the same area, there is nothing.
A Deeper Dive into OSPF's Filtering Points
Type 3 filtering at an ABR
! Control which summaries enter area 2 from elsewhere
ip prefix-list AREA2-IN seq 5 permit 10.0.0.0/8 le 24
ip prefix-list AREA2-IN seq 10 deny 0.0.0.0/0 le 32
!
router ospf 1
area 2 filter-list prefix AREA2-IN in
! 'in' = into area 2. 'out' = out of area 2 into others.
!
! Verify on a router inside area 2
R6# show ip route ospf | count ^O IA
Number of lines which match regexp = 12
! ^ Down from the full inter-area set. This is real filtering:
! the Type 3 LSAs are not generated into the area at all.
Suppressing a range with area range
! Summarise on the way out of area 1
router ospf 1
area 1 range 10.1.0.0 255.255.0.0
!
! Or suppress it entirely
router ospf 1
area 1 range 10.1.99.0 255.255.255.0 not-advertise
! ^ No Type 3 is generated for anything inside this range.
!
! Confirm the summary and the suppression
R1# show ip ospf | begin Area 1
Area 1
Area ranges are
10.1.0.0/16 Active(2) Advertise
10.1.99.0/24 Passive DoNotAdvertise
Suppressing externals at an ASBR
! Summarise redistributed externals
router ospf 1
summary-address 172.16.0.0 255.255.0.0
!
! Or suppress a range of them completely
router ospf 1
summary-address 172.16.99.0 255.255.255.0 not-advertise
!
! Better still, never create them - filter the redistribution
route-map INTO-OSPF permit 10
match ip address prefix-list SHARE-THESE
set tag 90
!
router ospf 1
redistribute eigrp 100 subnets route-map INTO-OSPF
! ^ The cleanest option: the LSA is never generated.
The direction keyword on area filter-list
The in and out keywords are relative to the area named in the command, not to the router. area 2 filter-list prefix X in filters Type 3 LSAs being generated into area 2 from every other area; out filters those being generated out of area 2 into the rest of the domain. Getting this backwards produces a filter that is syntactically valid, applies to the opposite set of prefixes, and appears to do nothing because the prefixes it names do not travel in that direction.
Both directions can be configured on the same area, and on a router that is an ABR for several areas each area needs its own statement. A filter applied to one area does not affect what crosses at another ABR, so an area with two ABRs needs the identical filter on both — the same partial-deployment problem that affects redistribution tags.
area filter-list applied on only one of two ABRs Symptom: a filter intended to keep a set of prefixes out of an area works when traffic and LSAs flow through one ABR and stops working after a failure moves them to the other, so the prefixes appear intermittently and correlate with nothing obvious. Cause: the filter was configured on one ABR only; the second continues generating the Type 3 LSAs into the area normally. Confirm: show ip ospf database summary on a router inside the area shows the prefixes with the second ABR as advertising router; show running-config | include filter-list on both ABRs shows only one. Fix: apply the identical filter-list on every ABR serving the area, and audit for it whenever an ABR is added or rebuilt.Area types, which block classes rather than prefixes
| Area type | Blocks | Configured on | Effect on the area's database |
|---|---|---|---|
| Stub | Type 4 and Type 5 | Every router in the area | No externals; a default arrives instead |
| Totally stubby | Type 3, 4 and 5 | no-summary on the ABR |
Only intra-area plus a default |
| NSSA | Type 4 and Type 5 | Every router in the area | No external imports; Type 7 permitted locally |
| Totally NSSA | Type 3, 4 and 5 | no-summary on the ABR |
Smallest database that still allows a local ASBR |
! The largest database reduction available, in two commands
! On the ABR:
router ospf 1
area 2 stub no-summary
!
! On every internal router in area 2:
router ospf 1
area 2 stub
!
! Measure the effect
R6# show ip ospf database database-summary | include Total|Summary
Summary Net 1 0 0
Total 6 0 0
! ^ One Type 3, the default. Down from hundreds.
What distribute-list in actually does
It prevents routes from being installed in the local routing table. The LSAs are received, stored in the local LSDB, flooded onward normally, and used by SPF; only the resulting RIB entry is suppressed. There are legitimate uses — preventing a specific router from using a path while leaving the rest of the area unaffected — and they are narrow. Using it as a general filter produces a router with a routing table that disagrees with its own database and with every neighbour.
! Legitimate use: this router specifically must not use this path
ip prefix-list NOT-VIA-ME seq 5 deny 10.7.0.0/16
ip prefix-list NOT-VIA-ME seq 10 permit 0.0.0.0/0 le 32
!
router ospf 1
distribute-list prefix NOT-VIA-ME in
!
! The consequence, stated plainly
R2# show ip route 10.7.0.0
% Network not in table
R2# show ip ospf database | include 10.7.0.0
10.7.0.0 3.3.3.3 412 0x80000004 0x00A2B1
! ^ R2 cannot reach it. Every other router in the area can.
! If that is not what you wanted, this is the wrong command.
distribute-list in to filter an OSPF area Symptom: a filter is applied to stop a set of prefixes propagating into part of the network; the router it was applied to no longer has them, and every other router in the area still does. Traffic that transits the filtered router is black-holed while traffic taking any other path works. Cause: under OSPF, distribute-list in filters RIB installation only. LSA flooding, and therefore every other router's view, is unaffected. Confirm: show ip route <prefix> is empty on the filtered router while show ip ospf database contains it there and everywhere. Fix: filter at a boundary instead — area filter-list at an ABR, a route-map on redistribution at an ASBR, or an area type that blocks the class. If the requirement genuinely is per-router, understand that you are creating a router whose forwarding disagrees with the area.How Do I Filter BGP and Redistributed Static Routes?
What is different about these two?
BGP is the most filterable of the protocols: four mechanisms per neighbour per direction per address family, plus ORF to push a filter to the peer, plus the structural fact that only the best path is ever advertised. Static routes have no protocol to filter at all — the filtering point is the redistribution that injects them into whatever protocol is going to carry them, which makes a route-map on the redistribute static statement the only control available and therefore the one that matters.
A Deeper Dive into BGP and Static Filtering
Why BGP is the easiest of the three
BGP was designed on the assumption that the operator does not trust the peer and the peer does not trust the operator, so every advertisement is subject to policy in both directions by default. That produces the richest filtering model of the three protocol families and one structural bonus: because BGP advertises only its best path, an inbound filter that rejects a path also removes it from consideration for everything downstream, and an outbound filter is the last word on what leaves.
The cost of that richness is that four mechanisms can apply in one direction and all of them must permit a prefix. A prefix rejected by a prefix-list never reaches the route-map, so reading the route-map alone will never explain its absence — which is why the recommendation elsewhere is one mechanism per direction, with everything else referenced from inside it.
BGP, briefly, in this context
! Four mechanisms, per neighbour, per direction, per family.
! All configured ones must permit a prefix for it to pass.
router bgp 65000
address-family ipv4 unicast
neighbor 192.0.2.2 prefix-list CUST-A-PFX in
neighbor 192.0.2.2 filter-list 10 in
neighbor 192.0.2.2 route-map CUST-A-IN in
neighbor 192.0.2.6 route-map TRANSIT-OUT out
exit-address-family
!
! And the change takes effect only after a refresh
R1# clear ip bgp 192.0.2.2 soft
!
! Verify by counting, on both sides of the policy
R1# show ip bgp neighbors 192.0.2.2 routes | include Total
R1# show ip bgp neighbors 192.0.2.6 advertised-routes | include Total
Static routes: tag at creation, filter at redistribution
A router accumulates static routes for several unrelated purposes — a Null0 discard supporting a summary, a management route, a temporary route added during an incident, a genuine reachability entry that should propagate. redistribute static with no filter carries all of them. Tagging each static at the moment it is created, with a value describing its purpose, turns the redistribution filter into a one-line match that stays correct as statics come and go.
! Tag statics by purpose, at creation
ip route 10.9.0.0 255.255.0.0 10.0.0.9 tag 500 ! propagate
ip route 172.16.0.0 255.240.0.0 Null0 tag 900 ! discard, never propagate
ip route 192.168.99.0 255.255.255.0 10.0.0.1 tag 800 ! management only
!
! One filter, correct for every static ever added
route-map STATIC-OUT permit 10
match tag 500
set tag 1
! implicit deny excludes 900 and 800 automatically
!
router ospf 1
redistribute static subnets route-map STATIC-OUT
!
router eigrp CORP
address-family ipv4 unicast autonomous-system 100
topology base
redistribute static metric 1000000 100 255 1 1500 route-map STATIC-OUT
exit-af-topology
exit-address-family
Filtering connected interfaces
redistribute connected has the same problem in a sharper form: every interface on the router, including management interfaces, out-of-band links, and loopbacks used for protocol identifiers, is carried unless filtered. A prefix-list naming the ranges that should propagate is the minimum, and matching on interface is available where the addressing does not partition cleanly.
! By prefix range - the usual approach
ip prefix-list SHARE-CONN seq 5 permit 10.1.0.0/16 le 30
!
route-map CONN-OUT permit 10
match ip address prefix-list SHARE-CONN
!
! Or by interface, where addressing does not partition cleanly
route-map CONN-OUT-2 permit 10
match interface GigabitEthernet0/1 GigabitEthernet0/2
!
router ospf 1
redistribute connected subnets route-map CONN-OUT
!
! Verify the management interface did not propagate
R5# show ip route 192.168.99.0
% Network not in table
Choosing the filtering point
| Requirement | Best filtering point | Why |
|---|---|---|
| A branch should not see core detail | Summary or default on the branch-facing interface | Reduces detail while preserving reachability |
| A prefix must not be reachable from a domain | Deny at the redistribution or the area boundary | Stops it existing there at all |
| Externals must not enter an area | Stub or NSSA area type | Blocks the class, not a list |
| A specific Type 3 must not cross | area filter-list at the ABR |
The only Type 3 control point |
| Only some statics should propagate | Tag at creation, match at redistribution | Stays correct as statics change |
| A peer should stop sending prefixes | BGP inbound filter, or ORF | ORF also saves the transfer |
| Redistributed routes must not return | Tag on export, deny on import | Prefix-independent |
Which Filtering Mistakes Cause Black Holes?
What goes wrong?
Six things. An OSPF distribute-list in used as a propagation filter produces one router that disagrees with its area. An outbound deny that removes the only path to a destination black-holes it rather than merely hiding it. A prefix-list with an inverted ge or le matches nothing or everything. A filter applied without the implicit-deny in mind rejects far more than intended. A BGP filter applied without a soft reset governs only new prefixes. And a filter that removes a next hop breaks routes that recursively depended on it, which is invisible in the filter itself.
A Deeper Dive into the Failure Catalogue
Auditing filters that outlived their requirement
Filters accumulate. A prefix-list added for a migration that finished, a distribute-list from an incident three years ago, an area filter-list nobody can attribute — each was correct once and each now constrains the network for reasons nobody can state. The audit is mechanical: list every filter object, find where each is referenced, and for any with no reference remove it. For the ones that are referenced, the harder question is whether the requirement still exists, which only documentation can answer.
! Every filter object defined on the device
R1# show running-config | include ^ip prefix-list|^route-map|^ip as-path
!
! Which are actually referenced anywhere?
R1# show ip prefix-list detail | include ^ip prefix-list|refcount
ip prefix-list OLD-MIGRATION:
count: 4, range entries: 0, sequences: 5 - 20, refcount: 0
! ^ refcount 0 = defined and used nowhere. Safe to remove.
!
! Where every filter is applied, by protocol
R1# show running-config | include distribute-list|filter-list|prefix-list .* in|out
R1# show running-config | include area .* filter-list|summary-address|area .* range
The recursive next-hop failure
A route whose next hop is not directly connected requires a second lookup to resolve. Filtering the prefix that provides that resolution removes the first route as well, even though it was never mentioned in the filter. This is most common with BGP next hops learned from an IGP, and with static routes pointing at addresses several hops away.
! The filter removes 10.0.0.0/24 - apparently unrelated
ip prefix-list TIDY seq 5 deny 10.0.0.0/24
ip prefix-list TIDY seq 10 permit 0.0.0.0/0 le 32
!
! But a BGP path's next hop lives in that range
R3# show ip bgp 203.0.113.0/24 | include from
10.0.0.1 (inaccessible) from 10.0.0.9 (10.0.0.9)
! ^ The BGP prefix is now unusable because its next hop cannot
! be resolved. Nothing in the filter mentions 203.0.113.0.
!
! Check what depends on a prefix before filtering it
R3# show ip bgp | include 10.0.0.1
R3# show ip route 10.0.0.1
The implicit deny, again
! WRONG - a prefix-list with only deny entries permits nothing
ip prefix-list BLOCK-LAB seq 5 deny 10.99.0.0/16 le 32
!
R2# show ip route eigrp | count ^D
Number of lines which match regexp = 0
! ^ Everything filtered. The implicit deny caught the rest.
!
! RIGHT
ip prefix-list BLOCK-LAB seq 5 deny 10.99.0.0/16 le 32
ip prefix-list BLOCK-LAB seq 10 permit 0.0.0.0/0 le 32
!
! Same rule for route-maps used as distribute-lists
route-map FILTER deny 10
match tag 110
route-map FILTER permit 20
! ^ Without clause 20, nothing is advertised at all.
Writing a filter that can be reviewed
A filter's correctness is judged by somebody who was not there when it was written, usually during an incident. Three habits make that possible. Name the object after what it permits rather than where it is used, so CUSTOMER-BLOCKS survives being applied somewhere new while GI0-1-IN does not. Number entries in tens so an insertion does not require renumbering the whole list. And write the trailing permit or deny explicitly even where the implicit one would do the same thing, because an explicit final line is evidence that the author considered the case.
The fourth habit is a comment in configuration management naming the requirement the filter implements. A prefix-list with no stated purpose is a prefix-list nobody will remove even when the requirement has gone, which is how a network accumulates filters that nobody can justify and nobody dares delete.
! Named for content, numbered in tens, explicit final line
ip prefix-list CUSTOMER-BLOCKS seq 10 permit 203.0.113.0/24
ip prefix-list CUSTOMER-BLOCKS seq 20 permit 198.51.100.0/22 le 24
ip prefix-list CUSTOMER-BLOCKS seq 30 deny 0.0.0.0/0 le 32
! ^ The deny is redundant and states the intent anyway.
!
! Find every place an object is used, before changing it
R1# show running-config | include CUSTOMER-BLOCKS
neighbor 192.0.2.2 prefix-list CUSTOMER-BLOCKS in
match ip address prefix-list CUSTOMER-BLOCKS
!
! And read it back with its entry counts
R1# show ip prefix-list detail CUSTOMER-BLOCKS
ip prefix-list CUSTOMER-BLOCKS:
count: 3, range entries: 1, sequences: 10 - 30, refcount: 3
seq 10 permit 203.0.113.0/24 (hit count: 1, refcount: 1)
! ^ refcount 3 means three places reference this list. Changing it
! affects all three.
Verification per protocol
! EIGRP: did the route stop being advertised?
R1# show ip eigrp topology 10.99.0.0/16
! (absent = the inbound filter worked)
R-NEIGH# show ip route 10.99.0.0
! (absent = the outbound filter worked)
!
! OSPF: is the LSA gone, or just the RIB entry?
R2# show ip route 10.7.0.0 ! RIB
R2# show ip ospf database | include 10.7.0.0 ! LSDB
! Absent from BOTH = a real boundary filter.
! Absent from the RIB only = distribute-list in. Probably wrong.
!
! BGP: compare pre-policy and post-policy
R1# show ip bgp neighbors 192.0.2.2 received-routes | include Total
R1# show ip bgp neighbors 192.0.2.2 routes | include Total
!
! Any protocol: did anything become unreachable that should not have?
R5# ping 10.5.0.1 source Loopback0
R5# traceroute 10.5.0.1
| Mistake | Symptom | Confirming command | Fix |
|---|---|---|---|
OSPF distribute-list in as a filter |
One router disagrees with its area | RIB empty, LSDB populated | Filter at an ABR, ASBR, or by area type |
| Outbound deny removes the only path | Black hole for that destination | show ip route empty downstream |
Summary or default instead of deny |
| Missing trailing permit | Everything filtered | Route count drops to zero | Add permit 0.0.0.0/0 le 32 |
Inverted ge/le |
Matches nothing or everything | show ip prefix-list |
Both must exceed the stated length |
| Recursive next hop filtered | Unrelated prefixes become unusable | BGP path shows inaccessible |
Permit the next-hop range explicitly |
| BGP filter without a refresh | Applies only to new prefixes | Prefix count unchanged | clear ip bgp X soft |
| Standard ACL instead of prefix-list | Matches more than intended | Compare against the mask | Use a prefix-list |
Conclusion
Filtering is three different problems because the protocols advertise three different things. A distance-vector protocol advertises routes, so withholding one removes it from the downstream view completely and filtering is available everywhere. A path-vector protocol advertises paths per neighbour and was designed around policy, so filtering is a first-class feature with four mechanisms and a way to push your filter to the peer. A link-state protocol advertises topology that every router in an area must hold identically, so there is no place inside an area to filter and all the control lives at boundaries.
The OSPF case deserves the emphasis because the command that looks like a filter is not one. distribute-list in stops the local router installing a route while the LSA continues to flood everywhere, including to that router's own database. Used deliberately, on one router, for a narrow reason, that is a legitimate tool. Used as a general filter, it produces a router whose forwarding disagrees with its area, which is a black hole for anything that transits it and is invisible from every other router.
The practical rule that covers most requirements is to reduce rather than remove. A branch that does not need core detail wants a summary or a default, not a deny — both remove the detail and only one preserves reachability. Where a deny is genuinely required, filter as close to the source as possible so the route never exists downstream, and check what depends on the prefix before removing it, because a recursive next hop is the dependency nobody looks for and the one that turns a tidy-up into an outage.
External Links Recommendations
- RFC 2328 — OSPF Version 2: Section 13 establishes that all routers in an area must have identical link-state databases, which is why filtering within an area is not possible.
- RFC 7868 — Cisco's Enhanced Interior Gateway Routing Protocol (EIGRP): the update model that makes route filtering possible on any interface.
- Cisco — What Are OSPF Areas and Virtual Links?: area types and the LSA classes each one blocks.
- Cisco — Redistributing Routing Protocols: filtering at redistribution points and the use of route tags.
- Cisco — BGP Case Studies: prefix-list, filter-list, and route-map filtering per neighbour.
- Cisco IOS-XE IP Routing Protocol-Independent Configuration Guide: current
distribute-list, prefix-list, and route-map syntax. - Cisco Learning Network — CCIE Enterprise Infrastructure: current blueprint and lab equipment list.
Reference Notes
- RFC 2328, Section 13 — the flooding procedure, which requires every router in an area to receive and store every LSA originated within it.
- RFC 2328, Section 16 — the SPF calculation operates on the link-state database, so a router with a different database computes a different tree.
- RFC 2328, Section 12.4.3 — summary-LSAs are originated by area border routers, which is why the ABR is the only Type 3 filtering point.
- RFC 2328, Section 3.6 — stub areas, in which Type 5 LSAs are not flooded, blocking a whole class rather than individual prefixes.
- RFC 3101 — the NSSA option and Type 7 LSAs, permitting a local ASBR within an otherwise stub-like area.
- RFC 7868, Section 4 — EIGRP's reliable update mechanism advertises routes rather than topology, which permits filtering at any interface.
- Cisco IOS-XE IP Routing Configuration Guide —
distribute-list inunder OSPF filters routes from installation in the routing table and does not affect LSA flooding. - Cisco IOS-XE IP Routing Configuration Guide —
area filter-list prefixfilters Type 3 summary LSAs into or out of an area at an ABR. - Cisco IOS-XE IP Routing Configuration Guide —
area range not-advertiseandsummary-address not-advertisesuppress Type 3 and Type 5 LSAs respectively. - Cisco IOS-XE EIGRP Configuration Guide —
distribute-listundertopology basefor process-wide filtering and underaf-interfacefor per-interface filtering. - Cisco IOS-XE IP Routing Configuration Guide — prefix-list
geandlevalues must both exceed the specified prefix length. - Cisco IOS-XE IP Routing Configuration Guide —
match interfaceandmatch tagas route-map conditions for filtering connected and static redistribution.