CoPP (Control Plane Policing)
CoPP (Control Plane Policing) is an IOS-XE feature used to protect the control plane from overload conditions which max out the CPU. Control plane packets are packets that are destined to the router, or sourced from the router, and therefore must be processed in hardware. CoPP allows you to apply a QoS-style policy-map to the control plane itself.
CoPP is implemented using the MQC (Modular QoS CLI). For this reason it is useful to have a basic understanding of implementing QoS on IOS-XE. CoPP is essentially just applying a QoS policy to the control plane, instead of applying the policy to an interface. The control plane is basically treated as a virtual interface.
Here are the basic configuration steps:
ip access-list extended name
! permit statements are a "match" statement
! deny statements are a "do not match" statement
!
class-map name
match access-group name acl-name
!
policy-map name
class class-map-name
policy rate [rate or pps] conform-action transmit exceed-action drop
!
control-plane
service-policy input policy-map-name
When applying CoPP policies, you must be careful to not affect routing protocol traffic. BGP, OSPF, etc. traffic counts as control plane traffic. If you accidentally drop these packets, you might have flapping adjacencies.
What about management plane traffic?
Management and control plane traffic are the same thing in the eyes of the CoPP feature. In both cases, the packets are destined to the router itself and are processed by the CPU. When applying a policy-map to the control plane, it will also affect any management plane traffic.
Lab
To demonstrate and test CoPP I connected three CSR1000v routers together in a line. The idea is that R1 should be rate-limited when pinging R2, but not R3. (Pings to R3 go through R2 as data plane traffic).

On R2 we need to define an ACL that matches ICMP traffic and associate it with a class-map. Note that when configuring CoPP, only extended ACLs are supported.
ip access-list extended ICMP-ACL
permit icmp any any
!
class-map ICMP-CLASS-MAP
match access-group name ICMP-ACL
The ACL can simply match any/any src/dst IPs because it is only inspected at the control plane level. Any data plane traffic is switched in hardware and will not be processed by this ACL anyways. (If you wanted to specifically match traffic destined for 2.2.2.2/32, you might think you would use permit icmp any host 2.2.2.2. However, in my testing, I’ve found that the logic has to be reversed. Only permit icmp host 2.2.2.2 any matches traffic destined for 2.2.2.2/32. I’m not exactly sure why this is, but be aware of this.)
Next we define our policy-map where we set our policing rates. Let’s limit pings to the minimum bps of 8000. Any packets exceeding this rate should be dropped.
policy-map ICMP-POLICY-MAP
class ICMP-CLASS-MAP
police 8000 conform-action transmit exceed-action drop
Finally we apply the policy map to the control plane virtual interface in the input direction.
control-plane
service-policy input ICMP-POLICY-MAP
To verify the policy-map applied to the control plane we can use the following show command:
R2#show policy-map control-plane
Control Plane
Service-policy input: ICMP-POLICY-MAP
Class-map: ICMP-CLASS-MAP (match-all)
0 packets, 0 bytes
5 minute offered rate 0000 bps, drop rate 0000 bps
Match: access-group name ICMP-ACL
police:
cir 8000 bps, bc 1500 bytes
conformed 0 packets, 0 bytes; actions:
transmit
exceeded 0 packets, 0 bytes; actions:
drop
conformed 0000 bps, exceeded 0000 bps
Class-map: class-default (match-any)
11 packets, 374 bytes
5 minute offered rate 0000 bps, drop rate 0000 bps
Match: any
So far no packets have matched the ICMP class map, but 11 packets have matched the class-default class-map. This is our routing protocol traffic, which in my case is OSPF hellos.
Let’s ping from R1 to R2 and see if we experience dropped packets:
R1#ping 2.2.2.2 source lo0 repeat 10 size 1000 timeout 1
Type escape sequence to abort.
Sending 10, 1000-byte ICMP Echos to 2.2.2.2, timeout is 1 seconds:
Packet sent with a source address of 1.1.1.1
!.!.!.!.!.
Success rate is 50 percent (5/10), round-trip min/avg/max = 1/1/4 ms
Every other packet is dropped. This is because I sized the ICMP requests to 1000 bytes which is 8000 bits. The first packet uses up the 8000 bps rate limit on R2. The next packet then is dropped and times out for 1 second. The subsequent packet is good to send and gets a reply, and the process repeats.
We can check the stats on R2:
R2#show policy-map control-plane
Control Plane
Service-policy input: ICMP-POLICY-MAP
Class-map: ICMP-CLASS-MAP (match-all)
10 packets, 10000 bytes
5 minute offered rate 0000 bps, drop rate 0000 bps
Match: access-group name ICMP-ACL
police:
cir 8000 bps, bc 1500 bytes
conformed 5 packets, 5000 bytes; actions:
transmit
exceeded 5 packets, 5000 bytes; actions:
drop
conformed 0000 bps, exceeded 0000 bps
Class-map: class-default (match-any)
81 packets, 2854 bytes
5 minute offered rate 0000 bps, drop rate 0000 bps
Match: any
Let’s ensure that R1 can ping R3:
R1#ping 3.3.3.3 source lo0 repeat 10 size 1000 timeout 1
Type escape sequence to abort.
Sending 10, 1000-byte ICMP Echos to 3.3.3.3, timeout is 1 seconds:
Packet sent with a source address of 1.1.1.1
!!!!!!!!!!
Success rate is 100 percent (10/10), round-trip min/avg/max = 1/1/2 ms
This works because R2 sees this traffic as data plane traffic. It is not processed by the control plane and therefore not subjected to the policer.
Further Reading
https://nwmichl.net/2021/02/03/coping-with-copp-why-icmp-drops-happen/
https://traceroute.home.blog/2018/10/01/control-plane-policing/
This involves a more realistic example of ACLs used to identify critical/important/undesirable traffic.
https://jeffostermiller.blogspot.com/2015/11/modifying-control-plane-policying-to.html
Interesting case study of ARP drops causing EIGRP flaps
Last updated