Saturday, February 22, 2020

QoS Pre-Classify on Cisco IOS

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:
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 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 3.3.3.3 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 1.1.1.1 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: 3.3.3.3
Repeat count [5]: 
Datagram size [100]: 
Timeout in seconds [2]: 
Extended commands [n]: y
Source address or interface: 1.1.1.1
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 3.3.3.3, timeout is 2 seconds:
Packet sent with a source address of 1.1.1.1 
!!!!!
Success rate is 100 percent (5/5), round-trip min/avg/max = 1/2/4 ms
This ping between 1.1.1.1 and 3.3.3.3 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:
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 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 3.3.3.3 /source-interface loopback 0
Trying 3.3.3.3 ... 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:
IP Packet GRE encapsulation
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!

Pre Header Classification (Physical Interface)

The first method to solve this issue is to enable pre-classification on the tunnel interface. This tells the router to create a copy of the original IP header and to use that for the policy. Here’s how to do this:
R1(config)#interface Tunnel 0
R1(config-if)#qos pre-classify 
You can use the qos pre-classify command to do this. Let’s do another test and we’ll see the difference:
R1#clear counters
Clear "show interface" counters on all interfaces [confirm]
R1#telnet 3.3.3.3 /source-interface loopback 0
Trying 3.3.3.3 ... 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)
      11 packets, 735 bytes
      5 minute offered rate 0 bps, drop rate 0 bps
      Match: access-group name TELNET
      police:
          cir 128000 bps, bc 4000 bytes
        conformed 11 packets, 889 bytes; actions:
          transmit 
        exceeded 0 packets, 0 bytes; actions:
          drop 
        conformed 0 bps, exceed 0 bps

    Class-map: GRE (match-all)
      0 packets, 0 bytes
      5 minute offered rate 0 bps
      Match: access-group name GRE

    Class-map: class-default (match-any)
      1 packets, 60 bytes
      5 minute offered rate 0 bps, drop rate 0 bps
      Match: any
Great! Now we see matches on our telnet traffic so it can be policed if needed. We don’t see any matches on our GRE traffic anymore. Let me visualize what just happened for you:
GRE Qos Pre classify copy header
When the router encapsulates a packet, it will make a temporary copy of the header. This temporary copy is then used for the policy instead of the outer header. When this is done, the temporary copy is destroyed.
We accomplished this with the qos pre-classify command but there is another method to get the same result, here’s how…

Pre Header Classification (Tunnel Interface)

Instead of activating the policy on the physical interface we can also enable it on the tunnel interface:
R1(config)#interface FastEthernet 0/0
R1(config-if)#no service-policy output POLICE

R1(config)#interface Tunnel 0
R1(config-if)#no qos pre-classify 
R1(config-if)#service-policy output POLICE  
Note that I also removed the qos pre-classify command on the tunnel interface. Let’s give it another try:
R1#clear counters
Clear "show interface" counters on all interfaces [confirm]
R1#telnet 3.3.3.3 /source-interface loopback 0
Trying 3.3.3.3 ... Open
Here’s what you will see:
R1#show policy-map interface Tunnel 0
 Tunnel0 

  Service-policy output: POLICE

    Class-map: TELNET (match-all)
      11 packets, 737 bytes
      5 minute offered rate 0 bps, drop rate 0 bps
      Match: access-group name TELNET
      police:
          cir 128000 bps, bc 4000 bytes
        conformed 11 packets, 737 bytes; actions:
          transmit 
        exceeded 0 packets, 0 bytes; actions:
          drop 
        conformed 0 bps, exceed 0 bps

    Class-map: GRE (match-all)
      0 packets, 0 bytes
      5 minute offered rate 0 bps
      Match: access-group name GRE

    Class-map: class-default (match-any)
      0 packets, 0 bytes
      5 minute offered rate 0 bps, drop rate 0 bps
      Match: any 
If you enable the policy on the tunnel interface then the router will use the inner header for classification, just like we saw when we used the qos pre-classify command on the tunnel interface.
hostname R1
!
ip cef
!
interface Loopback0
 ip address 1.1.1.1 255.255.255.255
!
interface Tunnel0
 ip address 172.16.13.1 255.255.255.0
 tunnel source 192.168.12.1
 tunnel destination 192.168.23.3
!
interface FastEthernet0/0
 ip address 192.168.12.1 255.255.255.0
!
ip route 3.3.3.3 255.255.255.255 172.16.13.3
!
end
hostname R2
!
ip cef
!
interface FastEthernet0/0
 ip address 192.168.12.2 255.255.255.0
!
interface FastEthernet1/0
 ip address 192.168.23.2 255.255.255.0
!
end
hostname R3
!
interface Loopback0
 ip address 3.3.3.3 255.255.255.255
!
interface Tunnel0
 ip address 172.16.13.3 255.255.255.0
 tunnel source 192.168.23.3
 tunnel destination 192.168.12.1
!
interface FastEthernet0/0
 ip address 192.168.23.3 255.255.255.0
!
ip route 1.1.1.1 255.255.255.255 172.16.13.1
!
end


That’s all there is to explain. I hope this lesson has been useful to understand the difference between “outer” and “inner” header classification and how to deal with this issue.

No comments:

Post a Comment