Juniper refers to QoS as Class of Service (CoS) and it is something that I’ve always had trouble quite getting my head around for some reason. Sure – I’ve got CoS working nicely on switches and SRXes in customer networks, with packets hitting the right queues and so on, but you’re never quite sure it is exactly right.
Studying for my JNCIP-SP, I did a practice exam on the Juniper website and it seems that CoS is something I am weak in, so I am writing up some notes here for my own reference.
Overview
Packets that need different levels of treatment when passing through a Juniper device have to be classified as they enter the device, and queued for transmission before exiting the device. How packets are taken from the queues for transmission is called ‘scheduling’ – some queues are treated as higher priority than other queues so that more important packets such as voice or video get sent first. Within that queue, other things can happen such as shaping the traffic down to a particular rate, re-marking packets, or dropping packets. These things are done to proactively manage the queues in the device so that they don’t fill up. If they did, all packets would be dropped (tail-drop), so it is better to drop less critical packets early using Random Early Detection.
Classification of Packets
Packets can be classified in two ways:
1) By observing QoS markings on the packet (such as EXP bits, DSCP, IP ToS or 802.1P bits)
2) By observing other fields such as source/destination address, port numbers etc.
The first method is called Behaviour Aggregate classification. It implies that your whole network has been set up from end to end to classify (for example) voice packets using the DSCP bits.
The second method is called a Multi-Field Classifier, and is used when there are no markings on the packets that can be observed. The MFC might be used at the edge of the network to classify voice packets which are then marked with DSCP values. Once marked, classification can be done through the core of the network using a BA classifier instead.
Packet Flow through Junos CoS
As a packet enters the router, the classifier assigns each packet a ‘forwarding class’ and a ‘loss priority’. (Although I prefer to talk about a ‘loss probability’ because it makes sense to me – higher LP = higher chance of the packet being dropped).
Forwarding classes are assigned to queues.
Each queue has a scheduler applied to it. The scheduler determines how packets are treated in the queue (i.e. dropped, re-marked, shaped) and how the packets are transmitted (i.e. which queue to serve first).
The packet is transmitted.
Classifiers
There is a default classifier applied to all interfaces on a Juniper router, which is based on IP Type of Service – it is called ‘ipprec-compatibility’ and you can see it below:
root@LAB_SRX2> show class-of-service classifier name ipprec-compatibility Classifier: ipprec-compatibility, Code point type: inet-precedence, Index: 13 Code point Forwarding class Loss priority 000 best-effort low 001 best-effort high 010 best-effort low 011 best-effort high 100 best-effort low 101 best-effort high 110 network-control low 111 network-control high
The code-points are 3-bit patterns in the left column, and these each map to a forwarding class and loss priority in the middle and right columns. Out of the box, everything except network control traffic hits the best-effort class.
You don’t see any config statements associating the classifier with interfaces within Junos – that all happens under the hood. However, when you associate a classifier with an interface yourself, the ‘ipprec-default’. You assign a classifier to an interface by typing “set class-of-service interface <name> unit <number> classifiers inet-precedence default”.
The default classifier for inet-precedence looks a bit different to the compatibility one.
Alternatively, you can make your own classifier – based on precedence or DSCP or whatever. You can import the default one, and simply make the necessary changes you need – in the snippet below, I import the default classifier, change the expedited forwarding for packets marked with 111 and assign it to an interface:
root@LAB_SRX2# show class-of-service classifiers { inet-precedence CLASS1 { import default; forwarding-class expedited-forwarding { loss-priority high code-points 111; } } } interfaces { ge-0/0/0 { unit 0 { classifiers { inet-precedence CLASS1; } } } }
You can see that the new classifier has taken effect by issuing the operational command “show class-of-service interface”:
Physical interface: ge-0/0/0, Index: 134 Queues supported: 8, Queues in use: 4 Scheduler map: , Index: 2 Congestion-notification: Disabled Logical interface: ge-0/0/0.0, Index: 78 Object Name Type Index Classifier CLASS1 ip 4804
So that’s all good. Now I’m classifying, what to do next?
Schedulers
As I’ve said, a scheduler governs how the queue is treated. There are four properties of a scheduler that you can define:
1) The bandwidth assigned to the queue
2) The buffer size for storing packets in the queue
3) The priority of the queue
4) The drop profile
By default, only two schedulers are used – queue 0 for best effort traffic (allocated 95% of interface bandwidth), and queue 3 for network control stuff (getting the remaining 5% bandwidth).
So here’s a scheduler and a drop profile:
drop-profiles { DP1 { fill-level 50 drop-probability 50; fill-level 80 drop-probability 80; } } schedulers { SCHED1 { transmit-rate percent 10; buffer-size percent 10; drop-profile-map loss-priority low protocol any drop-profile DP1; } }
This sets up a drop profile that randomly discards 50% of packets when the queue is 50% full, and 80% when it is 80% full. The scheduler SCHED1 is created with 10% of line rate and 10% of the interface’s buffers. You might be wondering how I came up with those numbers. To be honest, I just made them up. You won’t find a right answer for creating these values anywhere – you need to set something up that looks OK and then monitor the results closely in most situations. If you get it wrong, by default a queue can exceed the defined bandwidth if there is room in other queues. (Quite what happens if those queues then fill up, I don’t know…)
Now that the scheduler has been created, we need to associate it to a forwarding class – this is done through a scheduler map. Using the examples above: “set class-of-service scheduler-map MAP1 forwarding-class expedited-forwarding scheduler SCHED1”
Finally, assign the scheduler map to the interface using “set class-of-service interface ge-0/0/0 scheduler-map MAP1”.
Testing
To see if this works there are a couple of things you can do. Junos allows you to set the TOS bits in ping packets, so you can do that to create the right markings and then see if the packets are hitting the queues correctly.
Pinging with the right TOS value requires a calculation. If your classifier is looking for the pattern 101 (as per the example), you have to remember that the TOS field is eight bits in length, so there are five zeros in the remainder of the field (10100000). The two 1s occupy the 128 and 32 bit positions – add these together and you get a value of 160. So the command from the neighbouring device to ping the one you’ve configured your CoS on is:
ping tos 160 10.0.0.2
This creates the marked packets – now go to the device where you configured your CoS, and look at the interface statistics in detail. On the second page of the output you should see packets hitting the expedited-forwarding queue:
Queue counters: Queued packets Transmitted packets Dropped packets 0 best-effort 61155 61155 0 1 expedited-fo 11 11 0 2 assured-forw 0 0 0 3 network-cont 22795 22795 0 Queue number: Mapped forwarding classes 0 best-effort 1 expedited-forwarding 2 assured-forwarding 3 network-control
So that’s some basic CoS configuration based on IP ToS. I’m off for a coffee.
It might be interesting to know that although you can pick your own mapping of queues and forwarding-classes as far as I know it is not possible to actually change the queue on traffic that is generated by the forwarding-plane itself. E.g. you cannot change the queue for BFD traffic on hardware that offloads BFD processing to the forwarding-plane. This traffic is always hardwired into queue 3.
A little something to keep in mind if you decide to change the queue in which you handle network-control type traffic.
Actually we could change queue for routing engine generated traffic. Its documented on Juniper web. http://www.juniper.net/documentation/en_US/junos12.2/topics/concept/hw-cos-default-re-traffic-overview-cos-config-guide.html
Hi,
I would like to know where have you defined the forwarding classes? The number of ques varies depending upon the platform. I have got Juniper 2320 where I have defined 8 queues.
Hi – I can’t remember to be honest! It was a couple of years ago.
I know you can define queue numbers like this though:
PE1> show configuration chassis
fpc 0 {
pic 0 {
tunnel-services {
bandwidth 1g;
}
max-queues-per-interface 8;
}
pic 1 {
max-queues-per-interface 8;
}
pic 2 {
max-queues-per-interface 8;
}
}
I am always confused between shaping-rate and buffer size under the scheduler config Can you please explain difference between them ?
[…] https://dataplumber.wordpress.com/2011/12/30/junos-qos-notes/ […]
[…] https://dataplumber.wordpress.com/2011/12/30/junos-qos-notes/ […]
Very helpful post! By the way, quite what happens in a full queue situation is depicted in the following:
http://www.juniper.net/documentation/en_US/junos14.2/topics/example/bw-sharing-excess-examples-cos-config-guide.html
Your interface will have some very real queueing limitations, which you can adjust with the typical delay vs delivery reliability tradeoff, but at some point in over-congestion, the excess will get dropped. All you can do is prioritize critical traffic and try to get TCP sessions to self-regulate via the WRED shenanigans.
Ah – thanks Aaron!
Thanks Mate, You noted saved lot of my time.
Tony Singarayar