In this lesson you will learn about the QoS Pre-classify feature. When you use tunnelling, your Cisco IOS router will do classification based on the outer (post) header, not the inner (pre) header. This can cause issues with QoS policies that are applied to the physical interfaces. I will explain the issue and we will take a look how we can fix it. Here’s the topology that we will use:
Below is the tunnel configuration, I’m using a static route so that R1 and R3 can reach each other’s loopback interfaces through the tunnel:
R1(config)#interface Tunnel 0 R1(config-if)#tunnel source 192.168.12.1 R1(config-if)#tunnel destination 192.168.23.3 R1(config-if)#ip address 172.16.13.1 255.255.255.0
R1(config)#ip route 22.214.171.124 255.255.255.255 172.16.13.3
The configuration on R3 is similar:
R3(config)#interface Tunnel 0 R3(config-if)#tunnel source 192.168.23.3 R3(config-if)#tunnel destination 192.168.12.1 R3(config-if)#ip address 172.16.13.3 255.255.255.0
R3(config)#ip route 126.96.36.199 255.255.255.255 172.16.13.1
The tunnel is up and running, before we play with classification and service policies, let’s take a look at the default classification behaviour of Cisco IOS when it comes to tunnelling…
Default Classification Behaviour
IOS will copy the information in the TOS (Type of Service) byte from the inner IP header to the outer IP header by default. We can demonstrate this with a simple ping, here’s how:
R1#ping Protocol [ip]: Target IP address: 188.8.131.52 Repeat count : Datagram size : Timeout in seconds : Extended commands [n]: y Source address or interface: 184.108.40.206 Type of service : 160 Set DF bit in IP header? [no]: Validate reply data? [no]: Data pattern [0xABCD]: Loose, Strict, Record, Timestamp, Verbose[none]: Sweep range of sizes [n]: Type escape sequence to abort. Sending 5, 100-byte ICMP Echos to 220.127.116.11, timeout is 2 seconds: Packet sent with a source address of 18.104.22.168 !!!!! Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms
This ping between 22.214.171.124 and 126.96.36.199 will go through the tunnel and I marked the TOS byte of this IP packet with 160 (decimal). 160 in binary is 10100000, remove the last two bits and you have our 6 DSCP bits. 101000 in binary is 40 in decimal which is the same as the CS5.
Below you can see a wireshark capture of this ping:
As you can see, Cisco IOS automatically copied the TOS byte from the inner IP header to the outer IP header. This is a good thing, I’m using GRE in my example so we can see both headers but if this was an encrypted IPSEC tunnel then we (and any device in between) could only see the outer header.
When you have QoS policies based on the TOS byte then you will have no problems at all because the TOS byte is copied from the inner to the outer header. You will run into issues when you have policies based on access-lists that match on source / destination addresses and/or port numbers. Let me give you an example…
Post Header Classification
I’m going to create two class-maps, one for telnet traffic and another one for GRE traffic. Both class-maps will use an access-list to classify traffic:
R1(config)#ip access-list extended TELNET R1(config-ext-nacl)#permit tcp any any eq telnet R1(config)#class-map TELNET R1(config-cmap)#match access-group name TELNET
R1(config)#ip access-list extended GRE R1(config-ext-nacl)#permit gre any any R1(config)#class-map GRE R1(config-cmap)#match access-group name GRE
The two class-maps will be used in a policy-map:
R1(config)#policy-map POLICE R1(config-pmap)#class TELNET R1(config-pmap-c)#police 128000 R1(config-pmap-c-police)#exit R1(config-pmap-c)#exit R1(config-pmap)#class GRE R1(config-pmap-c)#exit R1(config-pmap)#exit
I’ve added policing for telnet traffic and nothing for GRE. It doesn’t matter what “actions” we configure here, even without an action the traffic will still be classified and it will show up in the policy-map. Let’s activate it on the physical interface:
R1(config)#interface FastEthernet 0/0 R1(config-if)#service-policy output POLICE
Something to keep in mind is that when you enable a policy on the physical interface, it will be applied to all tunnel interfaces. Let’s generate some telnet traffic between R1 and R3 so it goes through the tunnel:
R1#telnet 188.8.131.52 /source-interface loopback 0 Trying 184.108.40.206 ... Open
Now take a look at the policy-map:
R1#show policy-map interface FastEthernet 0/0 FastEthernet0/0 Service-policy output: POLICE Class-map: TELNET (match-all) 0 packets, 0 bytes 5 minute offered rate 0 bps, drop rate 0 bps Match: access-group name TELNET police: cir 128000 bps, bc 4000 bytes conformed 0 packets, 0 bytes; actions: transmit exceeded 0 packets, 0 bytes; actions: drop conformed 0 bps, exceed 0 bps Class-map: GRE (match-all) 11 packets, 735 bytes 5 minute offered rate 0 bps Match: access-group name GRE Class-map: class-default (match-any) 2 packets, 120 bytes 5 minute offered rate 0 bps, drop rate 0 bps Match: any
See how it only matches the GRE traffic? We don’t have any matches for the telnet traffic. If this was a real network, it means that telnet traffic will never get policed (or any other action you configured). The reason that we don’t see any matches is because Cisco IOS first encapsulates the IP packet and then applies the policy to the GRE traffic. Let me illustrate this:
The blue IP header on top is our original IP packet with telnet traffic, this is encapsulated and the router adds a GRE header and a new IP header (the red one). The policy-map is then applied to this outer IP header.
How do we fix this? There are a couple of options…let’s look at the first one!
Very clear and concise explanation, thank you
Thanks a lot for your excelent explanation…
I was very happy to find you had a lab on this subject. I went through this myself and everything worked as described, except one area. When I moved the service policy off the FA0/0 interface and put it on the Tunnel 0 interface (and removed the qos pre-qualify from the tunnel), the encapsulated IP header had the CS5 markings, but the outer header did not (as seen below)
Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
Differentiated Services Field: 0xa0 (DSCP 0x28: Class Select... Continue reading in our forum
That’s interesting, it seems that when you use a policy-map to set the DSCP that this happens after the automatic copying of the TOS byte.
What happens if you keep your policy-map and then try an extended ping where you set the TOS to CS3 or something? I’m guessing that it will copy CS3 from the inner to outer header and then afterwards it changes your inner header to CS5.
As usual, you are exactly right.
Doing what you described, set CS3 for the outer packet:
Differentiated Services Field: 0x60 (DSCP 0x18: Class Selector 3; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
And kept CS5 for the inner packet:
Differentiated Services Field: 0xa0 (DSCP 0x28: Class Selector 5; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))