Tuesday, March 12, 2013

Cisco ASA QoS For VoIP

So the goal is simple, right? You have a hosted VoIP solution and you want to ensure that your data traffic does not delay the VoIP traffic or worst still, you don't want the edge firewall dropping any VoIP packets because of high data usage.

I have a few customers that have deployed hosted VoIP solutions from WaveStreet and 8x8 - the usual complaint from time to time is that "the voice quality is bad" or "I could not hear the other party". Now most of these folks have simple networks like the one depicted below and I have managed to eliminate their VoIP issues with QoS configurations on the ASA.



In this particular example, we have a Cisco ASA 5505, a layer 3 switch with two VLANs, one for data and one for voice. Not included in this blog are the configs for the switches. It is advised that you turn on QoS on the switches if they supported it.

Prioritizing VoIP traffic using a Cisco ASA is well documented but the problem is Cisco's documents tend to omit a few important facts. Their example always use just the outside interface (ISP facing). Now, because QoS only acts on the egress traffic when applied to an interface, this does nothing for the inbound traffic from the ISP - the more important direction!

The second critical detail omitted is that even after you have applied the QoS to the correct interfaces, it does not help when a really long download is saturating the ISP link. Those VoIP packets don't have a chance getting down in time from the Internet to your network over that saturated pipe!

So how do we correct these. I used a nested policy on both the outside and inside interfaces of the firewall. The policy on the inside acts on the egress interface and therefore will impact the inbound traffic from the Internet whereas the outside one impacts the outbound traffic toward the Internet. Unfortunately, you've got to sacrifice the data bandwidth for this solution to work but there is no way around it. In my opinion it's a small price to pay.

Each call takes up about 80Kbps in our example and we have had about 10 simultaneous calls in the past  so I reserved 1Mbps of our 3Mbps Internet pipe for voice traffic. This implies that the data traffic (or all but voip traffic) can share 2Mbps. To do this, you shape the default class to 2Mbps and nest the voice policy so that the voip traffic is omitted from shaping (or drops) which will give it the remaining 1Mbps. Since I had a symmetrical 3Mbps Internet connection, I applied 2Mbps of traffic shaping to both interfaces. Change the shape rate accordingly if you have asymmetrical speeds.

Here's the relevant ASA 5505 configs with some explanations.

interface Vlan1
 nameif inside
 security-level 100
 ip address 10.0.0.1 255.255.255.0
!
interface Vlan2
 nameif outside
 security-level 0
 ip address i.i.i.i 255.255.255.248
!
interface Ethernet0/0
 switchport access vlan 2
!
interface Ethernet0/1
!
!I expect you to limit the udp ports to just what your provider has recommended. !I opened up all udp just to keep things simple
!
access-list outside_access_in extended permit udp any any 
!
!Although I used the entire subnet to classify the voip packets, please
!feel free to use dscp, precedence or ports instead
!
!Inbound voip traffic classification
access-list voip_inside extended permit ip any 10.16.1.0 255.255.255.0
!
!outbound (toward Internet) voip traffic classification
access-list voip_outside extended permit ip 10.16.1.0 255.255.255.0 any
!
global (outside) 1 70.35.47.195 netmask 255.255.255.255 nat (inside) 1 10.0.0.0 255.0.0.0 ! access-group outside_access_in in interface outside route outside 0.0.0.0 0.0.0.0 i.i.i.a 1 !
!Enable the piority queues on both interfaces
priority-queue inside
priority-queue outside
!
!Define the class maps for both inbound and outbound voice traffic and prioritize
!the voice traffic
!
class-map voice-inside-class
 match access-list voip_inside
class-map voip-outside-class
 match access-list voip_outside
!
policy-map global_policy
 class inspection_default
  inspect dns migrated_dns_map_1
  inspect ftp
  inspect h323 h225
  inspect h323 ras
  inspect rsh
  inspect rtsp
  inspect sqlnet
  inspect skinny
  inspect sunrpc
  inspect xdmcp
  inspect netbios
  inspect tftp
!
policy-map outside-policy
 class voip-outside-class
  priority
policy-map inside-policy
 class voice-inside-class
  priority
!
!Nested policy. Shapes all but VoIP traffic inbound from ISP at 2Mbps.
policy-map ins-policy
 class class-default
  shape average 2000000 8192
  service-policy inside-policy
!
!Nested policy. Shapes all but VoIP traffic outbound to ISP at 2Mbps.
policy-map out-policy
 class class-default
  shape average 2000000 8192
  service-policy outside-policy
!
service-policy global_policy global
service-policy ins-policy interface inside
service-policy out-policy interface outside

This will protect those sensitive real time packets in both directions but remember the bandwidth sacrifice!

7 comments:

  1. This is the best example driven documentation I have seen for simple voip qos. Very useful, and *generic* which is what I was looking for. Thanks!

    ReplyDelete
  2. Excellent article! I just have one question: How do you test or verify that QoS is really working?

    ReplyDelete
    Replies
    1. The simplest way is to saturate your Internet bandwidth in both directions, then place calls during that download or upload.
      If you're looking for commands, the 'show service-policy' will tell you if that policy is being hit. Unfortunately, there are not many commands on the ASA to perform more tests than that...as far as I know.

      Delete
  3. This comment has been removed by the author.

    ReplyDelete
  4. So based on this example, would this be accurate when matching on DSCP EF?

    class-map Voice
    match dscp ef

    policy-map Voicepolicy-Inside
    class Voice
    priority

    policy-map Voicepolicy-Outside
    class Voice
    priority

    policy-map Nested-Voicepolicy-Inside
    class class-default
    shape average 2000000
    service-policy Voicepolicy-Inside

    policy-map Nested-Voicepolicy-Outside
    class class-default
    shape average 2000000
    service-policy Voicepolicy-Outside

    service-policy Nested-Voicepolicy-Outside interface outside
    service-policy Nested-Voicepolicy-Inside interface inside

    ReplyDelete
    Replies
    1. Yep, that works. Matching on the dscp marking is more specific and is preferred.

      Delete