Latest Cisco, PMP, AWS, CompTIA, Microsoft Materials on SALE Get Now Get Now

BGP Routing Policies: The Tooling, the Sharp Edges, and the Filter Everyone Forgets

A BGP router with no policy will accept everything a neighbour sends and re-advertise everything it knows. That is the default behaviour that produced every large route leak of the last two decades, and it is why RFC 8212 now specifies that an eBGP session should exchange nothing until an operator has explicitly said what to exchange. Policy in BGP is not an optimisation applied after the protocol works. It is the mechanism that decides what the protocol does at all, and a session without it is a session whose behaviour was chosen by whoever is on the other end.

The tooling is small and the semantics are precise. Four filter mechanisms attach to a neighbour in each direction — prefix-list, filter-list for AS paths, distribute-list, and route-map — and a prefix must pass every one that is configured. Route-maps are the general instrument: an ordered sequence of numbered clauses, each either permit or deny, each with zero or more match conditions and zero or more set actions, terminated by an implicit deny that catches everything no clause matched. Prefix-lists match address ranges with ge and le qualifiers whose meanings are easy to invert. AS-path access-lists use regular expressions where the underscore is a delimiter class rather than a literal character. Community-lists come in standard and expanded forms with different matching semantics.

This article covers the whole toolkit and the reasoning behind each choice. Section one maps the tools onto the places they attach and explains what happens when several apply at once. Section two dissects route-map processing — clause order, permit versus deny, the implicit deny, and continue. Section three covers precise matching: prefix-list ge/le, AS-path regular expressions, and the two kinds of community list. Section four covers what policy can change and which best-path step each change affects. Section five is the failure catalogue, starting with the route leak that an outbound filter would have prevented.

Blog ClaimEvery large BGP route leak has the same root cause — an outbound policy that permitted more than it was meant to — which makes the outbound filter, not the inbound one, the configuration that protects everybody other than yourself.
Policy attaches per neighbour and per direction, multiple filters are ANDed, and a route-map is an ordered list whose first matching clause decides — with an implicit deny catching everything else.

What Are the Policy Tools and Where Does Each Apply?

Which mechanism should I use for which job?

Use a prefix-list when the decision is purely about address ranges, because it is fast, readable, and expresses length constraints directly. Use a filter-list when the decision is about AS path, since it takes an AS-path access-list and nothing else does. Use a route-map when the decision involves more than one criterion, or when you need to change an attribute rather than only permit or deny. Distribute-lists are the legacy mechanism and offer nothing a prefix-list does not, aside from extended access-list matching on prefix and mask together. All of them attach to a neighbour under a specific address family, in a specific direction, and every one configured in that direction must permit a prefix for it to pass.

A Deeper Dive into the Attachment Model

The four mechanisms side by side

Mechanism Matches on Can modify attributes Command Best used for
Prefix-list Prefix and length No neighbor X prefix-list NAME in|out Clean address-range filtering
Filter-list AS_PATH regular expression No neighbor X filter-list NAME in|out Accepting or rejecting by origin or transit AS
Distribute-list Standard or extended ACL No neighbor X distribute-list NAME in|out Legacy; extended ACL can match prefix plus mask
Route-map Anything, including several criteria together Yes neighbor X route-map NAME in|out Combined matching, and any attribute change
Table-map Applied on RIB installation Limited — traffic-index, local policy table-map NAME Marking routes as they enter the RIB
ORF Prefix-list pushed to the peer No neighbor X capability orf prefix-list send Making the peer filter on your behalf

Policy attaches per address family

A route-map applied under address-family ipv4 unicast has no effect on VPNv4 or IPv6 prefixes from the same neighbour. This is easy to miss when a neighbour is activated in several families, and the symptom is policy that works for one family and silently does nothing for another. Every filter statement must be repeated in every family where it should apply.

! One neighbour, three families, three separate policy attachments
router bgp 65000
 neighbor 192.0.2.2 remote-as 65001
 !
 address-family ipv4 unicast
  neighbor 192.0.2.2 activate
  neighbor 192.0.2.2 route-map CUST-IN in
  neighbor 192.0.2.2 prefix-list CUST-PFX in
  neighbor 192.0.2.2 route-map CUST-OUT out
 exit-address-family
 !
 address-family ipv6 unicast
  neighbor 192.0.2.2 activate
  ! Separate policy required - the IPv4 maps do not apply here
  neighbor 192.0.2.2 route-map CUST-IN-V6 in
  neighbor 192.0.2.2 route-map CUST-OUT-V6 out
 exit-address-family

Multiple filters in one direction are ANDed

Configuring a prefix-list and a route-map inbound on the same neighbour means a prefix must be permitted by both. That is occasionally useful — a coarse prefix-list plus a route-map that sets attributes — and frequently confusing, because a prefix denied by the prefix-list never reaches the route-map and no amount of reading the route-map explains why. Using one mechanism per direction removes the ambiguity entirely, and a route-map can express anything the others can.

! Both must permit. A prefix rejected by the list never sees the map.
 neighbor 192.0.2.2 prefix-list ALLOWED in
 neighbor 192.0.2.2 route-map SET-ATTRS in
!
! Cleaner: one route-map that does both jobs
ip prefix-list ALLOWED seq 5 permit 203.0.113.0/24
!
route-map CUST-IN permit 10
 match ip address prefix-list ALLOWED
 set local-preference 200
 set community 65000:1000 additive
! implicit deny 65535 rejects everything else
!
router bgp 65000
 address-family ipv4 unicast
  neighbor 192.0.2.2 route-map CUST-IN in

Reusing policy across many neighbours

A network with fifty customer sessions does not want fifty copies of the same policy. Peer templates solve this in two layers: a session template carries the transport-level settings — remote AS, source interface, timers, password — while a policy template carries the address-family settings including route-maps and prefix-lists. A neighbour inherits one of each, and templates can inherit from other templates, so a base customer policy can be specialised for a particular class of customer without duplication.

Peer-groups are the older mechanism and do both jobs at once. They remain widely deployed and have one operational advantage: members share an update group, so an advertisement is formatted once and sent to all of them, which matters on a router with hundreds of sessions. Templates achieve the same update-group efficiency when the resulting policy is identical, so the choice is mostly about configuration clarity rather than performance.

! Session template: transport settings only
template peer-session CUSTOMER-SESSION
 timers 10 30
 password 7 08351F1B1D431F5B
 update-source Loopback0
 exit-peer-session
!
! Policy template: address-family settings
template peer-policy CUSTOMER-POLICY
 route-map CUST-IN in
 route-map CUST-OUT out
 maximum-prefix 500 80 warning-only
 send-community both
 exit-peer-policy
!
router bgp 65000
 neighbor 192.0.2.2 remote-as 65100
 neighbor 192.0.2.2 inherit peer-session CUSTOMER-SESSION
 address-family ipv4 unicast
  neighbor 192.0.2.2 activate
  neighbor 192.0.2.2 inherit peer-policy CUSTOMER-POLICY
 exit-address-family
!
! Confirm what a neighbour actually inherited
R1# show ip bgp template peer-policy CUSTOMER-POLICY
R1# show ip bgp neighbors 192.0.2.2 policy

Applying and reverting policy needs a refresh

Changing an inbound policy does not re-evaluate prefixes the peer already sent. Either the peer must resend them, which route refresh accomplishes without dropping the session, or the local router must have kept a pre-policy copy via soft reconfiguration. Route refresh is negotiated by essentially every modern implementation and costs nothing; soft reconfiguration costs memory proportional to the table size and should be enabled only for a troubleshooting window.

! Confirm route refresh is available before relying on it
R1# show ip bgp neighbors 192.0.2.2 | include Route refresh
  Route refresh: advertised and received(new)
!
! Re-apply inbound policy without dropping the session
R1# clear ip bgp 192.0.2.2 soft in
! Re-apply outbound policy - always local, never disruptive
R1# clear ip bgp 192.0.2.2 soft out
!
! Pre-policy view, for troubleshooting only
router bgp 65000
 address-family ipv4 unicast
  neighbor 192.0.2.2 soft-reconfiguration inbound
RFC 8212 and default-deny eBGPThe original specification left an eBGP session with no policy exchanging everything. RFC 8212 reverses that: a conformant implementation exchanges nothing on an eBGP session until an import and export policy are configured. Current IOS-XE and NX-OS releases implement this behaviour, so a newly configured eBGP session that appears established but exchanges no prefixes may be working exactly as specified — check whether any policy is attached before troubleshooting the session.
One mechanism per directionPick route-maps and use them everywhere, with prefix-lists and AS-path lists referenced from inside them as match conditions. That keeps every decision for a direction in one place, in one readable ordered list, and eliminates the class of problem where a prefix is filtered by something the route-map never sees.
Sub claimPolicy attaches per neighbour, per family, and per direction, and every filter in a direction must agree — which makes a single route-map per direction the only configuration where the decision is visible in one place.

How Does a Route-Map Actually Process a Prefix?

What are the processing rules?

Clauses are evaluated in ascending sequence number order. Within a clause, every match statement of a different type must succeed, while multiple values of the same type are an OR. A clause with no match statements matches every prefix. When a clause matches, processing stops: a permit clause permits the prefix and applies its set statements, a deny clause rejects it and any set statements are ignored. If no clause matches, an implicit deny at the end rejects the prefix. That last rule is the one that catches people, because a route-map written to deny a few prefixes rejects everything else as well unless a trailing permit clause is added.

A Deeper Dive into Route-Map Semantics

The implicit deny, demonstrated

! WRONG - this rejects everything, not just the bogons
route-map CUST-IN deny 10
 match ip address prefix-list BOGONS
! implicit: deny everything else. Nothing is accepted at all.
!
! RIGHT - deny the bogons, then explicitly permit the rest
route-map CUST-IN deny 10
 match ip address prefix-list BOGONS
!
route-map CUST-IN permit 20
 set local-preference 200
! ^ No match clauses, so this matches everything that survived
!   clause 10, permits it, and sets local preference.

AND across match types, OR within one

Two match statements of different types in the same clause must both succeed. Two values on the same match statement, or two statements of the same type, are alternatives. This distinction determines whether a clause is narrow or broad and is worth verifying whenever a route-map matches more or fewer prefixes than expected.

! AND: must be in the prefix-list AND carry the community
route-map NARROW permit 10
 match ip address prefix-list CUSTOMER-BLOCKS
 match community CUST-TAG
 set local-preference 250
!
! OR: either community list satisfies the clause
route-map BROAD permit 10
 match community CUST-TAG PEER-TAG
 set local-preference 150
!
! Also OR: two statements of the same type
route-map ALSO-BROAD permit 10
 match ip address prefix-list BLOCK-A
 match ip address prefix-list BLOCK-B

Set statements on a deny clause do nothing

A deny clause rejects the prefix, and rejection is the end of processing. Any set statements in that clause are never applied. This appears in configurations where someone intended to deny a prefix from being advertised while still tagging it locally, which is not what the syntax does — tagging requires a permit clause somewhere.

The continue statement

continue overrides the stop-on-match behaviour, allowing a matched permit clause to apply its set statements and then proceed to a later clause. It enables layered policies where several clauses each contribute part of the final attribute set. It also makes a route-map considerably harder to read, so use it where the alternative is a combinatorial explosion of clauses and not merely to save typing.

! Layered tagging: geography, then customer class, then action
route-map INGRESS permit 10
 match ip address prefix-list EMEA-BLOCKS
 set community 65000:1001 additive
 continue 30
!
route-map INGRESS permit 20
 match ip address prefix-list AMER-BLOCKS
 set community 65000:1002 additive
 continue 30
!
route-map INGRESS permit 30
 match community GOLD-CUSTOMER
 set local-preference 300
!
route-map INGRESS permit 40
 set local-preference 100
! ^ Without 'continue', a prefix matching clause 10 would never
!   reach the local-preference logic in clause 30.

Verifying what a route-map does before applying it

! Read the map back with its hit counters
R1# show route-map CUST-IN
route-map CUST-IN, deny, sequence 10
  Match clauses:
    ip address prefix-lists: BOGONS
  Set clauses:
  Policy routing matches: 0 packets, 0 bytes
route-map CUST-IN, permit, sequence 20
  Match clauses:
  Set clauses:
    local-preference 200
!
! Find every neighbour a given map is attached to
R1# show running-config | include route-map CUST-IN
!
! Compare pre-policy and post-policy for one neighbour
R1# show ip bgp neighbors 192.0.2.2 received-routes | count network
R1# show ip bgp neighbors 192.0.2.2 routes | count network
! ^ A large difference is your inbound policy doing its job, or
!   doing considerably more than you intended.
Pitfall: an empty permit clause placed too early Symptom: a route-map with several carefully written clauses appears to ignore all of them, and every prefix receives the attributes from one clause. Cause: a clause with no match statements sits at a lower sequence number than the specific clauses, so it matches every prefix first and processing stops there. Confirm: show route-map NAME and look for a clause with an empty Match clauses section that is not the last one. Fix: renumber so the catch-all clause has the highest sequence number. Leave gaps of ten between clauses when writing a map so a later insertion does not require renumbering.
Number clauses in tensSequence numbers 10, 20, 30 leave room to insert 15 later without rewriting the map. A map numbered 1, 2, 3 forces a full renumber the first time a requirement changes, and renumbering a live policy is exactly the operation during which an implicit deny gets exposed.
Sub claimA route-map's most consequential clause is the one nobody writes — the implicit deny — and every route-map intended to filter a few things needs an explicit trailing permit to stop it filtering everything.

How Do I Match Prefixes, AS Paths, and Communities Precisely?

What are the three match languages?

Prefix-lists match an address and a length, with optional ge and le qualifiers that constrain the length range; without them the length must match exactly. AS-path access-lists use regular expressions over the AS_PATH string, where the underscore matches any delimiter — space, comma, brace, parenthesis, or the start and end of the string — which makes _65001_ match the AS number 65001 anywhere without also matching 650011. Community-lists come in two forms: standard, which takes literal community values and treats multiple values on one line as an AND, and expanded, which takes a regular expression over the community string.

A Deeper Dive into the Match Languages

Prefix-list ge and le, precisely

A prefix-list entry names a network and a length. With no qualifiers, only that exact prefix and length matches. ge sets a minimum length and le a maximum, and both must be greater than the stated length. When only ge is given, the range runs from ge to 32; when only le is given, it runs from the stated length to le. Getting these backwards is the most common prefix-list error, and the symptom is a list that matches nothing or everything.

Entry Matches Does not match
permit 10.0.0.0/8 Exactly 10.0.0.0/8 10.0.0.0/16, 10.1.0.0/16
permit 10.0.0.0/8 le 24 Any prefix inside 10/8 with length 8–24 10.1.2.0/25
permit 10.0.0.0/8 ge 24 Any prefix inside 10/8 with length 24–32 10.1.0.0/16
permit 10.0.0.0/8 ge 24 le 24 Only /24s inside 10/8 10.0.0.0/8 itself, 10.1.2.128/25
permit 0.0.0.0/0 Only the default route Everything else
permit 0.0.0.0/0 le 32 Everything Nothing
! Accept only customer /24s from within their allocation
ip prefix-list CUST-A seq 5 permit 203.0.113.0/24
ip prefix-list CUST-A seq 10 permit 198.51.100.0/22 ge 24 le 24
!
! Reject anything longer than /24 from the internet
ip prefix-list NO-LONGER-THAN-24 seq 5 deny 0.0.0.0/0 ge 25
ip prefix-list NO-LONGER-THAN-24 seq 10 permit 0.0.0.0/0 le 24
!
! Test a prefix against a list without applying it
R1# show ip prefix-list CUST-A
ip prefix-list CUST-A: 2 entries
   seq 5 permit 203.0.113.0/24
   seq 10 permit 198.51.100.0/22 ge 24 le 24

AS-path regular expressions

The AS_PATH is matched as a string of AS numbers separated by spaces. The metacharacters follow standard regular expression conventions with one addition: the underscore matches any delimiter, which includes a space, a comma, a brace or parenthesis from confederation and AS_SET notation, and the start or end of the string. That makes the underscore the correct way to delimit an AS number, because a bare 65001 would also match inside 650011.

Expression Matches Typical use
^$ Empty AS_PATH — prefixes originated locally Advertise only your own prefixes
^65001_ Received directly from AS 65001 Filter by directly connected neighbour
_65001$ Originated by AS 65001 Accept only a specific origin AS
_65001_ AS 65001 anywhere in the path Reject anything transiting a given AS
^65001(_65001)*$ Only AS 65001, with any amount of prepending Accept a customer's own prefixes only
^[0-9]+$ Exactly one AS in the path Directly connected origins only
.* Everything Catch-all permit
! Accept only the customer's own prefixes, allowing prepending
ip as-path access-list 10 permit ^65100(_65100)*$
!
! Advertise only locally originated prefixes to a peer
ip as-path access-list 20 permit ^$
!
! Never accept anything that transited a known bad AS
ip as-path access-list 30 deny _64999_
ip as-path access-list 30 permit .*
!
router bgp 65000
 address-family ipv4 unicast
  neighbor 192.0.2.2 filter-list 10 in
  neighbor 192.0.2.6 filter-list 20 out
!
! Test an expression against the live table before applying it
R1# show ip bgp regexp ^65001_
R1# show ip bgp filter-list 10

Standard versus expanded community lists

A standard community list takes literal values. Several values on a single permit line form an AND — a route must carry all of them. Several lines form an OR. An expanded community list takes a regular expression matched against the community string, which is what you need for patterns like "any community belonging to AS 65000".

! Standard: AND on one line
ip community-list standard GOLD-EMEA permit 65000:1001 65000:2000
! ^ Route must carry BOTH communities.
!
! Standard: OR across lines
ip community-list standard ANY-REGION permit 65000:1001
ip community-list standard ANY-REGION permit 65000:1002
ip community-list standard ANY-REGION permit 65000:1003
!
! Expanded: regex over the community string
ip community-list expanded OURS permit _65000:[0-9]+_
!
! Match exactly this set and nothing else
route-map EXACT permit 10
 match community GOLD-EMEA exact-match
Pitfall: forgetting that a standard community list line is an AND Symptom: a community list written to match any of three tags matches almost nothing, and prefixes that visibly carry one of the tags are rejected. Cause: the three values were written on a single permit line, which requires the route to carry all three simultaneously. Confirm: show ip community-list and check whether the values share a line; then show ip bgp community 65000:1001 to see what actually carries each. Fix: put each value on its own permit line to get OR semantics, and reserve the multi-value line for the rare case where AND is genuinely intended.
Test every expression against the live table firstshow ip bgp regexp <expr>, show ip bgp filter-list <n>, and show ip bgp community <value> each evaluate a match against the table already in memory, without touching any policy. Running the expression before attaching it turns a guess into a count, and a regular expression that returns zero prefixes on a full table is almost always wrong rather than genuinely selective.
exact-match changes the questionWithout exact-match, a community match succeeds if the route carries the listed communities among others. With it, the route's community set must be exactly the listed set — no extras. That is occasionally what you want and is almost never what someone means when they add the keyword to make a match stricter, because in practice routes accumulate communities from several sources.
Sub claimEach match language has one counterintuitive rule — ge/le bounds a length range rather than a prefix, the underscore is a delimiter class rather than a character, and a multi-value community line is an AND — and those three account for most matching that silently does the wrong thing.

What Can Policy Change, and What Does Each Change Affect?

Which set actions matter and where do they act?

Six do real work. set weight decides at best-path step one and never leaves the router. set local-preference decides at step two and propagates through the whole autonomous system. set as-path prepend lengthens the path, which is evaluated at step four by other autonomous systems. set origin acts at step five. set metric sets MED, evaluated at step six and only against paths from the same neighbouring AS. set community changes nothing directly but signals policy that some other router may act on. Two more manipulate rather than decide: set ip next-hop overrides forwarding, and set comm-list delete removes specific communities.

A Deeper Dive into Set Actions

Matching the instrument to the intended scope

Set action Best-path step Scope of effect Direction it influences Applied where
set weight 1 This router only Outbound from this router Inbound
set local-preference 2 Entire AS Outbound from the AS Inbound
set as-path prepend 4 — in other ASes Global Inbound to the AS Outbound
set origin 5 Global Rarely used deliberately Either
set metric (MED) 6 One neighbouring AS Inbound to the AS Outbound
set community Wherever it propagates Signals only Either
set ip next-hop This router's forwarding Forwarding, not selection Inbound
set comm-list delete Removes matched communities Cleans up signalling Either

Inbound versus outbound placement

Attributes that influence your own decision belong inbound, because you are changing how you evaluate what a peer sent. Attributes that influence somebody else's decision belong outbound, because you are changing what you advertise. Applying set local-preference outbound to an eBGP peer is a no-op, since local preference is stripped before leaving the AS; applying set as-path prepend inbound affects only your own step-four comparison and nobody else's.

! INBOUND: change how I evaluate what this peer sends
route-map TRANSIT-A-IN permit 10
 match ip address prefix-list CUSTOMER-ROUTES
 set local-preference 200
 set community 65000:1000 additive
route-map TRANSIT-A-IN permit 20
 set local-preference 150
!
! OUTBOUND: change what other autonomous systems see
route-map TRANSIT-B-OUT permit 10
 match as-path 20
 set as-path prepend 65000 65000 65000
 set metric 200
route-map TRANSIT-B-OUT deny 20
! ^ Advertise only locally originated prefixes, prepended.

Cleaning up communities on the way out

set comm-list delete removes every community that matches a named list, which is how internal signalling is stripped before advertisement to an external peer. Leaving internal communities on prefixes you advertise to the world exposes your topology and, worse, may be interpreted by somebody else's policy in a way you did not intend.

! Strip our internal 65000:1xxx tags before advertising externally
ip community-list expanded INTERNAL-TAGS permit _65000:1[0-9][0-9][0-9]_
!
route-map TRANSIT-OUT permit 10
 match as-path 20
 set comm-list INTERNAL-TAGS delete
 set community 65001:100 additive
!
! Verify what the peer actually receives
R1# show ip bgp neighbors 192.0.2.6 advertised-routes
R-PEER# show ip bgp 203.0.113.0/24 | include Community

Changing forwarding without changing selection

set ip next-hop in an inbound route-map rewrites where this router forwards traffic for the matched prefixes, without altering which path won selection or what gets advertised onward. That separation is occasionally exactly what a design needs — steering a subset of traffic through a scrubbing appliance or an inspection device while leaving the control plane untouched — and it is a frequent source of confusion when inherited, because the routing table and the forwarding behaviour disagree with each other in a way that no BGP command explains.

Two variants matter. set ip next-hop peer-address substitutes the address of the peer the route came from or is being sent to, depending on direction. set ip next-hop self in an outbound map is the route-map equivalent of the next-hop-self neighbour command but applied selectively rather than to every prefix.

! Steer matched prefixes through an inspection device
route-map SCRUB-IN permit 10
 match ip address prefix-list PROTECTED-BLOCKS
 set ip next-hop 10.99.0.10
route-map SCRUB-IN permit 20
!
! Selective next-hop-self, rather than for every prefix
route-map SELECTIVE-NHS permit 10
 match ip address prefix-list EXTERNAL-ORIGIN
 set ip next-hop self
route-map SELECTIVE-NHS permit 20
!
! The routing table shows the rewritten next hop, not the BGP one
R1# show ip bgp 203.0.113.0/24 | include next hop|10.99
R1# show ip route 203.0.113.0
  Known via "bgp 65000", distance 20, metric 0
  * 10.99.0.10, from 192.0.2.2, 00:04:11 ago
! ^ 'from' is the BGP peer; the next hop is the rewritten address.

Conditional advertisement and maximum-prefix

Two protective mechanisms sit alongside ordinary policy. Conditional advertisement advertises a prefix only while some other prefix is absent, which implements backup transit without relying on the other side to prefer correctly. Maximum-prefix caps how many prefixes a peer may send, with a warning threshold and an optional automatic restart — it is the single most effective protection against a peer accidentally sending a full table on a session sized for a handful of routes.

! Cap what a customer session will accept
router bgp 65000
 address-family ipv4 unicast
  neighbor 192.0.2.2 maximum-prefix 100 80 restart 15
  ! 100 prefix limit, warn at 80%, tear down and retry after 15 min
!
! Advertise the backup block only while the primary is absent
route-map ADVERTISE-BACKUP permit 10
 match ip address prefix-list BACKUP-BLOCK
route-map WATCH-PRIMARY permit 10
 match ip address prefix-list PRIMARY-BLOCK
!
router bgp 65000
 address-family ipv4 unicast
  neighbor 192.0.2.6 advertise-map ADVERTISE-BACKUP non-exist-map WATCH-PRIMARY
!
R1# show ip bgp neighbors 192.0.2.6 | include Condition
  Condition-map WATCH-PRIMARY, Advertise-map ADVERTISE-BACKUP,
  status: Withdraw
! ^ 'Withdraw' means the primary IS present, so the backup is not
!   being advertised. 'Advertise' means the primary has gone.
Set weight only where the router is aloneWeight is invisible to every other router, so using it on one of several border routers gives each border a different opinion and lets the IGP decide which one traffic reaches. It is the right tool on a single-router site with two upstreams and the wrong tool everywhere else, where local preference expresses the same intent across the whole autonomous system.
Sub claimEvery set action has a scope, and matching the scope to the intent is the whole design decision — weight for one router, local preference for one AS, prepending or communities for somebody else's AS.

Which Policy Mistakes Cause Outages or Leaks?

What goes wrong most often?

Five things. An outbound policy that permits more than intended re-advertises one provider's routes to another, which is the anatomy of every large route leak. A route-map's implicit deny rejects everything because a trailing permit clause is missing. A policy change is applied and never refreshed, so the peer's existing prefixes are still evaluated by the old rules. A prefix-list ge/le qualifier is inverted and matches nothing. And a filter applied to the wrong address family silently does nothing at all.

A Deeper Dive into the Failure Catalogue

The route leak, and the filter that prevents it

A network with two transit providers that advertises everything it knows to both becomes transit between them. Traffic that has no business traversing your network arrives, your circuits saturate, and the two providers see each other through you. The prevention is a single outbound filter expressing the only correct policy for a non-transit network: advertise your own prefixes and your customers' prefixes, and nothing else.

! The only outbound policy a non-transit network needs
ip as-path access-list 20 permit ^$
ip as-path access-list 20 permit ^65100(_65100)*$
ip as-path access-list 20 permit ^65200(_65200)*$
! ^ Own prefixes (empty path) plus each customer AS. Nothing else.
!
route-map TRANSIT-OUT permit 10
 match as-path 20
route-map TRANSIT-OUT deny 20
! ^ Explicit deny for clarity; the implicit one would suffice.
!
router bgp 65000
 address-family ipv4 unicast
  neighbor 192.0.2.2 route-map TRANSIT-OUT out
  neighbor 192.0.2.6 route-map TRANSIT-OUT out
  ! Belt and braces: cap what we will ever advertise
  neighbor 192.0.2.2 maximum-prefix 500 80 warning-only
Pitfall: no outbound filter on a multi-homed network Symptom: transit circuits saturate with traffic between two other networks, and one or both providers open a ticket describing your AS as an unexpected transit path. Nothing is down and nothing in your own monitoring looks wrong until the circuits fill. Cause: with no outbound policy the router advertises every best path to every eBGP peer, including routes learned from the other provider. Confirm: show ip bgp neighbors <peer> advertised-routes | count returns a number close to your full table size rather than close to your prefix count. Fix: an outbound AS-path filter permitting only ^$ and your customer ASes. Apply it to every eBGP peer, including ones you consider low-risk.

Policy applied but never refreshed

An inbound route-map change affects prefixes the peer sends from that moment. Prefixes already in the table were evaluated under the previous policy and stay as they were until the peer resends them. The symptom is a policy that appears to work for new prefixes and not for existing ones, which looks like a partial failure and is a missing soft reset.

! After every inbound policy change
R1# clear ip bgp 192.0.2.2 soft in
!
! After every outbound policy change
R1# clear ip bgp 192.0.2.6 soft out
!
! Or refresh everything, which is safe with route refresh negotiated
R1# clear ip bgp * soft
!
! Confirm the change took effect by counting before and after
R1# show ip bgp neighbors 192.0.2.2 routes | count network

The address-family trap

! WRONG - applied outside any address family, or in the wrong one
router bgp 65000
 neighbor 2001:db8::2 remote-as 65001
 address-family ipv4 unicast
  neighbor 2001:db8::2 route-map V6-POLICY in
 exit-address-family
! ^ The v6 neighbour is not even activated in ipv4 unicast.
!
! RIGHT
router bgp 65000
 neighbor 2001:db8::2 remote-as 65001
 address-family ipv6 unicast
  neighbor 2001:db8::2 activate
  neighbor 2001:db8::2 route-map V6-POLICY in
 exit-address-family
!
! Audit which families a neighbour is active in
R1# show ip bgp neighbors 2001:db8::2 | include address family|Policy
 For address family: IPv6 Unicast
  Route map for incoming advertisements is V6-POLICY

Validating a policy change before it reaches production

Most policy mistakes are visible before the change is committed, provided you look at counts rather than at configuration. Record how many prefixes a neighbour currently sends and how many you currently advertise to it, apply the change, refresh, and compare. A number that moved by an unexpected amount in either direction is the entire signal — you do not need to know which clause caused it to know that something did. On a session carrying a full table this takes seconds and catches the class of error where a route-map was correct in isolation and wrong in combination with a prefix-list applied in the same direction.

! Baseline before the change
R1# show ip bgp neighbors 192.0.2.2 routes | include Total
Total number of prefixes 847
R1# show ip bgp neighbors 192.0.2.6 advertised-routes | include Total
Total number of prefixes 12
!
! ... apply the change, then refresh both directions ...
R1# clear ip bgp 192.0.2.2 soft in
R1# clear ip bgp 192.0.2.6 soft out
!
! Compare. Twelve advertised prefixes becoming 900000 is a leak
! in progress and is visible within one refresh cycle.
R1# show ip bgp neighbors 192.0.2.6 advertised-routes | include Total
Total number of prefixes 12

Defensive defaults worth adopting

  • Every eBGP session has an inbound and an outbound policy, even when the policy is permissive — an explicit permit documents intent that a missing filter does not.
  • Every eBGP session has a maximum-prefix sized to the expected table plus headroom.
  • Bogon and reserved-space filters inbound, and a maximum prefix length, typically rejecting anything longer than a /24 in IPv4.
  • Never accept a default route from a peer unless the design explicitly requires one.
  • Outbound policy is AS-path based, so it stays correct when a customer adds a prefix without telling you.
! A defensible inbound baseline for an internet peer
ip prefix-list SANE-IN seq 5 deny 0.0.0.0/0
ip prefix-list SANE-IN seq 10 deny 0.0.0.0/8 le 32
ip prefix-list SANE-IN seq 15 deny 10.0.0.0/8 le 32
ip prefix-list SANE-IN seq 20 deny 127.0.0.0/8 le 32
ip prefix-list SANE-IN seq 25 deny 169.254.0.0/16 le 32
ip prefix-list SANE-IN seq 30 deny 172.16.0.0/12 le 32
ip prefix-list SANE-IN seq 35 deny 192.168.0.0/16 le 32
ip prefix-list SANE-IN seq 40 deny 224.0.0.0/4 le 32
ip prefix-list SANE-IN seq 45 deny 0.0.0.0/0 ge 25
ip prefix-list SANE-IN seq 50 permit 0.0.0.0/0 le 24
!
route-map PEER-IN permit 10
 match ip address prefix-list SANE-IN
 set local-preference 150
 set community 65000:2000 additive
Mistake Symptom Confirming command Fix
No outbound filter Becoming transit between two providers show ip bgp neighbors X advertised-routes | count AS-path filter permitting ^$ plus customers
Missing trailing permit Route-map rejects everything show route-map NAME Add a permit clause with the highest sequence
Empty clause too early All prefixes get one clause's attributes show route-map NAME — empty Match section Renumber so the catch-all is last
Policy not refreshed Works for new prefixes only Compare received-routes and routes clear ip bgp X soft in|out
Inverted ge/le Prefix-list matches nothing show ip prefix-list NAME Both qualifiers must exceed the stated length
Wrong address family Policy has no effect at all show ip bgp neighbors X per family Repeat the attachment in each family
Community list AND semantics Match succeeds far less often than expected show ip community-list One value per permit line
Exam contextPolicy is a P0 area of the CCIE Enterprise Infrastructure blueprint and is examined as construction rather than recall: a task states an outcome and expects a route-map, prefix-list, or AS-path list that produces it exactly, with no side effects on other prefixes. The reliably tested traps are the implicit deny, the ge/le semantics, and the requirement to soft-reset after applying inbound policy. ENARSI 300-410 covers the same tooling with more emphasis on prefix-lists and route-maps and less on AS-path regular expressions.
Sub claimInbound policy protects you and outbound policy protects everyone else, which is why the filter most networks omit is the one whose absence is visible from outside rather than inside.

Conclusion

BGP policy is a small language with a few sharp edges, and every one of those edges produces a failure that looks like something else. The implicit deny turns a filter for three prefixes into a filter for everything. A clause with no match statements matches everything, so its position in the sequence decides whether it is a sensible default or a policy that swallows the entire map. The ge and le qualifiers bound a length range rather than a prefix. A multi-value community line is an AND. Learning those four rules eliminates most of the surprises, and none of them is difficult once stated explicitly.

The structural principle underneath the syntax is scope. Every policy decision has a blast radius, and the instruments differ mainly in how far their effects travel. Weight stops at the router. Local preference stops at the autonomous system boundary. Prepending and communities travel to other people's networks, where they take effect only if that network's policy chooses to act on them. Matching the instrument to the intended reach is what separates a policy that works from one that works on the router you tested it on.

Above all, treat the outbound filter as the important one. Inbound policy protects your own routing table, and a mistake there is visible to you immediately. Outbound policy determines what the rest of the internet believes about your network, and a mistake there is visible to everyone except you until the circuits fill. An AS-path filter permitting an empty path and your customer autonomous systems, applied to every external neighbour, is four lines and prevents the entire category. Build a three-AS lab, write the outbound filter first, and then verify with advertised-routes rather than assuming — the count is the whole answer.

Reference Notes

  1. RFC 4271, Section 9.1 — the decision process, whose steps determine where each policy-set attribute takes effect.
  2. RFC 4271, Section 5.1.5 — LOCAL_PREF is included only in UPDATE messages sent to internal peers, which is why setting it outbound to an eBGP peer has no effect.
  3. RFC 4271, Section 5.1.4 — MULTI_EXIT_DISC is compared only between routes received from the same neighbouring autonomous system.
  4. RFC 8212 — a BGP speaker must not advertise or accept routes on an eBGP session until import and export policies are explicitly configured.
  5. RFC 7454, Section 6 — prefix filtering recommendations including bogon filtering and maximum prefix length limits.
  6. RFC 7454, Section 9 — maximum-prefix limits as protection against a peer announcing an unexpected number of routes.
  7. RFC 2918 — the Route Refresh capability, which allows inbound policy to be re-applied without resetting the session.
  8. Cisco, "Using Regular Expressions in BGP" — the underscore matches any delimiter including spaces, commas, braces, parentheses, and the start or end of the AS_PATH string.
  9. Cisco IOS-XE BGP Configuration Guide — route-map clauses are evaluated in ascending sequence order, the first matching clause terminates processing, and an implicit deny follows the final clause.
  10. Cisco IOS-XE BGP Configuration Guide — a route-map clause with no match statements matches all routes.
  11. Cisco IOS-XE IP Routing Configuration Guide — prefix-list ge and le values must be greater than the specified prefix length, and ge must not exceed le.
  12. Cisco IOS-XE BGP Configuration Guide — a standard community list line containing multiple values requires a route to carry all of them; separate lines provide alternative matches.