Don’t Let CBWFQ Recommendations Lead You Astray

by Bill Heller

I wanted to share some thoughts about an element of one of my favorite subjects in QoS (Quality of Service) and that is specifically CBWFQ.

Whenever you see recommendations for setting the values for a queue, you sometimes see a recommendation to set a bandwidth metric for the default-class queue. This drives me crazy. I’d like to explain why I believe this to be an erroneous concept.

In order to understand how CBWFQ (Class-Based Weighted Fair Queuing) works, we have to understand how WFQ (Weighted Fair Queuing) works.

The goal of WFQ was to get over the limitations of Priority Queuing and Custom Queuing. Both of these had the ability to lead to protocol starvation (a protocol or flow not getting enough bandwidth to work at all) and both of them could leave small flows effectively clobbered because of queue dominance by large, high-bandwidth flows.

To start with, WFQ seeks to give every flow its own queue. That way some bandwidth hog doesn’t overwhelm the queue I am sending my data into. That bandwidth hog can now have a queue to itself and overflow that queue without overflowing the queue of the less-bandwidth intensive flows and causing them to lose data.

To this end WFQ has a system for recognizing each and every flow. It takes note of Source IP address, Destination IP address, L3 protocol value (in the IP header) L4 port value and IP Precedence value. It then runs a mathematical formula against these values to come up with a hash value by which it recognizes each of the flows running through it. It then attempts to give each flow its own queue.

NOTE: When I say it “attempts to give each flow its own queue,” it is because there may be more flows going through an interface than the number of queues the interface can build. In this case multiple flows may be assigned to the same queue. It will try to only put flows of the same IPP into a given queue.

The effect of doing the above is that every flow has a queue and every packet which goes into a queue gets a number assigned to it as to the order of service. I like to refer to this as a “Sequence Number.”  Then, the element of WFQ which decides which packet goes next. The “Scheduler” just takes the packet with next (lowest) sequence number (SN).

Pretty easy, right? Well what we get from this is not Weighted Fair Queuing, but rather Fair Queuing.  That’s nice, it’s really nice, but it doesn’t allow me to prioritize some traffic over others. And since one of my favorite definitions of QoS is “Managed Unfairness,” Fair Queuing disappoints us in regard to being able to prejudice the network in favor of some traffic versus others. This is the point at which that the “Weight” in “Weighted Fair Queuing” comes in.

When building the sequence number (SN) for a packet WFQ uses three values. Those values are the Time of arrival in the queue, Size of packet and Metric. The time and size are intended to give value and relevance to the size of a packet so that flows with higher payloads per packet do not necessarily get more data through the queue and so that time of arrival makes a flow with a poor metric still “bubble to the top” of the service list and assure that it does get serviced.

The value that I want to get into is the metric value. The metric value is based upon a concept that the BEST value is a metric of 1, which would imply 100% of the bandwidth, or the very highest possible computation against a packet. The bottom of that scale is 32,768. The formula for the metric assigned to packets is (32,768/((IPP)+1)). The “+1” is necessary because otherwise there would be a multiplier of 0 in the equation for IPP 0 which wouldn’t work out so well.

Here are the IP Precedence metric values used in Weighted Fair Queuing:

0 = 32,768

1 = 16,384

2 = 10,920

3 = 8192

4 = 6552

5 = 5456

6 = 4680

7 = 4096

This is great since it means I can just mark some traffic with a higher IP Precedence (IPP) than others and get it to consistently be treated better. What are the limitations? Well, for one I can’t use all of those values. It turns out that standards forbid me from using IPP 6 and 7 for most enterprise traffic because they are reserved for traffic management traffic (like Routing Protocols).

Okay, so now I’m down to 6 classes of traffic, using IPPs 0-5. Cool. But, what if I have more than 6 classes of traffic to prioritize? With WFQ I have no choice but to classify multiple types of traffic with the same value. If I’m a control freak, well, I don’t like that! And QoS is a technology built for control freaks.

Enter Class-Based Weighted Fair Queuing, or “CBWFQ.” CBWFQ uses all of WFQ except the default metrics based upon IPP. With CBWFQ, you get to set the metric, using a “bandwidth” statement. With CBWFQ, you enter something like “bandwidth 784 (in kbps)” or “bandwidth percent 18.”

What CBWFQ will do is compare your bandwidth statement to the overall bandwidth available. It thinks 1 is 100% of the bandwidth and 32,768 is 0%. If you say “bandwidth percent 50” it gives you a metric for all of the packets flowing through that queue of 16,384, or halfway between 32,768 and 0.

Now I can create up to 64 queues by default with CBWFQ and simply assign them varying bandwidth values and the system will automatically brew up metrics which are relative to each other and to the overall bandwidth value for the interface. Everybody has a value comparative to the bottom metric, 32,768. If my bandwidth statement is “bandwidth percent 25” then my metric is 24,576, because that’s 25% of the way to 1 from 32,768. Easy, right?

The problem is the recommendation I see sometimes suggesting that you always give a minimum value to the default-class in CBWFQ. You see, in configuring a CBWFQ policy-map there is always a queue at the bottom created by default. It is the “default-class” queue. It is the queue into which traffic is classified if it hasn’t been shoveled into the queues mentioned higher in the policy-map. For instance:

Policy-map Ape

Class Gorilla

Bandwidth percent 26

Class Orangutan

Bandwidth percent 17

Class default-class


In this example, all traffic which does not meet the specifications of the “Ape” class or the “Orangutan” class-maps (not shown) just goes into the default-class queue.

What I have done is to specifically figure out how much bandwidth the other two types of traffic need to operate sufficiently for the accomplishment of my business mission. I then told the router how much those types of traffic need. The router automatically brewed up a metric based upon the interface value between 1 and 32,768 and now these two types of traffic have a metric which is relative to the interface and relative to the 0% and 100% bandwidth values (32,768 and 1). I have purposely promoted these two types of traffic over any other traffic.

As I said before, a common recommendation is to assign a bandwidth value to the default-class. This has the concept of assuring that the default-class queue gets a minimum of service. But the problem is, it throws the whole relative formula out-of-whack. The recommendation I’ve seen is to always assign “bandwidth percent 25” to the default-class. What?!

If I assign a 25% bandwidth statement to the default-class then all data going through it will get a metric of 24,576. That means that anything I want to be treated better than the traffic I haven’t classified must now get a better metric, i.e., a better bandwidth statement. Most mechanisms won’t let you identify more than 100% of the bandwidth! So am I forced to do the following?

Policy-map Ape

Class Gorilla

Bandwidth percent 40

Class Orangutan

Bandwidth percent 35

Class default-class

Bandwidth percent 25


The simple answer is…no. Why create a false bottom? The default-class will ALWAYS get service, because the WFQ algorithm includes time and size in the calculation for the packet SNs. Remember, besides getting a metric, these metrics are relative to each other also, in terms of being serviced. I suggest that the proper way to make sure that the default-class gets adequate service is proper design in the first place.

Make sure you calculate how much bandwidth is required by the business-relevant applications and add it together to make sure you have enough bandwidth in the first place. Also, calculate the amount of bandwidth necessary for those unspecified types of traffic which you do want to get through. Then assign bandwidth values relevant to those types of traffic and leave enough of the 100% unclassified and unspecified. That is your “leftovers” allowance. At the end of it all you would have created relative metrics with values relative to what the application requires and relative to the other business-relevant applications in use.

The default-class is meant to be the category which refers to “and everything else.” It’ll get serviced. It has to get serviced based upon the WFQ formula in the first place. It’s just that the more important traffic will be able to “take cuts in line” so to speak. And that’s exactly what we want. That is the reason for QoS. Remember “Managed Unfairness.”

What about that traffic I want to punish and treat worse than the traffic that goes into the default-class? I have a suggestion. Put it in a queue with a policer or a shaper. In this way, that traffic can get through, but only to a limit. That limitation now frees up bandwidth for the classes I have given a bandwidth statement to. Here is an example:

Policy-map Enterprise

Class A

Bandwidth percent 40

Class B

Bandwidth percent 20

Class C

Bandwidth percent 15

Class D

Bandwidth percent 10

Class Scavenger

Shape percent 3

(Class-default) – no statement. The metric will be 32,768 but there will be no upper limit on throughput

In this way, the bandwidth statements will still be true to their intention, which is that Class A gets a metric which is 40% of the way between 1 and 32,768 (19,660). Class B gets a metric which is 20% (26,214), etc.

We can punish the non-essential traffic with the shaper or policer so that during times of congestion that traffic is held down, thus forcing available space for the business-relevant traffic. In both the cases of a shaper and policer, the queuing scheduler will be limited in the data it can service from the Scavenger queue and it will thus move on to other traffic!

To learn more about QoS, visit

Related Posts

Close Bitnami banner