Category: QoS

Challenge: CB-WFQ Bandwidth+Police behavior

I have to admit I was somewhat surprised by the lab test results I’ve published in my previous CB-WFQ post. It looks like we’ve been fed misleading information about (classic) CB-WFQ behavior for years.

Don’t tell me that things are completely different with HQF implemented in IOS releases 12.4(late)T and 15.0. I know that … but 95+% of the installed base do not use those releases.

Let’s see whether you can figure out what my next lab test results showed. I’ve been running three parallel TTCP sessions on ports 5001, 5002 and 5003 across a 256 kbit point-to-point link. Here’s the relevant part of my router configuration:

read more see 11 comments

CB-WFQ misconceptions

Reading various documents describing Class-Based Weighted-Fair-Queueing (CB-WFQ) one gets the impression that the following configuration …

class-map match-all High
match access-group name High
!
policy-map WAN
class High
bandwidth percent 50
!
interface Serial0/1/0
bandwidth 256
service-policy output WAN
!
ip access-list extended High
permit ip any host 10.0.3.1
permit ip host 10.0.3.1 any

… allocates 128 kbps to the traffic to/from IP host 10.0.3.1 and distributes the remaining 128 kbps fairly between conversations in the default class.

I am overly familiar with weighted fair queuing (I was developing QoS training for Cisco when WFQ just left the drawing board) and was thus always wondering how they manage to implement that behavior with WFQ structures. A comment made by Petr Lapukhov re-triggered my curiosity and prompted me to do some actual lab tests.

The answer is simple: CB-WFQ does not work as advertised.

read more see 29 comments

Netflix summary

Many thanks to those of you that responded with Netflix details (special thanks to Volcker for sending me the packet capture). Immediately after someone mentioned firewalls, I knew what the most sensible answer should be: to get across almost anything, use HTTP. No surprise, Netflix chose to use it. However, they’ve managed to deploy streaming video over TCP, which is not a trivial task. So, how did they do it?

read more see 2 comments

Zone-based Traffic Policing

The zone-based firewall uses security policy-maps to specify how the flows between zones should be handled based on their traffic classes. The obvious actions that you can use in the security policy are pass, drop and inspect, but there’s also the police action and one of the readers sent me an interesting question: “why would you need the police action in the security policy if you already have QoS policing”.

read more see 2 comments

Rate-limiting Inbound Traffic on DSL

Julian is faced with an interesting challenge:

In the real world, many customers using DSL solutions have their Internet connection disrupted by one internal user performing a large download. On a typical DSL solution, implementing quality of service on outbound traffic is trivial (you can use PQ, CBWFQ, policing or shaping). However, how does one rate-limit inbound traffic in a sensible fashion? Turnkey solutions like packeteer allow inbound classes of traffic like HTTP to be rate limited per flow by dynamically changing window sizes.

Cisco IOS has three basic QoS mechanisms: queuing, shaping and policing. It cannot intercept a TCP session and slow it down by reducing its window size (like PacketShaper).

read more see 5 comments

ADSL overhead

Yesterday I’ve described the difference between line rate and bit rate (actually physical layer gross bit rate and physical layer net bit rate). Going to the other extreme, we can measure goodput (application-level throughput), which obviously depends on multiple factors, including the TCP window sizes and end-to-end delays. There are numerous tools to test the goodput from/to various locations throughout the world (speedtest.net worked quite nicely for me) and you’ll soon discover that the goodput on your DSL line differs significantly from what the ISP is advertising.

read more see 10 comments

Bandwidth allocation with class-based weighted fair queuing (CB-WFQ)

Sebastian sent me an interesting question:

I have read that we can only use 75% of the bandwidth for the custom queues as 25% is reserved for the keepalives and routing protocol updates. If I want to set 50% of bandwidth for a particular queue should it 50% of the total bandwidth or 50% of the available 75% of the bandwidth?

Before going into the details, it’s important to remember that the WFQ (CB-WFQ is only a mechanism to sort packets into output queues) uses relative ratios (percentages) between queues to determine which packet to send (the absolute bandwidths are used just to compute the ratios).

read more see 7 comments

Interactions between IP routing and QoS

One of my readers sent me an interesting question a while ago:

I reviewed one of your blog posts "Per-Destination or Per Packet CEF Load Sharing?" and wondered if you had investigated previously on how MQC QoS worked together with the CEF load-sharing algorithm (or does it interact at all)? For example, let's say I have two equal cost paths between two routers and the routing table (as well as CEF) sees both links as equal paths to the networks behind each router. On each link I have the same outbound service policy applied with a simple LLQ, BW, and a class-default queues. Does CEF check each IP flow and make sure both link's LLQ and BW queues are evenly used?

Unfortunately, packet forwarding and QoS are completely uncoupled in Cisco IOS. CEF performs its load balancing algorithm purely on source/destination information and does not take in account the actual utilization of outbound interfaces. If you have bad luck, most of the traffic ends on one of the links and the packets that would easily fit on the other link will be dropped by the QoS mechanisms.

You could use multilink PPP to solve the problem in low-speed environments. With MLPPP, CEF sends the traffic to a single output interface (the Multilink interface) and the queuing mechanisms evenly distribute packet fragments across the links in the bundle.

In high-speed environments, you can only hope that the number of traffic flows traversing the links will be so high that you’ll get a good statistical distribution (which is usually the case).

see 3 comments

This is QoS; Who Cares about Real-Time Response?

It all started with a innocuous question: can you detect voice traffic with EEM? Looks simple enough: create a QoS class-map that matches voice calls and read the cbQosClassMapStats table in the CISCO-CLASS-BASED-QOS-MIB. The first obstacle was finding the correct indexes, but a Tcl script quickly solved that; I was ready to create the EEM applet. The applet failed to work correctly and after lots of debugging I figured out the counters in the cbQosClassMapStats table change only every 10 seconds.

I couldn’t believe my eyes and simply had to test other MIB variables as well. As expected, the IF-MIB (standard interface MIB) counters increase in real-time, but obviously someone had the bright idea that we need to detect changes in traffic profile only every now and then. Although I've received numerous suggestions from my readers, none of them works on a Cisco 1800 or a Cisco 7200. Oh, well, Cisco developers from the days when I started working with routers would have known better…

read more see 14 comments

The most convoluted MIB I’ve seen

Jared Valentine sent me a really interesting problem: he would like to detect voice traffic and start shaping TCP traffic for the duration of the voice call. The ideal solution would be an EEM applet reacting to the changes in the CISCO-CLASS-BASED-QOS-MIB; one of its tables contains the amount of traffic for each class configured in a service policy.

The MIB navigation looks simple: you just read the values from the cbQosClassMapStats table, indexed by policy ID and class ID. The real problem is finding the correct index values. I could walk the MIB manually with a MIB browser or snmp_getnext TCL calls, but this approach is obviously not scalable, so I wrote a script that walks through the cbQosServicePolicy, cbQosObjects, cbQosPolicyMapCfg and cbQosClassMapCfg tables and prints the index values you need.

The following text written by Ivan Pepelnjak in 2008 was originally published on CT3 wiki. That web site became unreachable in early 2019. We retrieved the original text from the Internet Archive, cleaned it up, updated it with recent information if necessary, and republished it on ipSpace.net blog on November 17, 2020

This script traverses the Class-based QoS MIB and displays service policies and classes attached to individual interfaces. The policy index and class index values are printed next to the policy/class name to help the operator fetch the desired SNMP variable from the statistics tables of the CISCO-CLASS-BASED-QOS-MIB.

Installation

  • Download the source file into flash:cbindex.tcl
  • Configure alias exec cbindex tclsh flash:cbindex.tcl
  • Configure persistent CBQoS indexes with the snmp mib persist cbqos (otherwise the indexes will change after the router reload).

Usage guidelines

Usage: cbindex community

Command line parameters:

  • Community: SNMP community with R/O access to the CISCO-CLASS-BASED-QOS-MIB

Source code

#
# title:    Displays MQC class map indexes
# name:     cbindex.tcl
# desc:     The script traverses the Class-based QoS MIB and
#           displays service policies and classes attached to 
#           individual interfaces. The policy index and class
#           index values are printed next to the policy/class
#           name to help the operator fetch the desired SNMP 
#           variable from the statistics tables of the 
#           CISCO-CLASS-BASED-QOS-MIB.
#

proc snmpInit { oid } {
  global snmpCommunity
  set getResult [ snmp_getnext $snmpCommunity $oid ]
  if { [ regexp {snmp error} $getResult ] } { 
    puts "SNMP calls with community $snmpCommunity fail"; return 0 
  }
  if { [ regexp {oid='(.*)'} $getResult ignore nxtoid ] } {
    if { [string first $oid $nxtoid] == 0 } { return 1 }
  }
  puts "MIB $oid not implemented in this IOS release"; return 0;
}
  
proc snmpGet { oid result } {
  global snmpCommunity
  upvar $result r
  if { [info exists r] } { unset r }

  set getResult [ snmp_getone $snmpCommunity $oid ]
  if { [ regexp {snmp error.*text='(.*)'} $getResult ignore errtxt ] } { 
    error "snmpGet - $errtxt"; return 0 
  }
  if { [ regexp {oid='(.*)'.*val='(.*)'} $getResult ignore oid result ] } {
    if { ! [ string equal $result "NO_SUCH_INSTANCE_EXCEPTION" ] } {
      set r(OID) $oid ;
      set r(VALUE) $result ; 
      return 1;
    }
  }
  return 0;
}

proc snmpGetNext { oid result } {
  global snmpCommunity
  upvar $result r
  if { [info exists r] } { unset r }

  set getResult [ snmp_getnext $snmpCommunity $oid ]
  if { [ regexp {snmp error.*text='(.*)'} $getResult ignore errtxt ] } { 
    error "snmpGet - $errtxt"; return 0 
  }
  if { [ regexp {oid='(.*)'.*val='(.*)'} $getResult ignore oid result ] } {
    if { ! [ string equal $result "NO_SUCH_INSTANCE_EXCEPTION" ] } {
      set r(OID) $oid ;
      set r(VALUE) $result ;
      set oidSplit [ split $oid "." ]
      set r(NAME)  [ lindex $oidSplit 0 ]
      set r(INDEX) [ lreplace $oidSplit 0 0 ]
      set r(IDXLIST) [ join $r(INDEX) "." ]
      return 1;
    }
  }
  return 0;
}

proc snmpGetInTable { oid result { parentoid "" }} {
  global snmpCommunity
  upvar $result r

  snmpGetNext $oid r
  if { ! [info exists r(OID)] } { return 0 }
  if { [string equal $parentoid ""] } {
    set oidSplit [ split $oid "." ]
    set parentoid [lindex $oidSplit 0]
  }
  if { [string first $parentoid $r(OID)] != 0 } { return 0 }
  return 1;
}

proc printQosClassIndex {} {
  global snmpCommunity
  set oid "cbQosIfIndex"
  array set dirLookup { 1 in 2 out }
  set cnt 0
  while { [ snmpGetInTable $oid svcPolicy ] } {
    if { [snmpGet "ifDescr.$svcPolicy(VALUE)" ifDescr] } {
      snmpGet "cbQosPolicyDirection.$svcPolicy(INDEX)" svcDirection
      snmpGetNext "cbQosConfigIndex.$svcPolicy(INDEX)" policyObject
      snmpGet "cbQosPolicyMapName.$policyObject(VALUE)" policyName
      puts "\n$ifDescr(VALUE) ($dirLookup($svcDirection(VALUE))): $policyName(VALUE) ($svcPolicy(INDEX))"
      set coid "cbQosObjectsType.$svcPolicy(INDEX)"
      set parentoid $coid
      while { [ snmpGetInTable $coid svcClass $parentoid ] } {
        if { $svcClass(VALUE) == 2 } {
          snmpGet "cbQosConfigIndex.$svcClass(IDXLIST)" svcClassConfig
          snmpGet "cbQosCMName.$svcClassConfig(VALUE)" svcClassName
          puts "  $svcClassName(VALUE) $svcClass(IDXLIST)"
        }
        set coid $svcClass(OID)
      }
    } else { error "Cannot get interface name for service policy $svcPolicy(VALUE)" }
    set oid $svcPolicy(OID)
  }
}

set snmpCommunity [lindex $argv 0]
if { [string equal $snmpCommunity ""] } { set snmpCommunity "public" }
if { ! [ snmpInit "cbQosObjectsType" ] } return
printQosClassIndex

Sample usage scenario

The following QoS classes and policies have been configured on the router:

class-map match-all Mail
 match protocol smtp
!
class-map match-all Web
 match protocol http
!
class-map match-all SecureWeb
 match protocol secure-http
!
class-map match-any Surfing
 match class-map Web
 match class-map SecureWeb
!
class-map match-all Files
 match protocol ftp
!
policy-map Internet
 class Web
    bandwidth 128
 class SecureWeb
    priority 64
 class Mail
    bandwidth 32
!
policy-map MailOrFtp
 class Mail
  set ip precedence 0
 class Files
  set ip precedence 0
 class Surfing
    police 16000
 class class-default
   police cir 8000
     exceed-action drop 
!
interface Serial1/0
 service-policy input MailOrFtp
 service-policy output Internet
!
interface Serial1/1
 service-policy output MailOrFtp

The cbindex script reported the following SNMP indexes:

c7200#cbindex Test

Serial1/0 (in): MailOrFtp (48)
  Web 48.383777
  Surfing 48.1970017
  Mail 48.4297921
  Files 48.13110129
  class-default 48.14779377
  SecureWeb 48.15077857

Serial1/0 (out): Internet (50)
  Mail 50.10516033
  Web 50.14007809
  SecureWeb 50.14520625
  class-default 50.15008753

Serial1/1 (out): MailOrFtp (66)
  Web 66.383777
  Surfing 66.1584993
  Files 66.4236097
  Mail 66.11615889
  SecureWeb 66.15077857
  class-default 66.15082481

Based on these indexes, you could monitor the bit rate of the Web class in outbound policy configured on Serial 1/1 with SNMP variable cbQosCMPrePolicyBitRate.66.383777.

c7200#tclsh
c7200(tcl)#snmp_getone Test cbQosCMPrePolicyBitRate.66.383777
{<obj oid='cbQosCMPrePolicyBitRate.66.383777' val='0'/>}
see 3 comments

MPLS QoS: Implementing the best model for guaranteed service

My MPLS QoS: Implementing the best model for guaranteed service article published by SearchTelecom gives you a high-level overview of the pipe and hose QoS models in the MPLS VPN environment. I’m also describing basic DiffServ QoS mechanisms available in an MPLS backbone.

If you’re new to IP QoS, you should start with the IP QoS: Two generations of class-of-service tools article.

add comment

Interesting links | 2008-11-08

As always, Jeremy Stretch posted several interesting articles: how to hijack HSRP, introduction to split horizon in distance vector routing protocols and (long needed) default redistribution metrics.

Petr Lapukhov started playing with HTTP URL regular expressions within NBAR and documented his findings. The most interesting is the last Q/A pair: can I use NBAR as a content filtering engine?

And last but definitely not least, if you’re worried what will happen to WPA2 now that WPA has been cracked, Robert Graham explains the fundamental differences between WPA and WPA2. Also, make sure you read the detailed explanation of the WPA flaw to understand its implications.

see 2 comments

QoS Policing in Cisco IOS

Policing implementations in Cisco IOS are a bit confusing: IOS supports three different algorithms that are configured with very similar parameters of the police command in modular QoS CLI. There's also the older rate-limit command that uses a limited implementation of one of the three algorithms. You'll find all policing details, including the graphic representations of all three algorithms in the QoS Policing in Cisco IOS article.

see 3 comments
Sidebar