Skip to content
Log in Sign up My account

5.2 ACLs and Control Plane Policing

Blueprint 5.2: Configure and verify infrastructure security features

  • 5.2.a ACLs
  • 5.2.b CoPP

Infrastructure security protects the network devices themselves and controls what passes through them. ACLs are the basic tool for both. CoPP reuses ACLs inside the Modular QoS CLI (MQC) to protect the route processor from being overwhelmed. Expect configuration exhibits where you must work out which host gets through, plus a lab item where you build an ACL or a CoPP policy and prove it works.

ACL types

Type Matches on Numbers Named form Place it
Standard Source IPv4 address only 1 to 99, 1300 to 1999 ip access-list standard NAME Close to the destination
Extended Protocol, source, destination, ports, flags, DSCP and more 100 to 199, 2000 to 2699 ip access-list extended NAME Close to the source
IPv6 Like extended, IPv6 only. Always named none ipv6 access-list NAME Close to the source

Named ACLs are the better habit: the name documents the purpose, and you can insert or delete individual entries by sequence number. Numbered ACLs entered in global configuration can also be edited by sequence number in current releases, through ip access-list extended 101 for example.

Wildcard masks

A wildcard mask has a 0 where the bit must match and a 1 where any value is allowed. For a contiguous mask, the wildcard is 255.255.255.255 minus the subnet mask.

Need to match Address and wildcard Keyword form
One host 10.1.1.10 0.0.0.0 host 10.1.1.10
Everything 0.0.0.0 255.255.255.255 any
10.1.1.0/24 10.1.1.0 0.0.0.255
172.16.32.0/20 (172.16.32.0 to 172.16.47.255) 172.16.32.0 0.0.15.255
10.1.1.0/30 10.1.1.0 0.0.0.3
Odd-numbered hosts in 10.1.1.0/24 10.1.1.1 0.0.0.254 (non-contiguous, valid in ACLs)

How an ACL is processed

  1. Entries are checked from the lowest sequence number up.
  2. The first match decides. Nothing after it is checked.
  3. If nothing matches, the implicit deny at the end drops the packet. It never appears in show access-lists and never counts matches, so add an explicit deny ip any any log if you want to see what it drops.
  4. One ACL per interface, per direction, per protocol (one IPv4 inbound, one IPv4 outbound, one IPv6 inbound, one IPv6 outbound).
graph TB
  P["Packet arrives on Gi1"] --> Q{"Inbound ACL on Gi1?"}
  Q -- "no" --> RT["Route lookup"]
  Q -- "yes" --> E1{"Entry 10 matches?"}
  E1 -- "yes" --> ACT1["Apply its permit or deny, stop"]
  E1 -- "no" --> E2{"Entry 20 matches?"}
  E2 -- "yes" --> ACT2["Apply its permit or deny, stop"]
  E2 -- "no" --> IMP["Implicit deny any"]
  ACT1 --> RT
  RT --> O{"Outbound ACL on exit interface?"}
  O -- "permit or none" --> OUT["Forward"]
  O -- "deny" --> DROP["Drop"]

Exam trap

An outbound ACL does not filter packets the router generates itself (routing updates, pings sourced by the router, syslog). It filters only traffic routed through the router and out that interface. If an exhibit shows ip access-group X out and asks whether the router's own ping is blocked, the answer is no.

Exam trap

Applying an ACL name that does not exist yet (ip access-group NOT-YET in) does not block anything on IOS: an undefined IPv4 ACL on an interface permits all traffic. The moment you create the ACL with a single entry, the implicit deny takes effect. Build the ACL first, apply it second, and always end with the permit you need.

Extended ACL syntax

{permit | deny} protocol source source-wildcard [operator port]
               destination destination-wildcard [operator port]
               [established] [dscp value] [log | log-input]
Operator Meaning Example
eq Equal to eq 443 or eq www
neq Not equal neq 23
lt / gt Less than / greater than gt 1023
range Inclusive range range 20 21
  • The source port sits after the source address and the destination port after the destination address. Putting eq 80 after the source when you meant the destination is a classic mistake: it then matches packets from port 80, which is web replies, not requests.
  • established matches TCP segments with the ACK or RST bit set. It lets return traffic of sessions started from inside come back in, without a stateful firewall.
  • log sends a syslog message for matches. Messages are rate-limited and summarised, so they are not a packet capture. log-input adds the input interface and source MAC.

Building and editing a named ACL

ip access-list extended EDGE-IN
 10 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 443
 20 permit udp 10.10.10.0 0.0.0.255 host 172.16.1.53 eq domain
 30 permit icmp 10.10.10.0 0.0.0.255 any echo
 40 deny ip 10.10.10.0 0.0.0.255 172.16.1.0 0.0.0.255 log
 50 permit ip 10.10.10.0 0.0.0.255 any
!
interface GigabitEthernet2
 ip access-group EDGE-IN in
!
! Insert a rule between 10 and 20, then remove one
ip access-list extended EDGE-IN
 15 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 22
 no 30
!
ip access-list resequence EDGE-IN 10 10
ip access-list standard BLOCK-GUEST
 10 deny 10.20.0.0 0.0.255.255
 20 permit any
interface GigabitEthernet3
 ip access-group BLOCK-GUEST out
ip access-list standard MGMT-ONLY
 permit 192.168.100.0 0.0.0.255
line vty 0 15
 access-class MGMT-ONLY in
ipv6 access-list V6-EDGE-IN
 permit tcp 2001:db8:10::/64 host 2001:db8:172::10 eq 443
 deny ipv6 2001:db8:10::/64 2001:db8:172::/64 log
 permit ipv6 any any
interface GigabitEthernet2
 ipv6 traffic-filter V6-EDGE-IN in

IPv6 ACLs are applied with ipv6 traffic-filter, not ip access-group. Before their implicit deny ipv6 any any, they also have implicit permits for neighbor solicitation and neighbor advertisement so that neighbor discovery keeps working. An explicit deny ipv6 any any at the end removes that protection.

Exam trap

A standard ACL that only has deny entries blocks everything, because of the implicit deny. access-list 10 deny host 10.1.1.5 applied to an interface stops all IPv4 traffic, not only 10.1.1.5. You need access-list 10 permit any after it.

Verifying ACLs

R1# show access-lists EDGE-IN
Extended IP access list EDGE-IN
    10 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 443 (1284 matches)
    15 permit tcp 10.10.10.0 0.0.0.255 host 172.16.1.10 eq 22 (37 matches)
    20 permit udp 10.10.10.0 0.0.0.255 host 172.16.1.53 eq domain (412 matches)
    40 deny ip 10.10.10.0 0.0.0.255 172.16.1.0 0.0.0.255 log (9 matches)
    50 permit ip 10.10.10.0 0.0.0.255 any (20311 matches)
R1# show ip interface GigabitEthernet2 | include access list
  Outgoing access list is not set
  Inbound  access list is EDGE-IN
R1# clear ip access-list counters EDGE-IN

The match counters are your best troubleshooting tool. Generate the traffic, then see which line the counter moves on. If a line you expect never moves, an earlier line is catching the traffic or the ACL is applied in the wrong place or direction.

Control Plane Policing (CoPP)

A router has three planes:

Plane What it handles Example traffic
Data (forwarding) Transit packets, switched in hardware or CEF User traffic passing through
Control Packets addressed to or punted to the route processor OSPF, BGP, ARP, HSRP, ICMP to the router, TTL-expired packets
Management Traffic used to manage the box SSH, SNMP, NETCONF, syslog

The route processor CPU handles everything that is not simply forwarded. A flood of pings or SSH connection attempts aimed at the router can starve the CPU so that routing protocol hellos are missed and adjacencies drop. CoPP is a QoS policy attached to the control plane that rate-limits each kind of traffic before it reaches the CPU.

graph LR
  IN["Incoming packets"] --> FW{"Destined to<br/>the router?"}
  FW -- "no: transit" --> HW["Forwarded, CoPP not involved"]
  FW -- "yes or punted" --> CP["control-plane<br/>service-policy input COPP"]
  CP --> C1["CM-ROUTING<br/>OSPF, BGP: generous"]
  CP --> C2["CM-MGMT<br/>SSH, SNMP: moderate"]
  CP --> C3["CM-ICMP<br/>low rate"]
  CP --> C4["CM-UNDESIRABLE<br/>drop"]
  CP --> C5["class-default<br/>low rate"]
  C1 & C2 & C3 & C5 --> CPU["Route processor"]

Building a CoPP policy

CoPP uses the same three MQC steps as QoS: classify with class-maps, act with a policy-map, attach with service-policy. The difference is where it is attached.

! 1. ACLs select traffic. permit = "belongs to this class"
ip access-list extended COPP-ROUTING
 permit ospf any any
 permit tcp any any eq bgp
 permit tcp any eq bgp any
ip access-list extended COPP-MGMT
 permit tcp 192.168.100.0 0.0.0.255 any eq 22
 permit udp 192.168.100.0 0.0.0.255 any eq snmp
ip access-list extended COPP-ICMP
 permit icmp any any
ip access-list extended COPP-UNDESIRABLE
 permit tcp any any eq telnet
 permit udp any any eq tftp
!
! 2. Class-maps
class-map match-all CM-ROUTING
 match access-group name COPP-ROUTING
class-map match-all CM-MGMT
 match access-group name COPP-MGMT
class-map match-all CM-ICMP
 match access-group name COPP-ICMP
class-map match-all CM-UNDESIRABLE
 match access-group name COPP-UNDESIRABLE
!
! 3. Policy-map. Rates are in bits per second
policy-map COPP
 class CM-UNDESIRABLE
  drop
 class CM-ROUTING
  police 1000000 conform-action transmit exceed-action transmit
 class CM-MGMT
  police 512000 conform-action transmit exceed-action drop
 class CM-ICMP
  police 32000 conform-action transmit exceed-action drop
 class class-default
  police 64000 conform-action transmit exceed-action drop
!
! 4. Attach to the control plane
control-plane
 service-policy input COPP

Design notes:

  • Routing protocol traffic is matched first and usually never dropped. Here it is policed with exceed-action transmit, which only measures it. That way the counters show if routing traffic ever exceeds the expected rate.
  • Undesirable traffic is dropped outright. Put it near the top so it is caught before broader classes.
  • class-default catches everything else, including ARP on many platforms unless you classify it separately. Police it, but never drop it entirely, or you will break things you forgot about.
  • Start with generous rates and exceed-action transmit to baseline what normal looks like, then tighten.

Exam trap

In a CoPP or QoS class-map, the ACL is only a classifier. A deny entry does not drop the packet; it means "not in this class", and the packet moves on to the next class. To drop traffic, match it with permit and give the class a drop or a policer whose actions drop.

Exam trap

CoPP is attached with service-policy input under control-plane, not on an interface. It only affects traffic to or punted to the route processor. If a question asks how to stop a flood of pings through the router, CoPP is the wrong tool; use an interface ACL or a QoS policer on the interface.

Catalyst 9000 switches

Catalyst 9000 switches ship with a system-defined CoPP policy (system-cpp-policy) that is attached by default. You tune the rates of its predefined classes rather than replacing it with your own policy. Routers such as the Catalyst 8000 series and ISR 4000 use the user-defined control-plane policy shown on this page. Check the configuration guide for your platform before you change CoPP.

Verifying CoPP

R1# show policy-map control-plane
 Control Plane

  Service-policy input: COPP

    Class-map: CM-UNDESIRABLE (match-all)
      24 packets, 1440 bytes
      5 minute offered rate 0000 bps, drop rate 0000 bps
      Match: access-group name COPP-UNDESIRABLE
      drop

    Class-map: CM-ROUTING (match-all)
      5321 packets, 431002 bytes
      5 minute offered rate 2000 bps, drop rate 0000 bps
      Match: access-group name COPP-ROUTING
      police:
          cir 1000000 bps, bc 31250 bytes
        conformed 5321 packets, 431002 bytes; actions:
          transmit
        exceeded 0 packets, 0 bytes; actions:
          transmit

    Class-map: CM-ICMP (match-all)
      18342 packets, 25678800 bytes
      5 minute offered rate 241000 bps, drop rate 209000 bps
      Match: access-group name COPP-ICMP
      police:
          cir 32000 bps, bc 1500 bytes
        conformed 2210 packets, 3094000 bytes; actions:
          transmit
        exceeded 16132 packets, 22584800 bytes; actions:
          drop
    ...

Output is trimmed and the burst values depend on the platform. Read it top to bottom: packets per class, the offered rate, and the conformed and exceeded counters. A ping flood shows up as a high exceeded count in CM-ICMP while CM-ROUTING stays clean, which is exactly what CoPP is for.

Symptom Likely cause
Traffic you expected in a class lands in class-default ACL entry missing, wrong direction of ports, or match-all with conditions that can not all be true
SSH from the NOC is slow or drops under load Management class policed too low, or the NOC subnet is missing from the ACL so it falls to a tight class-default
OSPF or BGP flaps during an attack Routing traffic not classified first and is sharing a class with the flood
Policy configured but counters never move Policy not attached with service-policy input under control-plane

Lab: an ACL and a CoPP policy on R1

Topology: base topology from Lab Setup. R1 (Catalyst 8000v) with Gi2 facing DIST1 and the user VLAN 10.10.10.0/24, Gi1 on the management LAN 192.168.100.0/24 with Host1 at 192.168.100.10. OSPF runs between R1 and R2.

  1. Save a baseline.
  2. Build EDGE-IN from this page so that users can reach 172.16.1.10 (use R2's Loopback, renumbered or added as 172.16.1.10/32) on TCP 443 and 22 only, ping anything, and reach everything outside 172.16.1.0/24. Apply it inbound on R1's user-facing interface.
  3. From a user host, test HTTPS (or telnet 172.16.1.10 443 from an IOSv host) and SSH. Check which counters moved with show access-lists EDGE-IN.
  4. Move the eq 443 from after the destination to after the source on line 10. Test again: HTTPS now fails and line 40 counts. Fix it.
  5. Build the CoPP policy from this page with CM-ICMP policed to 16 kbps. Attach it to the control plane.
  6. From Host1, flood R1: sudo ping -f -s 1400 192.168.100.1 (or from an IOSv host, an extended ping with repeat 10000, size 1400, timeout 0).
  7. Watch show policy-map control-plane class CM-ICMP. Expected: the exceeded counter climbs, most pings fail, and show ip ospf neighbor stays FULL.
  8. Change the CoPP ACL for ICMP from permit icmp any any to deny icmp any any. Repeat the flood. Expected: CM-ICMP stops counting and the pings are now policed by class-default instead. That is the "deny means not this class" behaviour.

Quick check

Which addresses does 172.16.32.0 0.0.15.255 match?

172.16.32.0 to 172.16.47.255, a /20. The 15 in the third octet frees the low four bits, so third octet values 32 to 47 match.

A CoPP policy has no class for SNMP and class-default is policed to 8 kbps. SNMP polling from the NMS times out. Why?

SNMP falls into class-default and shares 8 kbps with everything else that is unclassified. Give SNMP from the NMS its own class with a suitable rate, matched before class-default.

Why does permit tcp any eq 80 any not match a user's web request?

eq 80 after the source matches the source port. A browser's request has destination port 80 and a high source port. The entry would match the server's replies instead.

References

  • Cisco IOS XE Security Configuration Guide: "IP Access List Overview" and "Creating an IP Access List and Applying It to an Interface" (search on cisco.com)
  • Cisco IOS XE QoS Configuration Guide: "Control Plane Policing" (search on cisco.com for your platform)
  • Cisco Guide to Harden Cisco IOS Devices, section on infrastructure ACLs and CoPP (search on cisco.com)
  • RFC 6192: Protecting the Router Control Plane, at rfc-editor.org
  • Cisco Live On-Demand Library: search "control plane protection" and "infrastructure security"