QoS Pre-Classify on Cisco IOS

In this lesson, you will learn about the QoS Pre-classify feature. When you use tunneling, 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 applied to the physical interfaces. I will explain the issue, and we will take a look at how we can fix it. Here’s the topology that we will use:

R1 R2 R3 GRE tunnel loopback interfaces

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
R1(config-if)#tunnel destination
R1(config-if)#ip address
R1(config)#ip route

The configuration on R3 is similar:

R3(config)#interface Tunnel 0
R3(config-if)#tunnel source
R3(config-if)#tunnel destination
R3(config-if)#ip address
R3(config)#ip route

The tunnel is up and running. Before we play with classification and service policies, let’s look at the default classification behavior of Cisco IOS when it comes to tunneling.

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:

Protocol [ip]: 
Target IP address:
Repeat count [5]: 
Datagram size [100]: 
Timeout in seconds [2]: 
Extended commands [n]: y
Source address or interface:
Type of service [0]: 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, timeout is 2 seconds:
Packet sent with a source address of 
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms

This ping between and 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, the same as the CS5.

Below, you can see a wireshark capture of this ping:

GRE Tunnel TOS marking inner outer

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 source/destination addresses and/or port numbers. Let me give you an example…

Post Header Classification

I will create two class maps, one for telnet traffic and another 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)#class GRE

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 /source-interface loopback 0
Trying ... Open

Now take a look at the policy-map:

R1#show policy-map interface FastEthernet 0/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
          cir 128000 bps, bc 4000 bytes
        conformed 0 packets, 0 bytes; actions:
        exceeded 0 packets, 0 bytes; actions:
        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). We don’t see any matches because Cisco IOS first encapsulates the IP packet and then applies the policy to the GRE traffic. Let me illustrate this:

IP Packet GRE encapsulation

The blue IP header 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!

We're Sorry, Full Content Access is for Members Only...

If you like to keep on reading, Become a Member Now! Here is why:

  • Learn any CCNA, CCNP and CCIE R&S Topic. Explained As Simple As Possible.
  • Try for Just $1. The Best Dollar You’ve Ever Spent on Your Cisco Career!
  • Full Access to our 791 Lessons. More Lessons Added Every Week!
  • Content created by Rene Molenaar (CCIE #41726)

1672 Sign Ups in the last 30 days

100% Satisfaction Guaranteed!
You may cancel your monthly membership at any time.
No Questions Asked!


Forum Replies

  1. Very clear and concise explanation, thank you

  2. Thanks a lot for your excelent explanation…

  3. Hello Rene,

    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

  4. Hi Andrew,

    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.


  5. 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))



6 more replies! Ask a question or join the discussion by visiting our Community Forum