Policy & Filters

Updated

September 4, 2026

Policy & Filters

Routing without policy is a demo; routing with policy is operations. This chapter covers prefix filters, distribute ideas, route-maps as a pattern, and loop-prevention instincts using FRR—still free and vendor-agnostic.

Learning goals

By the end of this chapter you can:

  • Write prefix-lists that match intended space only
  • Apply import/export filters on BGP neighbors
  • Use route-map style logic (match → set → permit/deny)
  • Predict leaks and loops from redistribution mistakes
  • Build a lab that rejects unauthorized prefixes

Why policy exists

Goal Mechanism ideas
Do not accept bogons / your own space from customers Inbound prefix filter
Do not advertise internal-only nets to Internet Outbound filter
Prefer one uplink local-pref on import
De-prefer backup path AS-path prepend on export
Redistribute without feedback loops Tags, filters, distance

Prefix lists (FRR)

ip prefix-list OWN-NETS seq 10 permit 192.168.1.0/24
ip prefix-list OWN-NETS seq 20 permit 1.1.1.1/32
ip prefix-list OWN-NETS seq 30 deny any
ip prefix-list CUST-ALLOW seq 10 permit 198.51.100.0/24
ip prefix-list CUST-ALLOW seq 20 deny any

Order matters: first match wins. Always know your implicit/default at the end.

Route-maps as idea

Regardless of vendor syntax, the pattern is:

if match prefix-list X:
  set local-preference 200
  permit
else deny

FRR example:

route-map FROM-CUST permit 10
 match ip address prefix-list CUST-ALLOW
 set local-preference 200
route-map FROM-CUST deny 99
!
route-map TO-CUST permit 10
 match ip address prefix-list OWN-NETS

Attach:

router bgp 65002
 neighbor 10.0.0.1 route-map FROM-CUST in
 neighbor 10.0.0.1 route-map TO-CUST out

Lab: filter unauthorized prefixes

Extend eBGP lab: r2 (ISP) should only accept 192.168.1.0/24 from r1 (customer), not a hijack prefix.

Customer r1 advertises extra junk

address-family ipv4 unicast
 network 192.168.1.0/24
 network 203.0.113.0/24

ISP r2 policy

ip prefix-list CUST-R1 seq 5 permit 192.168.1.0/24
ip prefix-list CUST-R1 seq 10 deny any
!
route-map FROM-R1 permit 10
 match ip address prefix-list CUST-R1
route-map FROM-R1 deny 20
!
router bgp 65002
 neighbor 10.0.0.1 route-map FROM-R1 in

Predict

  • ISP installs 192.168.1.0/24
  • 203.0.113.0/24 is rejected
  • show bgp on r2 lacks the junk

Observe

docker exec clab-bgp-ebgp-r2 vtysh -c 'show bgp ipv4 unicast'
docker exec clab-bgp-ebgp-r2 vtysh -c 'show ip route 203.0.113.0'
docker exec clab-bgp-ebgp-r1 vtysh -c 'show bgp ipv4 unicast neighbors 10.0.0.2 advertised-routes'

Harden

Return to explicit export on customer too—only advertise owned space.

route-map EXPORT-OWN permit 10
 match ip address prefix-list OWN-NETS
!
neighbor 10.0.0.2 route-map EXPORT-OWN out

Remove no bgp ebgp-requires-policy when policies are in place if you want FRR to enforce the discipline.

Local-pref steer drill

Two ISPs: isp1 and isp2; customer prefers isp1 for inbound to customer… actually:

  • Local pref (on customer) influences outbound exit from customer AS
  • AS prepend / MED / communities influence how others send inbound

Outbound preference (customer)

route-map PREFER-ISP1 permit 10
 set local-preference 300
route-map PREFER-ISP2 permit 10
 set local-preference 100
!
neighbor <isp1> route-map PREFER-ISP1 in
neighbor <isp2> route-map PREFER-ISP2 in

Predict: traffic leaves via isp1 when both paths exist.

vtysh -c 'show ip route 0.0.0.0'
vtysh -c 'show bgp ipv4 unicast'

Redistribution loop awareness

Redistributing OSPF ↔︎ BGP (or static ↔︎ OSPF) without filters can:

  • Re-inject prefixes with changed metrics
  • Create loops or suboptimal paths
  • Explode tables

Rules of thumb:

  1. Redistribute on purpose, on as few points as possible
  2. Tag routes; filter on tags
  3. Never blindly mutual redistribute two IGPs
  4. Prefer BGP for policy domains, IGP for underlay topology

Example static→OSPF with filter (sketch)

ip prefix-list STATICS seq 5 permit 192.168.9.0/24
route-map REDIST-STATIC permit 10
 match ip address prefix-list STATICS
!
router ospf
 redistribute static route-map REDIST-STATIC

ACL-style packet filters vs routing policy

Do not confuse:

Routing policy Packet filter
Which routes enter RIB Which packets pass
BGP/OSPF route-maps nftables/iptables/ACLs
Control plane Data plane

Both appear in hardening. A permit route does not mean packets are allowed through a firewall mid-path.

Distribute-list / filter-list ideas

Older or alternate forms filter by ACL or AS-path lists:

bgp as-path access-list 1 permit _65001$
neighbor x filter-list 1 in

Same intent: accept only what policy allows.

Failure drills

Drill 1 — over-broad permit any

Export permit any to a lab “ISP.”

Observe: internal lab nets leave the AS.

Fix: prefix-list OWN only.

Harden: default-deny export mindset.

Drill 2 — accidental deny all

Route-map deny first line matches everything.

Symptom: Established but zero prefixes.

Debug: show bgp neighbors ... routes / policy counters if available; simplify map.

Drill 3 — next-hop-self missing (iBGP)

Learned eBGP route reflected iBGP with remote next hop unreachable.

Symptom: BGP has path; FIB lacks usable route.

Fix: next-hop-self or IGP reachability to next hop.

verify.sh policy checks

#!/usr/bin/env bash
set -euo pipefail
fail() { echo "FAIL: $*" >&2; exit 1; }

docker exec clab-bgp-ebgp-r2 vtysh -c 'show bgp ipv4 unicast' | grep -q '192.168.1.0/24' \
  || fail "missing customer prefix"
if docker exec clab-bgp-ebgp-r2 vtysh -c 'show bgp ipv4 unicast' | grep -q '203.0.113.0/24'; then
  fail "hijack prefix should be filtered"
fi
echo OK

Policy design worksheet

Before applying:

## Neighbor: r1-r2 eBGP
Import accept: ...
Import deny: ...
Export advertise: ...
Export never: ...
Preference intent: ...
Failure mode if map wrong: ...

Summary

  • Policy decides which routes and with which attributes
  • Prefix-lists + route-maps are the portable pattern
  • Default-deny posture on Internet edges
  • Redistribution needs filters/tags or it will bite
  • Verify with BGP table and negative tests for rejected prefixes

Next part: ops & automation—observability, lab-as-code automation, and a capstone outline that pulls the book together.