The change was meant to restrict management access. SSH still worked afterward, but ping to the router failed, OSPF lost its neighbor, and the loopback eBGP session went down.
On br-edge, the clock read 04:44:08.546 UTC just after the restrictive WAN→self policy attached. OSPF logged its dead-timer expiry at 04:44:16.134. BGP logged Down at 04:44:22.621, following a hold-time-expired notification. A successful SSH login would have missed both failures.
This zone-based firewall (ZBF) self zone lab was built in my home lab in Containerlab, with the router guests running in a nested VM setup. The complete failure used unicast NON_BROADCAST OSPF on IOSv 15.9(3)M12. Broadcast-network multicast OSPF survived the earlier attached-policy test on this image. That observation does not establish that multicast hellos are always safe.
The zone-based firewall on IOS XE covers zones, the self-zone default, and an SSH-only policy that breaks ping on cat8000v; start there for the basics. Here the useful difference is routing: which adjacency dies first, why OSPF needs pass, and why fixing inbound traffic still leaves the router's own sessions broken.
Topology and addressing
The data path was lan-host → br-edge → upstream → noc-host. br-edge ran the firewall on IOSv; upstream ran IOL 17.18.2. OSPF across the WAN supplied reachability between the loopbacks used for eBGP.

| Device | Interface | Address | Role |
|---|---|---|---|
| br-edge, IOSv 15.9(3)M12 | Gi0/1 | 10.34.10.1/24 | lan-host gateway; ZN-LAN |
| br-edge | Gi0/2 | 100.64.34.1/30 | WAN toward upstream; ZN-WAN |
| br-edge | Lo0 | 10.34.255.1/32 | Router endpoint; AS 65034 |
| upstream, IOL 17.18.2 | Ethernet0/1 | 100.64.34.2/30 | WAN toward br-edge |
| upstream | Ethernet0/2 | 10.34.200.1/24 | NOC gateway |
| upstream | Lo0 | 192.0.2.34/32 | eBGP peer; AS 65200 |
| lan-host | eth1 | 10.34.10.10/24 | Gateway 10.34.10.1 |
| noc-host | eth1 | 10.34.200.10/24 | Gateway 10.34.200.1 |
IOL 17.18.2 rejected the zone security, parameter-map type inspect, and zone-pair security commands with invalid-input errors, even from privileged configuration mode. I replaced only the firewall router with IOSv. These are IOSv ZBF results, not a working IOL firewall implementation. The Gi interface names in the output belong to that fallback.
OSPF process 34 used area 0, passive endpoint LANs and loopbacks, and a WAN hello/dead interval of 2/8 seconds. The complete reproduction changed both WAN interfaces to non-broadcast and configured explicit neighbors. (OSPF network types explains why NBMA needs neighbor statements.) During troubleshooting, neighbor poll intervals became two seconds for faster retries.
These resulting OSPF settings include that later poll-interval adjustment. On br-edge:
interface GigabitEthernet0/2
ip address 100.64.34.1 255.255.255.252
zone-member security ZN-WAN
ip ospf network non-broadcast
ip ospf dead-interval 8
ip ospf hello-interval 2
duplex auto
speed auto
media-type rj45
!
router ospf 34
router-id 10.34.255.1
passive-interface default
no passive-interface GigabitEthernet0/2
network 10.34.10.0 0.0.0.255 area 0
network 10.34.255.1 0.0.0.0 area 0
network 100.64.34.0 0.0.0.3 area 0
neighbor 100.64.34.2 poll-interval 2
!
On upstream:
interface Ethernet0/1
ip address 100.64.34.2 255.255.255.252
ip ospf network non-broadcast
ip ospf dead-interval 8
ip ospf hello-interval 2
!
...
router ospf 34
router-id 192.0.2.34
passive-interface default
no passive-interface Ethernet0/1
network 10.34.200.0 0.0.0.255 area 0
network 100.64.34.0 0.0.0.3 area 0
network 192.0.2.34 0.0.0.0 area 0
neighbor 100.64.34.1 poll-interval 2
!
BGP ran between the loopbacks with multihop 2 and keepalive/hold timers of 5/15 seconds (configure eBGP neighbors covers ebgp-multihop and update-source). That separates the eBGP session from the connected WAN link: losing the OSPF route also removes its underlay.
Two lab controls matter. A static route covered only the NOC host, preserving SSH's return path after OSPF failed; SSH targeted the connected WAN address. There was no static route to the BGP peer loopback. Also, early BGP flaps coincided with BGP replacing the peer's OSPF /32. Raising BGP distance on br-edge preserved OSPF as the underlay:
router bgp 65034
bgp log-neighbor-changes
network 10.34.10.0 mask 255.255.255.0
neighbor 192.0.2.34 remote-as 65200
neighbor 192.0.2.34 ebgp-multihop 2
neighbor 192.0.2.34 update-source Loopback0
neighbor 192.0.2.34 timers 5 15
distance bgp 200 200 200
...
ip route 10.34.200.10 255.255.255.255 100.64.34.2 name NOC-TEST-CONTROL
The distance setting is a fixture for this topology, not a general BGP recommendation.
Baseline: no self zone-pair
The zone inventory and baseline pair output showed the LAN/WAN membership and one transit policy. There was no self pair:
br-edge#show zone security
zone self
Description: System Defined Zone
zone ZN-LAN
Member Interfaces:
GigabitEthernet0/1
zone ZN-WAN
Member Interfaces:
GigabitEthernet0/2
br-edge#show zone-pair security
Zone-pair name ZP-LAN-WAN
Source-Zone ZN-LAN Destination-Zone ZN-WAN
service-policy PM-LAN-TO-WAN
The LAN→WAN policy inspected transit TCP, UDP, and ICMP. It did not govern packets terminating on br-edge's WAN address or loopback. The self zone has no member interfaces; it covers every router address, including Lo0 (Cisco ZBF configuration guide). Cisco documents the self zone as the one exception to ZBF's default deny: traffic to and from the router is permitted until a policy restricts it (Cisco ZBF design guide).
After rebuilding the unicast baseline, OSPF was FULL and BGP was Established with one received prefix. In the BGP summary, the numeric final column is the prefix count:
br-edge#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
192.0.2.34 1 FULL/DR 00:00:06 100.64.34.2 GigabitEthernet0/2
...
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
192.0.2.34 4 65200 20 20 17 0 0 00:01:10 1
The NOC host received all three ping replies from both router addresses, SSH v2 succeeded, and LAN ping/HTTP to the NOC worked. A router-originated loopback ping also passed:
br-edge#ping 10.34.200.10 source lo0 repeat 4 timeout 1
Type escape sequence to abort.
Sending 4, 100-byte ICMP Echos to 10.34.200.10, timeout is 1 seconds:
Packet sent with a source address of 10.34.255.1
!!!!
Success rate is 100 percent (4/4), round-trip min/avg/max = 4/11/21 ms
I kept these separate tests because transit reachability, inbound management, and router-originated traffic exercise different policies.
The change: SSH survives while routing expires
There was a parser trap before the actual outage. IOSv rejected attaching the self policy when its class used SSH application inspection:
%Protocol configured in class-map CM-NOC-SSH cannot be configured for the self zone with inspect action. Please remove the protocol and retry
Cisco lists this limit: self-zone policies support TCP, UDP, ICMP and H.323 inspection only, with no application inspection (Cisco ZBF design guide). The bare zone-pair left by that rejected attachment did not reproduce the outage. Replacing SSH application matching with TCP plus an ACL allowed the service policy to attach. The relevant fault configuration, excerpted from the running configuration, was:
class-map type inspect match-all CM-NOC-SSH
match access-group name ACL-NOC-SSH
match protocol tcp
...
policy-map type inspect PM-WAN-TO-SELF
class type inspect CM-NOC-SSH
inspect
class class-default
drop log
...
zone-pair security ZP-WAN-SELF source ZN-WAN destination self
service-policy type inspect PM-WAN-TO-SELF
...
ip access-list extended ACL-NOC-SSH
permit tcp 10.34.200.0 0.0.0.255 any eq 22
The SSH class used match-all, requiring both TCP and the NOC source/port ACL. With match-any, adding that ACL alongside a protocol match would express OR. The nested class-map lab covers more elaborate classification; this rule needed a simple conjunction. SSH setup itself is covered in enable SSH on Cisco.
In the first attached-policy test, multicast OSPF stayed FULL while BGP and ping failed. I then removed the self pair, changed both OSPF WAN interfaces to NON_BROADCAST with explicit neighbors, and verified the new baseline before applying the same restriction again. The full failure below belongs to that unicast test.
The successful attachment and its clock anchor were:
br-edge(config)#zone-pair security ZP-WAN-SELF source ZN-WAN destination self
br-edge(config-sec-zone-pair)#service-policy type inspect PM-WAN-TO-SELF
br-edge(config-sec-zone-pair)#end
br-edge#show clock
*04:44:08.546 UTC Wed Oct 21 2026
OSPF was still FULL immediately afterward. Existing neighbor state can outlive the packets maintaining it. With the lab's OSPF hello/dead timers, the failure appeared several seconds later:
*Oct 21 04:44:09.256: %FW-6-DROP_PKT: Dropping tcp session 192.0.2.34:179 10.34.255.1:41218 on zone-pair ZP-WAN-SELF class class-default due to DROP action found in policy-map with ip ident 52216
...
*Oct 21 04:44:16.134: %OSPF-5-ADJCHG: Process 34, Nbr 192.0.2.34 on GigabitEthernet0/2 from FULL to DOWN, Neighbor Down: Dead timer expired
...
*Oct 21 04:44:22.586: %BGP-3-NOTIFICATION: sent to neighbor 192.0.2.34 4/0 (hold time expired) 0 bytes
...
*Oct 21 04:44:22.621: %BGP-5-ADJCHANGE: neighbor 192.0.2.34 Down BGP Notification sent
Those OSPF and BGP Down events were 7.588 and 14.075 seconds after the post-change clock reading. They are clock-anchor deltas, not exact configuration commit latencies. The routers' clocks were unsynchronized and drifted, so I do not subtract timestamps across devices.
The later neighbor snapshot showed an NBMA neighbor in ATTEMPT, not an empty OSPF table, and BGP Idle:
br-edge#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
N/A 0 ATTEMPT/DROTHER - 100.64.34.2 GigabitEthernet0/2
...
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
192.0.2.34 4 65200 0 0 1 0 0 00:00:29 Idle
OSPF routes and the received BGP prefix disappeared. From noc-host, both router targets lost all replies:
PING 10.34.255.1 (10.34.255.1): 56 data bytes
--- 10.34.255.1 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss
PING 100.64.34.1 (100.64.34.1): 56 data bytes
--- 100.64.34.1 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss
The WAN-source control failed as well:
br-edge#ping 10.34.200.10 source 100.64.34.1 repeat 3 timeout 1
Type escape sequence to abort.
Sending 3, 100-byte ICMP Echos to 10.34.200.10, timeout is 1 seconds:
Packet sent with a source address of 100.64.34.1
...
Success rate is 0 percent (0/3)
A fresh SSH v2 login to the WAN address still succeeded. Its /32 return route was the deliberate control that kept management reachable while the routing experiment failed.
Sessions and drops during the fault
The session view showed only the SSH class and the default drop. This snapshot followed the short SSH test closing, so it contained no live SSH entry; the earlier inspection statistics recorded one session creation.
br-edge#show policy-map type inspect zone-pair ZP-WAN-SELF sessions
policy exists on zp ZP-WAN-SELF
Zone-pair: ZP-WAN-SELF
Service-policy inspect : PM-WAN-TO-SELF
Class-map: CM-NOC-SSH (match-all)
Match: access-group name ACL-NOC-SSH
Match: protocol tcp
Inspect
Class-map: class-default (match-any)
Match: any
Drop
28 packets, 1668 bytes
br-edge#show policy-firewall stats drop-counters
DROP action found in policy-map 82
Stray Segment 5
The 28 default drops were local to this pair. The global DROP-action total was 82 and included earlier experiments. Neither number alone identifies every dropped protocol. The tuple in the log, the neighbor transition, and the packet capture provide the context.
The closed WAN capture, taken outside IOS at the guest's WAN NIC, contained arriving unicast OSPF hellos, BGP retransmissions, and received ICMP echo replies during failed ping tests. Early replies reached br-edge before underlay routes disappeared. A WAN-source ping also failed despite received replies, isolating firewall return-path filtering from later loopback routing loss. All four captures reported zero kernel drops.
Why the ZBF self zone policy caught OSPF and BGP
For a zone-based firewall, the self zone covers the router's own endpoints. BGP between loopbacks is router traffic, just as SSH to the WAN IP is. Neither belongs to the LAN→WAN transit policy.
Attaching the restrictive WAN→self policy put unmatched inbound traffic into its default drop. It allowed NOC TCP/22, but omitted unicast OSPF, BGP TCP traffic, and ICMP. The BGP drop log even showed traffic sourced from TCP/179 toward the local ephemeral port of an existing connection.
At that point self→WAN still had no pair. The router could send echo requests, but that did not create inspected state for their replies. An inbound rule allowing echo requests also would not admit echo replies to a router-originated ping. This distinction explains why an apparently repaired inbound policy later left outbound ping broken.
Treat the multicast result as a limit of this observation. Cisco also states that ZBF has no stateful inspection for multicast, including to the self zone, and points to CoPP for multicast control-plane protection (Cisco ZBF configuration guide). That is context, not a proven cause here. I did not establish its internal cause or prove equivalent behavior on other images. The outage evidence is for unicast OSPF on this IOSv.
OSPF inspect on the self zone: accepted, no sessions
I first added an ACL matching OSPF from upstream and gave that class an inspect action:
br-edge(config)#ip access-list extended ACL-OSPF-IN
br-edge(config-ext-nacl)#permit ospf host 100.64.34.2 any
br-edge(config-ext-nacl)#exit
br-edge(config)#class-map type inspect match-any CM-OSPF
br-edge(config-cmap)#match access-group name ACL-OSPF-IN
br-edge(config-cmap)#exit
br-edge(config)#policy-map type inspect PM-WAN-TO-SELF
br-edge(config-pmap)#class type inspect CM-OSPF
br-edge(config-pmap-c)#inspect
br-edge(config-pmap-c)#end
The parser accepted it. Runtime behavior did not follow: 20 packets matched, no sessions were created, Invalid Segment reached 22, and the neighbor remained ATTEMPT.
Class-map: CM-OSPF (match-any)
Match: access-group name ACL-OSPF-IN
20 packets, 1600 bytes
30 second rate 0 bps
Inspect
Session creations since subsystem startup or last reset 0
Current session counts (estab/half-open/terminating) [0:0:0]
...
br-edge#show policy-firewall stats drop-counters
DROP action found in policy-map 82
Invalid Segment 22
Stray Segment 5
br-edge#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
N/A 0 ATTEMPT/DROTHER - 100.64.34.2 GigabitEthernet0/2
OSPF could not be inspected successfully in this test. Matching an ACL did not make it a stateful session. That fits Cisco's limits: an ACL-only inspect class gets basic TCP or UDP inspection, and self-zone inspection covers only TCP, UDP, ICMP and H.323 (Cisco ZBF design guide). OSPF is IP protocol 89. I changed only that class's action from inspect to pass:
br-edge(config)#policy-map type inspect PM-WAN-TO-SELF
br-edge(config-pmap)#class type inspect CM-OSPF
br-edge(config-pmap-c)#no inspect
br-edge(config-pmap-c)#pass
br-edge(config-pmap-c)#end
OSPF logged FULL at 04:47:18.179, 1.018 seconds after the post-change clock anchor. BGP remained blocked and appeared Active in the next snapshot:
br-edge#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
192.0.2.34 1 FULL/DR 00:00:06 100.64.34.2 GigabitEthernet0/2
...
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
192.0.2.34 4 65200 0 0 1 0 0 00:03:18 Active
The OSPF neighbor troubleshooting guide helps distinguish adjacency states; here the action change and recovering neighbor tied the failure to the firewall. BGP's continuing Idle/Active state was a separate permit problem, even with its OSPF underlay restored; BGP neighbor stuck in Idle or Active covers the general causes.
The fix: pass OSPF and inspect BGP on both self zone-pairs

The final policy passed OSPF in each direction and inspected the permitted TCP/ICMP initiations. Pass is one-way and creates no return-session allowance. Cisco documents both halves: pass allows traffic in one direction only (Cisco ZBF design guide), and passed traffic bypasses the zone firewall without creating sessions (Cisco ZBF configuration guide). Inspection supplied state for TCP and ICMP returns, including sessions started by the router.
| Direction | Permitted initiation | Action |
|---|---|---|
| WAN→self | NOC TCP/22 | Inspect TCP with source/port ACL |
| WAN→self | OSPF from 100.64.34.2 | Pass |
| WAN→self | BGP peer TCP tuples | Inspect |
| WAN→self | NOC echo to WAN IP or Lo0 | Inspect ICMP |
| self→WAN | Router BGP peer TCP tuples | Inspect |
| self→WAN | Lo0 echo to noc-host | Inspect ICMP |
| self→WAN | OSPF from 100.64.34.1 | Pass |
The second trap, before the complete configuration
Adding inbound BGP and NOC echo inspection recovered BGP and inbound ping. An inbound BGP session was visible:
Session FAD4D00 (192.0.2.34:22168)=>(10.34.255.1:179) tcp SIS_OPEN/TCP_ESTAB
Created 00:00:37, Last heard 00:00:01
Bytes sent (initiator:responder) [306:305]
But Lo0-sourced router ping remained 0/3. I added a reverse policy inspecting router-originated BGP and ICMP, initially leaving OSPF out. This was the second fault:
br-edge(config)#zone-pair security ZP-SELF-WAN source self destination ZN-WAN
br-edge(config-sec-zone-pair)#service-policy type inspect PM-SELF-TO-WAN
br-edge(config-sec-zone-pair)#end
The new restrictive direction dropped outgoing OSPF. Incoming hellos continued, leaving br-edge INIT while upstream lost FULL, the classic one-way hello INIT state, caused here by the firewall; BGP fell back to Idle. The outbound log called the flow Unknown-l4:
br-edge#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
192.0.2.34 1 INIT/DROTHER 00:00:06 100.64.34.2 GigabitEthernet0/2
...
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
192.0.2.34 4 65200 0 0 1 0 0 00:00:13 Idle
...
*Oct 21 04:49:09.205: %FW-6-DROP_PKT: Dropping Unknown-l4 session 100.64.34.1:0 100.64.34.2:0 on zone-pair ZP-SELF-WAN class class-default due to DROP action found in policy-map with ip ident 1208
The reverse pair's default counter grew from 1 packet just after attachment to 20 in the later diagnostic snapshot. The capture showed outbound hellos ceasing while inbound hellos continued. Passing inbound OSPF had never authorized outbound OSPF.
Adding the outbound OSPF ACL/class and pass action completed the repair:
br-edge(config)#ip access-list extended ACL-OSPF-OUT
br-edge(config-ext-nacl)#permit ospf host 100.64.34.1 any
br-edge(config-ext-nacl)#exit
br-edge(config)#class-map type inspect match-any CM-SELF-OSPF
br-edge(config-cmap)#match access-group name ACL-OSPF-OUT
br-edge(config-cmap)#exit
br-edge(config)#policy-map type inspect PM-SELF-TO-WAN
br-edge(config-pmap)#class type inspect CM-SELF-OSPF
br-edge(config-pmap-c)#pass
br-edge(config-pmap-c)#end
Final ACLs, classes, and both self pairs
These are the working firewall blocks from br-edge. The BGP ACLs include destination-port and source-port variants; IOS renders TCP/179 as eq bgp. The SSH ACL permits the NOC subnet to TCP/22 on router endpoints, rather than only one destination address. The ICMP rules are narrower and name the tested endpoints.
ip access-list extended ACL-BGP-IN
permit tcp host 192.0.2.34 host 10.34.255.1 eq bgp
permit tcp host 192.0.2.34 eq bgp host 10.34.255.1
ip access-list extended ACL-BGP-OUT
permit tcp host 10.34.255.1 host 192.0.2.34 eq bgp
permit tcp host 10.34.255.1 eq bgp host 192.0.2.34
ip access-list extended ACL-NOC-ICMP
permit icmp 10.34.200.0 0.0.0.255 host 10.34.255.1 echo
permit icmp 10.34.200.0 0.0.0.255 host 100.64.34.1 echo
ip access-list extended ACL-NOC-SSH
permit tcp 10.34.200.0 0.0.0.255 any eq 22
ip access-list extended ACL-OSPF-IN
permit ospf host 100.64.34.2 any
ip access-list extended ACL-OSPF-OUT
permit ospf host 100.64.34.1 any
ip access-list extended ACL-SELF-ICMP
permit icmp host 10.34.255.1 host 10.34.200.10 echo
The final class definitions also include the existing LAN transit class:
class-map type inspect match-all CM-NOC-SSH
match access-group name ACL-NOC-SSH
match protocol tcp
class-map type inspect match-all CM-SELF-ICMP
match protocol icmp
match access-group name ACL-SELF-ICMP
class-map type inspect match-any CM-SELF-OSPF
match access-group name ACL-OSPF-OUT
class-map type inspect match-any CM-OSPF
match access-group name ACL-OSPF-IN
class-map type inspect match-all CM-SELF-BGP
match protocol tcp
match access-group name ACL-BGP-OUT
class-map type inspect match-any CM-LAN-INTERNET
match protocol tcp
match protocol udp
match protocol icmp
class-map type inspect match-all CM-NOC-ICMP
match protocol icmp
match access-group name ACL-NOC-ICMP
class-map type inspect match-all CM-BGP
match protocol tcp
match access-group name ACL-BGP-IN
Both self policies end with default drop logging. The existing LAN→WAN pair remains separate:
policy-map type inspect PM-WAN-TO-SELF
class type inspect CM-NOC-SSH
inspect
class type inspect CM-OSPF
pass
class type inspect CM-BGP
inspect
class type inspect CM-NOC-ICMP
inspect
class class-default
drop log
policy-map type inspect PM-SELF-TO-WAN
class type inspect CM-SELF-BGP
inspect
class type inspect CM-SELF-ICMP
inspect
class type inspect CM-SELF-OSPF
pass
class class-default
drop log
...
zone-pair security ZP-WAN-SELF source ZN-WAN destination self
service-policy type inspect PM-WAN-TO-SELF
zone-pair security ZP-SELF-WAN source self destination ZN-WAN
service-policy type inspect PM-SELF-TO-WAN
This is TCP inspection selected by ACL, not SSH application inspection. ZBF port-maps address a different classification problem; changing application ports would not repair an omitted OSPF pass action here.
After the fix: neighbors, routes, and real return traffic
The final post-change clock read 04:50:08.826. OSPF logged FULL at 04:50:09.006 and BGP Up at 04:50:14.359: anchor deltas of 0.180 and 5.533 seconds, respectively.
*Oct 21 04:50:09.006: %OSPF-5-ADJCHG: Process 34, Nbr 192.0.2.34 on GigabitEthernet0/2 from LOADING to FULL, Loading Done
...
*Oct 21 04:50:14.359: %BGP-5-ADJCHANGE: neighbor 192.0.2.34 Up
The subsequent snapshot confirmed FULL and an Established BGP session receiving one prefix:
br-edge#show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
192.0.2.34 1 FULL/DR 00:00:07 100.64.34.2 GigabitEthernet0/2
...
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd
192.0.2.34 4 65200 13 12 21 0 0 00:00:40 1
On br-edge, the peer prefix was best in BGP but marked RIB-failure because OSPF retained the route under the distance control. Upstream installed the advertised LAN prefix through BGP. These excerpts are from br-edge's BGP table, br-edge's route table, and upstream's route table, respectively:
Network Next Hop Metric LocPrf Weight Path
*> 10.34.10.0/24 0.0.0.0 0 32768 i
r> 192.0.2.34/32 192.0.2.34 0 0 65200 i
...
O 192.0.2.34 [110/2] via 100.64.34.2, 00:00:44, GigabitEthernet0/2
...
B 10.34.10.0/24 [20/0] via 10.34.255.1, 00:00:45
NOC pings to both router addresses returned 4/4, SSH v2 worked, and LAN ping/HTTP worked. The router's own Lo0-sourced ping now returned 4/4 too:
br-edge#ping 10.34.200.10 source lo0 repeat 4 timeout 1
Type escape sequence to abort.
Sending 4, 100-byte ICMP Echos to 10.34.200.10, timeout is 1 seconds:
Packet sent with a source address of 10.34.255.1
!!!!
Success rate is 100 percent (4/4), round-trip min/avg/max = 10/27/57 ms
Read policy-map type inspect zone-pair sessions and counters
The session commands showed router-originated BGP, router-originated ICMP, and inbound SSH with bytes in both directions. These excerpts omit other classes:
br-edge#show policy-map type inspect zone-pair ZP-SELF-WAN sessions
policy exists on zp ZP-SELF-WAN
Zone-pair: ZP-SELF-WAN
Service-policy inspect : PM-SELF-TO-WAN
...
Session FAD5E30 (10.34.255.1:21032)=>(192.0.2.34:179) tcp SIS_OPEN/TCP_ESTAB
Created 00:00:48, Last heard 00:00:01
Bytes sent (initiator:responder) [343:344]
...
Session FAD7640 (10.34.255.1:8)=>(10.34.200.10:0) icmp SIS_OPEN
Created 00:00:01, Last heard 00:00:00
ECHO request
Bytes sent (initiator:responder) [288:288]
...
br-edge#show policy-map type inspect zone-pair ZP-WAN-SELF sessions
policy exists on zp ZP-WAN-SELF
Zone-pair: ZP-WAN-SELF
Service-policy inspect : PM-WAN-TO-SELF
...
Session FAD72D0 (10.34.200.10:44514)=>(100.64.34.1:22) tcp SIS_OPEN/TCP_ESTAB
Created 00:00:13, Last heard 00:00:12
Bytes sent (initiator:responder) [2878:5611]
The final BGP connection originated on br-edge toward upstream TCP/179. Earlier, the inbound pair held a connection initiated by upstream. Keeping BGP inspection in both policies supported those permitted initiations. SSH replies worked without a separate outbound SSH class because the inbound connection was inspected.
During a quiet comparison window, inbound OSPF pass counts rose 163→175 and outbound counts 63→75. Router BGP inspection packets rose 88→107. WAN→self and self→WAN default drops stayed at 45 and 34; the global DROP-action count stayed 133. Old cumulative drops were not continuing failures. The later per-class excerpt showed:
Class-map: CM-OSPF (match-any)
211 packets, 16588 bytes
Pass
175 packets, 13708 bytes
...
Class-map: CM-SELF-OSPF (match-any)
75 packets, 4652 bytes
Pass
75 packets, 4652 bytes
Class-map: class-default (match-any)
Drop
34 packets, 2040 bytes
A deliberate denied test still dropped
From noc-host, a TCP/80 attempt to the router loopback timed out with curl exit 28. The router logged the denied tuple:
* Trying 10.34.255.1:80...
* Connection timed out after 3002 milliseconds
* closing connection #0
...
*Oct 21 04:52:30.353: %FW-6-DROP_PKT: Dropping tcp session 10.34.200.10:35684 10.34.255.1:80 on zone-pair ZP-WAN-SELF class class-default due to DROP action found in policy-map with ip ident 17699
WAN default drops rose 45→48 and global DROP action 133→136. The other global error counters stayed unchanged:
Class-map: class-default (match-any)
Drop
48 packets, 2396 bytes
br-edge#show policy-firewall stats drop-counters
DROP action found in policy-map 136
Invalid Segment 36
Stray Segment 10
Invalid Flags 7
Retransmitted Segment with Invalid Flags 2
That tied the new drop increments to the intentional probe while routing remained recovered. A timeout alone would not have supplied that proof.
Self zone rules I follow
- Inventory router endpoints and initiations before attaching a self policy: routing peers, management sources, monitoring, and locally sourced probes.
- Preserve a tested management return path. The NOC /32 made this experiment readable after OSPF disappeared.
- Use explicit pass for OSPF in both governed directions. Do not mistake an accepted inspect command for working inspection.
- Inspect permitted TCP/ICMP initiations where their return traffic needs state. Test from the router as well as toward it.
- Recheck routing when adding the reverse pair. It introduces another restrictive direction and can undo an inbound repair.
- Compare counter deltas alongside neighbor states and session tuples. Keep historical drop totals separate from new failures.
These observations concern Cisco ZBF router traffic on the tested image. Control-plane policing is a separate topic; this run did not test a CoPP change. The ZBF, ASA, and FTD comparison provides the wider firewall context.
Verification checklist
- Record zones and pairs before attaching policy; identify which direction will change.
- Confirm the OSPF network type and both peers' timers. Keep the multicast counterexample separate from the unicast failure.
- Check FULL and BGP's received-prefix count after waiting beyond the lab's dead/hold intervals.
- Verify the peer-loopback route, the management return route, and the advertised prefixes.
- Test NOC→router, router→NOC with an explicit source, and LAN transit separately.
- Read sessions on both self pairs and compare per-class pass/inspect/default-drop counters across two samples.
- Make one deliberate denied probe and correlate its tuple, log, and drop increment.
Related firewall labs
- Zone-based firewall basics — Zones, directional policies, and the original self-zone ping trap.
- ZBF port-maps — Application inspection when services use nonstandard ports.
- ZBF nested class-maps — Layered classification for more specific policies.
- ZBF vs ASA vs FTD — Compare the router firewall with the appliance options.
- Control-plane policing — A separate lab on policing traffic to the router.
- eBGP vs iBGP — How the external and internal BGP session types differ.
- CoPP vs CPPr — The other ways to protect traffic to the router.
FAQ
Why did SSH work after OSPF and BGP went down?
The policy explicitly inspected NOC TCP/22. SSH targeted the connected WAN IP, and the static NOC /32 preserved the return route. That success did not depend on the missing OSPF peer-loopback route.
Should ZBF OSPF use pass or inspect?
Use the pass behavior demonstrated here. IOSv accepted ACL-based OSPF inspect but created no sessions and left the neighbor ATTEMPT. Pass restored it. Once both directions had restrictive self policies, both needed OSPF pass. Cisco's pass action is one-way and creates no session (Cisco ZBF design guide, Cisco ZBF configuration guide), so each restrictive direction needs its own OSPF pass.
Did the self policy also break multicast OSPF?
No. Broadcast-network multicast OSPF survived the earlier attached policy on this IOSv. The complete OSPF outage required NON_BROADCAST unicast neighbors. This run does not prove multicast safety on other images or configurations.
Why did inbound ping recover before router-originated ping?
The inbound ICMP class allowed NOC echo requests. It did not allow the echo replies needed by a router-originated request. Inspecting the permitted outbound echo in self→WAN created the return state; the final session showed request and response bytes. Cisco documents this exact behavior (Cisco ZBF design guide, Control Access to the Router).
Which protocols can a ZBF self zone policy inspect?
Cisco limits self-zone inspection to TCP, UDP, ICMP and H.323, with no application inspection (Cisco ZBF design guide, Self-Zone Policy Limitations). That's why IOSv rejected SSH application inspection here, and why OSPF, IP protocol 89, needs pass.
Does a zone-pair to self also block the router's own traffic?
Yes, for return traffic. Cisco documents that with only a zone-to-self policy, replies to router-originated traffic hit that policy and are blocked, so router-originated traffic must be inspected in a self-to-zone pair (Cisco ZBF design guide, Control Access to the Router).