IOS Control Plane Protection for DoS Mitigation

By stretch | Thursday, October 1, 2009 at 8:22 a.m. UTC

IOS control plane protection is an extension of control plane policing (CoPP) introduced in 12.4(4)T which allows an administrator to apply a quality of service (QoS) policy to a router's control plane. The control plane handles all traffic which must be processed by the router in software.

A policy can be applied to the control plane generally, as with legacy CoPP, or it can be applied to one of the three control plane "subinterfaces:"

  • Host - Traffic destined for the router itself (management, routing protocols, etc.)
  • Transit - Software-switched transit traffic
  • CEF exception - Traffic which triggers a CEF exception (ARP, non-IP packets, etc.)

To illustrate the benefits of configuring control plane protection, we can observe what happens when an unprotected router is targeted by a primitive denial of service (DoS) attack. We can initiate a primitive DoS against a router at by initiating a UDP flood:

Attacker$ 1234 64 0

UDP packets are flooded at or near line rate with the intention of overwhleming the recipient. Since these packets are destined for the router itself, each gets punted from hardware to software prcoessing, consuming expensive CPU and memory resources. With no countermeasures in place, the router's processing power is quickly consumed:

Router# show processes cpu sorted
CPU utilization for five seconds: 100%/28%; one minute: 76%; five minutes: 25%
 PID Runtime(ms)     Invoked      uSecs   5Sec   1Min   5Min TTY Process
  29       85468         295     289722 71.30% 52.46% 16.90%   0 Net Background
   4        2136         118      18101  0.42%  0.35%  0.28%   0 Check heaps
   2          24          50        480  0.08%  0.02%  0.00%   0 Load Meter
  56          12        4131          2  0.08%  0.01%  0.00%   0 Dot11 driver
  80         848         185       4583  0.08%  0.20%  0.07%   0 IP Input
   1           4          11        363  0.00%  0.00%  0.00%   0 Chunk Manager

To mitigate this, we can apply control plane protection. A CoPP policy is configured via the modular QoS CLI (MQC) as with any regular QoS policy, and applied akin to a normal interface service policy. To keep things simple, we'll create a policy which just polices inbound UDP traffic to 16 Kbps:

class-map match-all UDP
 match access-group name UDP
policy-map CoPP
 class UDP
  police 16000 conform-action transmit exceed-action drop violate-action drop
ip access-list extended UDP
 permit udp any any

Finally we apply the service policy to the control plane. In this example, it is applied to the aggregate rather than to a subinterface:

R1(config)# control-plane ?
  cef-exception  Cef-exception traffic control-plane configuration
  host           Host traffic control-plane configuration
  transit        Transit traffic control-plane configuration

R1(config)# control-plane
R1(config-cp-host)# service-policy input CoPP
%CP-5-FEATURE: Control-plane Policing feature enabled on Control plane aggregate path

We can relaunch our UDP flood and compare the CPU utilization to what we saw without CoPP:

Router#show processes cpu sorted
CPU utilization for five seconds: 100%/97%; one minute: 53%; five minutes: 32%
 PID Runtime(ms)     Invoked      uSecs   5Sec   1Min   5Min TTY Process
  55       13492        2055       6565  0.32%  0.08%  0.02%   0 COLLECT STAT COU
   1           4          12        333  0.00%  0.00%  0.00%   0 Chunk Manager  
   2         968          83      11662  0.00%  0.00%  0.00%   0 Load Meter     
   4        3932         206      19087  0.00%  0.60%  0.49%   0 Check heaps    
   5           0           1          0  0.00%  0.00%  0.00%   0 Pool Manager   
   6           0           2          0  0.00%  0.00%  0.00%   0 Timers    

That's probably not what you expected: CPU utilization actually appears to have gone up! What happened? Before moving any further, let's verify that our CoPP policy is indeed performing as expected:

Router# show policy-map control-plane
 Control Plane

Service-policy input: CoPP

Class-map: UDP (match-all)
      6918133 packets, 733322098 bytes
      5 minute offered rate 16552000 bps, drop rate 16551000 bps
      Match: access-group name UDP
          cir 16000 bps, bc 1500 bytes, be 1500 bytes
        conformed 1575 packets, 166950 bytes; actions:
        exceeded 14 packets, 1484 bytes; actions:
        violated 6921762 packets, 733706772 bytes; actions:
        conformed 18000 bps, exceed 0 bps, violate 74591000 bps

Class-map: class-default (match-any)
      2 packets, 120 bytes
      5 minute offered rate 0 bps, drop rate 0 bps
      Match: any

Yep, our CoPP policy is policing at merely 16 Kbps inbound, and discarding all other malicious traffic. What gives?

The five-second CPU statistics listed at the beginning of the show processes cpu outputs is composed of two numbers: total utilization and utilization resulting from hardware interrupt requests. In our first report, interrupt utilization accounted for only around 30% of the total CPU utilization, whereas it now accounts for nearly all of it. Conversely, the first report showed the "Net Background" process (responsible for buffer allocation on newer IOS versions) consuming over 70% CPU utilization while the same process's utilization on the second output is negligible (it's not even listed in the top few).

What we've witnessed here is a shift from process-heavy computation to interrupt-heavy computation. Unfortunately, depending on the platform, this can be just as bad. Testing this on an 1811W I noticed that the terminal felt just as sluggish under 100% load with or without CoPP. Fortunately, once the load has been pushed back to the interrupt level, you can adjust the process scheduler allocation to give software processes a little more breathing room.

Scheduler allocation is defined as a proprotion of interrupt run time to process run time; for most platforms, 4000 ┬Ásec of interrupt time is allowed for merely 200 ┬Ásec of process time (according to the documentation). Older platforms might be limited to the scheduler interval command. Sensible scheduler allocation is a hairy topic in itself, but the permitted ranges offer some idea of the intended ratio:

Router(config)# scheduler allocate ?
  <3000-60000>  Microseconds handling network interrupts

Router(config)# scheduler allocate 8000 ?
  <1000-8000>  Microseconds running processes

Router(config)# scheduler allocate 8000 1000

An allocation of 8000/1000 worked well to put the spring back into the console of my 1800 series while it was being beaten to death with UDP. I have not experimented with the impact of this allocation on actual throughput. Your mileage may vary.

About the Author

Jeremy Stretch is a network engineer living in the Raleigh-Durham, North Carolina area. He is known for his blog and cheat sheets here at Packet Life. You can reach him by email or follow him on Twitter.


October 1, 2009 at 8:30 a.m. UTC

Great Article Stretch!

shivlu jain (guest)
October 1, 2009 at 12:53 p.m. UTC

Thanks for posting such a great article.

October 1, 2009 at 1:54 p.m. UTC

Pretty interesting stuff man. Good work!

mellowd (guest)
October 1, 2009 at 4:28 p.m. UTC

Interesting. I've played a bit with CoPP but didn't know this.

Where can you find the defaults for the scheduler for each platform? Also, how does this change affect the regular running of the router in other tasks?

wad (guest)
October 1, 2009 at 7:26 p.m. UTC

very useful and interesting article as your usual man and your site is very perfect after changes Thanks for your value information.

Roland Dobbins (guest)
October 2, 2009 at 1:35 a.m. UTC

CoPP & CoPr are pretty much a wash on software-based platforms, as all T-train routers are - you've just one CPU in the box, and there's little in the way of order-of-operations processing benefits to be gained.

CoPP (and CoPr, if it's ever ported) on hardware-based platforms makes much more sense, as you're now offloading the classification and evalution from the route processor to specialized hardware.

But I wouldn't bother with it on software-based routers - iACLs, uRPF, vty ACLs, and SNMP ACLs get you the most bang for the buck on those smaller boxes.

ron (guest)
October 2, 2009 at 10:06 p.m. UTC

I use CoPP on my 871's. CoPP also standardizes management-plane access lists across multiple routers, so they are not everywhere (vty, console, iACL). I permit the traffic on both exceed and violate actions for the policy-maps.

Roy Waterman (guest)
December 1, 2009 at 5:28 p.m. UTC

Hi Jeremy

My knowledge of control plane protection is somewhat limited, but it looks like you've configured CoPP (control plane policing) rather than control plane protection.

Your config shows: R1(config)# control-plane

As you didnt specify one of the subinterfaces, it looks like you have applied the service policy to the aggregate control plane interface.

Did you mean to configure the following?

R1(config)# control-plane host

Again, I am still in process of learning copp so I may well be incorrect.

December 1, 2009 at 6:07 p.m. UTC

@Roy: There's no practical difference in the terms. Cisco renamed control plane policing as control plane protection to better convey its potential defensive posturing.

November 16, 2010 at 11:05 a.m. UTC

i have trouble with this udp flood (torrents) can i do something like CoPP on catalyst3560 with IOS 12.2(25)SEE1 C3560-ADVIPSERVICESK ?

Brandon (guest)
December 11, 2015 at 6:13 p.m. UTC

@Ellion -

You can apply similar policy to your VLANs on the 3560. For example, in the configuration context of "interface vlan 1" you have the option to apply a "service-policy" in the same manner he has applied one to the "control-plane."

I hope this helps!

Comments have closed for this article due to its age.