Category Archives: SIP Trunking

CUBE URI-based Routing and Multiple Via Headers

Cisco introduced some pretty cool URI enhancements for CUBE from 15.4(1)T that have added some great extensions to the CUBE feature set, and specifically include some fine-grained SIP routing control.  These have been long overdue as IOS-based VoIP routing has been heavily dependent on numerical pattern matching due to Cisco’s ongoing support for H.323-style legacy configuration.

These enhancements are covered in a lovely Cisco doc here.  I’ve also blogged previously on a similar topic on how to utilize these and other new CUBE SIP features to provide Loop Prevention on CUBE.

 

To start, the basic configuration for URI dial-peer matching is somewhat trivial:

!
voice class uri voice-class-uri-tag sip|tel
    host hostname-pattern
    host ipv4:ipv4-address
    host ipv6:ipv6-address
    host dns:dns-address
    pattern uri-pattern
    user-id username-pattern
!
dial-peer voice tag voip
 session protocol sipv2
 incoming uri { from | request | to | via } voice-class-uri-tag
!

Here we see that incoming called-number is dropped and is instead routing using incoming uri.  Typically, we’d match the URI on a via header, with our voice class uri container applying a match on our preferred IP Address / DNS address.

I am referring to RFC compliant behaviour for the Via header from RFC 3261:

8.1.1.7 Via

   The Via header field indicates the transport used for the transaction
   and identifies the location where the response is to be sent.  A Via
   header field value is added only after the transport that will be
   used to reach the next hop has been selected (which may involve the
   usage of the procedures in [4]).

   When the UAC creates a request, it MUST insert a Via into that
   request.  The protocol name and protocol version in the header field
   MUST be SIP and 2.0, respectively.  The Via header field value MUST
   contain a branch parameter.  This parameter is used to identify the
   transaction created by that request.  This parameter is used by both
   the client and the server.

Here we note that a SIP Request can contain multiple Via headers.  This is used as a loop prevention mechanism for SIP Routing.  This becomes incredibly import when multiple SIP Proxies forward requests.  This is well described here for the SIP initiate.

 

With this in mind, I came across an interesting scenario recently where a call route through an ITSP’s SIP Proxy network changed without my knowledge, meaning that the Via header ordered list in the inbound INVITE changed.  This resulted in not matching my voice class uri configuration.  This stymied me at first until I noted the following for this feature:

In a scenario where multiple SIP hops are involved in a call, there would 
be multiple via headers involved, and the topmost via header of an 
incoming SIP invite represents the last hop that forwarded the SIP 
request, and the bottom-most via header would represent the originator 
of the SIP request. This feature supports matching by the last hop that 
forwarded the request (neighboringSIPentity), which is the topmost via 
header.

 

From the PDF link’s worked examples, we can see the matching will use the following behaviour:

INVITE sip:123@1.2.3.4:5060 SIP/2.0

Via: SIP/2.0/TCP 10.10.10.1:5093;branch=z9hG4bK-17716-1-0

Via: SIP/2.0/TCP 10.10.14.20:5093;branch=z9hG4bK-28280-1-0

 

In my situation, I’d been using a voice class uri that looked something like this:

!
voice class uri ITSP sip
    host ipv4:10.10.14.20
!
dial-peer voice tag voip
 session protocol sipv2
 incoming uri via ITSP
!
I would have expected the feature to consider the ordered list in decreasing priority, but the dial-peer never matched…  As per the feature description, only the “neighboringSIPentity” is considered.
Just something to note when deploying this feature in future.
#dontcalltac
Tagged , , , , , ,

CUCM Video Codec Preferences Support – CSCuw53802

Colleague called me for assistance with a video call that wouldn’t set up when dialling in to a VC bridge.

The call flow was from a Polycom endpoint to the new Conductor-managed vTS bridge that I’d installed a week before.  The endpoint could dial into the Rendezvous VC bridge, but calls only had audio.  Some additional testing showed that this wasn’t working for point-to-point calls to Jabber as well, which helped us rule out the bridge completely.

My colleague pulled a Wireshark from Jabber, and the signalling confirmed a codec support issue on the Polycom:

Jabber INVITE with H.264:

Selection_035

However, the response clearly showed that our Polycom unit didn’t like this, and marked the video streams as inactive:

Selection_036

My colleague did some reading up on our somewhat outdated Polycom unit, and we ultimately found that some release keys and a firmware upgrade would be needed.  Customer not too happy, but nothing to do here other than upgrade…

However, my colleague did post a question to me:

Can we not just set some video codec preferences for this call, or at least for the call into the VC bridge?

Well, the answer is… no!

 

As of 11.0 this is not supported.  However, thankfully this does appear to have been considered in the roadmap for CUCM 11.5:

https://bst.cloudapps.cisco.com/bugsearch/bug/CSCuw53802/

Selection_037

 

This is good news, as the CUCM-based video architecture is now quite mature, having gone through several iterations since it’s inception from CUCM 9.x.

As the market for Skype for Business grows, H.265 begins to create more and more headaches due to patent licensing problems, and Cisco subsequently begins to punt Thor as a potential future video standard, this new feature should hopefully solve some problems down the line.

 

#dontcalltac

Tagged , , , , , , , , , , , , , , ,

VoIP Bandwidth Calculations

If you’re preparing for a your CCIE Written or Lab exams, or (far more importantly) if you need to perform bandwidth sizing for a VoIP design or implementation, it’s critical to be able to accurately calculate the amount of bandwidth that your precious voice streams are going to need as they traverses your network.

Vik Mahli makes an excellent overview of what this means in terms of a QoS configuration here, but skips the calculation part altogether in order to focus on the LAN QoS config that he wished to cover in his post.  Naturally, this created some confusion which was carried over into the comments section!

I encourage you to read the comments, specifically Mark Holloway’s length post on this topic.  Mark makes an excellent reference here to the QoS SRND, and is well worth a read!  Please see this link and refer to where Mark and Vik use a 93bkps base for G.711 calls from.

Building on some of the discussions there, I’d like to provide some additional detail on how these calculations can be performed in this post.

Finally, please take note that this does not account for signalling bandwidth requirements.  This is a different discussion – ping me and I’ll blog about this too! 🙂

 

Performing VoIP Bandwidth Calculations

 

Calculation Assumptions

Firstly, we will have to make some protocol-related assumptions for sizing purposes:

  • IP – 20 bytes
  • User Datagram Protocol (UDP) – 8 bytes
  • Real-Time Transport Protocol (RTP) – 12 bytes
  • Compressed Real-Time Protocol (cRTP) reduces the IP/UDP/RTP headers to 2 or 4 bytes
  • Multilink Point-to-Point Protocol (MP) – 6 bytes
  • Frame Relay Forum (FRF).12 Layer 2 (L2)– 6 bytes
  • End-of-frame flag on MP and Frame Relay frames – 1 byte
  • Ethernet L2 headers– 18 bytes

 

Codec-Specific Information

Secondly, we need to know some values that are codec-specific:

  • Voice Payload Size
  • Codec Bitrate

Some values worth keeping in mind here are:

  • G711
    • Bit Rate – 64 kbps
    • Default Payload size – 160 bytes
  • G729
    • Bit Rate – 8 kbps
    • Default Payload size – 20 bytes
  • iLBC 20ms
    • Bit Rate – 15.2 kbps
    • Default Payload size – 38 bytes
  • iLBC 30ms
    • Bit Rate – 13.33 kbps
    • Default Payload size – 50 bytes

 

There is a detailed discussion of these values and their explanations here.  I won’t go into more detail in this post.  Please refer to the above document for clarity.

NOTE:

For differing Millesecond Packet Sizes (e.g. G.729 20ms/30ms), the codec bitrate is always constant.  Therefore the payload size can always be scaled as a ratio using the formula of:

codec bit rate = codec sample size / codec sample interval

More on this later in a worked example…

 

Bandwidth Calculation Formulas

From the TAC Online Help, we’re presented with a fairly simple calculation:

Total Packet Size = (Media Access Header - Layer 2) + (IP/UDP/RTP Header) + (voice payload)
Voice Packets Per Second (PPS) = codec bit rate / voice payload size
Bandwidth = [ (voice packet size) + 1 byte (frame flag) ] * PPS

Finally, it is best practice to allow for a 5.0% overhead in all calculations.

 

Some Worked Examples

This seems simple enough, so let’s put it into practice in some worked examples!

 

Example 1 : 3 Concurrent G.711 Calls over Ethernet

Total Packet Size = [ (18) + (40) + (160) ] = 218 bytes 

Packets per Second = [ 64 kbps * 1000 bits per kilobit ] / [ 160 bytes (default voice payload) * 8 bits per byte ]  = 50 pps

Bandwidth = [ ( 218 bytes ) + (0 bytes ) ] * 50 pps * 8 bites/byte = 87200 bits/sec = 87.2 kbps

5.0% Overhead87.2 kbps * 1.05 = 91.560 kbps

Concurrent Calls = 3 * 91.560 kbps = 274.68 kbps

 

Example 2 : 5 Concurrent G.729 Calls over PPP with Compressed RTP

Total Packet Size = [ (6) + (2) + (20) ] = 28 bytes 

Packets per Second = [ 8 kbps * 1000 bits per kilobit ] / [ 20 bytes (default voice payload) * 8 bits per byte ]  = 50 pps

Bandwidth = [ ( 28 bytes ) + (1 byte) ] * 50 pps * 8 bites/byte = 87200 bits/sec = 11.6 kbps

5.0% Overhead = 11.6 kbps * 1.05 = 12.18 kbps

Concurrent Calls = 5 * 12.18 kbps = 60.9 kbps

 

Example 3 : 10 Concurrent iLBC Calls over Ethernet using a 20ms bitrate

Total Packet Size = [ (18) + (40) + (38) ] = 96 bytes

Packets per Second =[ 15.2 kbps * 1000 bits per kilobit ]  / [ 38 bytes (default voice payload) * 8 bits per byte ]  = 50 pps

Bandwidth = [ ( 96 bytes ) + (0 bytes ) ] * 50 pps * 8 bites/byte = 38400 bits/sec = 38.4 kbps

5.0% Overhead = 38.4 kbps * 1.05 = 40.32 kbps

Concurrent Calls = 10 * 40.32 kbps = 403.20 kbps

The TAC Tool does not cover iLBC calculations, but we can see that there’s nothing special going on here.  We just needed to know the bitrate values for the codec and the calculations are effectively the same.

 

Example 4 : 5 Concurrent iLBC Calls over Ethernet using a 30ms bitrate

Total Packet Size = [ (18) + (40) + (50) ] = 108 bytes

Packets per Second =[ 13.3 kbps * 1000 bits per kilobit ]  / [ 50 bytes (default voice payload) * 8 bits per byte ]  = 33.3 pps

Bandwidth = [ ( 108 bytes ) + (0 bytes ) ] * 33.3 pps * 8 bites/byte = 28800 bits/sec = 28.8 kbps

5.0% Overhead = 28.8 kbps * 1.05 = 30.24 kbps

Concurrent Calls = 5 * 30.24 kbps = 151.20 kbps

 

Example 5 : 2 Concurrent G.729 Calls over Ethernet using a 40ms bitrate

OK, let’s end it off with a challenge 🙂

As I said above, the bitrate is always a constant for any codec:

codec bit rate = codec sample size / codec sample interval

Therefore, we will need to calculate our new Payload Sample Size for 40ms instead of 20ms:

Codec Sample Size = 8 kbps * 40ms  / (8bits/byte) = 40 bytes

See?  Not so hard!  If you’re following, you can actually see that you could have just used a ratio of:

New Payload Size = Old Payload Size * (New Sampling Interval / Old Sampling Interval)

 

OK, I digress.  Now, carrying on as before:

Total Packet Size = [ (18) + (40) + (40) ] = 98 bytes

Packets per Second =[ 8 kbps * 1000 bits per kilobit ]  / [ 40 bytes (default voice payload) * 8 bits per byte ]  = 25 pps

Bandwidth = [ ( 98 bytes ) + (0 bytes ) ] * 25 pps * 8 bites/byte = 19600 bits/sec = 19.60 kbps

5.0% Overhead =19.60 kbps * 1.05 = 20.58 kbps

Concurrent Calls = 2 * 40.32 kbps = 41.16 kbps

As you can see, the payload size may have doubled, but the packet throughput has halved!

 

Example 6 : 8 Concurrent G.722 Calls over Ethernet using a 10ms bitrate

Building on the ideas presented in the previous example:

New Payload Size = 160 kbps * (10/20) = 80 kbps

Total Packet Size = [ (18) + (40) + (80) ] = 138 bytes

Packets per Second =[ 64 kbps * 1000 bits per kilobit ]  / [ 80 bytes (default voice payload) * 8 bits per byte ]  = 100 pps

Bandwidth = [ ( 138 bytes ) + (0 bytes ) ] * 100 pps * 8 bites/byte = 110400 bits/sec = 110,4 kbps

5.0% Overhead =110.40 kbp * 1.05 = 115.92  kbps

Concurrent Calls = 8 *115.92 kbps = 927,36 kbps

OK, at this point not much more to cover! 🙂

 

A Final Note on Sampling Rates…

I highlighted the PPS value in Example 5 in red to make a final point on this topic.

As you can see, the payload size may have doubled, but the packet throughput has halved.

 

Where does all of this come  into play?  Well, there are two competing considerations here:

  1. Longer Durations (i.e. a lower PPS value) reduces Network Overheads
  2. Increased Packet Sizes decreases the resiliency to Network Errors (such as packet loss)

 

Considerations such as physical hardware capabilities, link stability, available bandwidth, PBX feature sets (and don’t forget that of your Peering Partners!)  etc. can all be considered when deciding on a preferred sampling rate for your VoIP network – a lot for the VoIP designer to think about when making decisions on what codecs (and respective capabilities) to support!

 

Online References

I have managed to find a number of excellent documents to help you.

 

For a detailed breakdown of how to perform these calculations:

 

A TAC tool, and simply the best out there with a nice GUI:

 

Configuring Bandwidth-based CAC for CUBE:

 

For quick and dirty calculations that don’t take into account network overheads:

 

Additional links to various sites that offer similar tools:

 

Hope this helps all you CCIE aspirants and VoIP network designers!

 

#dontcalltac

Tagged , , , , ,

RFC 5411 – And Other Guides to the SIP Galaxy

Given half a chance, I am always open to punt The SIP School as probably the best starting point for learning SIP out there.  I took this course some years ago, and was recently able to convince our management to get our whole voice team to complete the training.  It has really skilled up our team and made us a force to be reckoned within our local market.  If you want to learn SIP, look no further.  I’ve said it loads of times, this was without a doubt the key to my CCIE Collaboration success.  Before you ask, I have no affiliation to the SIP School whatsoever – am just a very, very satisfied customer!

That being said, my main motivation for suggesting this training material is that the course, although covering Core SIP and other topics incredibly well, is, by design, heavily influenced by the IETF standards documentation.  At the time of studying for the SSCA exam, I took the opportunity to do a detailed study of the RFCs that each section referenced.  To me, it is very important as a VoIP Engineer to have a strong understanding of RFC Compliance – particularly for SIP!

 

That being said, I only recently came across RFC 5411.  I can’t believe that in the last 5 years I’ve missed this!  This is absolutely the coolest IETF RFC for VoIP ever.  Unsurprisingly, this was written by Jonathan Rosenburg.

This is really a great starting point for working through the long list of RFCs that cover standard-based SIP (a term that can only ever be used loosely, haha).  Although there have been several key RFCs post-2009, this is an excellent starting point for even a seasoned SIP professional.  I particularly like how Jonathan has broken down this list functionally.  If you’re anything like me, you’ll soon find yourself deep down the rabbit hole!  And it definitely goes deep 🙂

 

I am particularly fond of these as well:

For something more Cisco-centric, this is a great read on how Cisco has recently endeavoured to remain RFC-compliant:

 

Happy reading.  Please ping me to add to this list!

Tagged , , ,

CUBE SIP Profiles – Normalizing Incorrect RURI/To Headers using Diversion

Had a strange requirement today.  Needed to replicate a behaviour that is apparently quiet common on Asterisk, but haven’t seen it before myself.

Our ITSP implemented a new softswitch/SBC setup that currently appears to be limiting (may just be configuration) when they “forward” a call internally within the softswitch to a trunk.

Our situation is that a client has a hybrid setup where a DID range is shared between extensions registered to their on-site CUCM cluster, and the hosted ITSP softswitch.  The inbound voice traffic is via a PRI that terminates on the client’s Cisco Voice Gateway.

This brings in the following type of call flow:

  1. Inbound traffic from ISDN
  2. Route traffic to CUCM
  3. Match DNs in Internal Partition, if not, Route Pattern back out same SIP Trunk to CUBE
  4. CUBE has registered trunk to ITSP, Loop Prevention is implemented to avoid extensions bouncing back and forth between system

External traffic is routed via ITSP, and both sides need to support 4-digit dialling between systems.

The challenge came on the softswitch side getting calls from softswitch-registered endpoints to CUCM.  The ITSP needed to provision aliases for the CUCM extensions and implement forwarding rules to the SIP Trunk SIP Account.

The result wasn’t pretty when it hit the CUBE inbound:

006846: Mar 17 21:33:56.184: //-1/xxxxxxxxxxxx/SIP/Msg/ccsipDisplayMsg:
Received:
INVITE sip:4396594@44.55.66.77:5060 SIP/2.0
Via: SIP/2.0/UDP 55.66.77.88:5060;branch=z9hG4bK0cB81sdf867sdf7
From: “Jonathan%20%20Els” <sip:0112223333@55.66.77.88>;tag=gK0c7b172a
To: <sip:4396594@44.55.66.77>
Call-ID: 19662878_12345657@55.66.77.88
CSeq: 957845045 INVITE
Max-Forwards: 70
Allow: INVITE,ACK,CANCEL,BYE,REGISTER,REFER,INFO,SUBSCRIBE,NOTIFY,PRACK,UPDATE,OPTIONS,MESSAGE,PUBLISH
Accept: application/sdp, application/isup, application/dtmf, application/dtmf-relay, multipart/mixed
Contact: “Jonathan%20%20Els” <sip:0112223333@55.66.77.88:5060;reg-info=1280c>
P-Preferred-Identity: “Jonathan%20%20Els” <sip:0112223333@55.66.77.88:5060>
Diversion: <sip:27445556666@55.66.77.88:5060>;privacy=off;screen=no; reason=unknown; counter=1
Supported: timer,100rel,precondition,replaces
Session-Expires: 1800
Min-SE: 90
Content-Length: 269
Content-Disposition: session; handling=required
Content-Type: application/sdp

v=0
o=Sonus_UAC 884721489 1041972446 IN IP4 55.66.77.88
s=SIP Media Capabilities
c=IN IP4 55.66.77.88
t=0 0
m=audio 48880 RTP/AVP 18 8 101
a=rtpmap:18 G729/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=sendrecv
a=maxptime:20

There’s a lot going on (*wrong :)) here…  Let’s break it down:

  • 4396594 – Called Party information is set to the SIP Account, not the DID that the hosted-PBX user tried to dial
  • 0112223333 – Calling number is set to the DID, and in local E.164 format
  • 27445556666 – Diversion header contains the Called Party information (i.e. based on the ITSP configuration described above, this is the “forwarding Alias”).  This is already in a plus-stripped E.164 format – not routable on our CUCM at the moment.
  • Jonathan%20%20Els – Oops, whitespace is duplicated and is URL encoded.

 

So, to normalize this, we need to do the following:

  1. Copy Diversion header DID and replace in the Inbound INVITE Request URI and To headers
  2. Calling Number is localized already – no need to cater for that
  3. Called number should be normalized to localized E.164 10-digit formatting – a task we will leave to CUCM to do.
  4. Encoded URL can be ignored – CUBE will translate this natively

 

As with all normalizations, we have 2 solutions available:

  • SIP Profiles in IOS
  • Lua Scripting in CUCM

 

I was requested to solve this in SIP Profiles.  To do this, we’ll need to make use of the  Support for Conditional Header Manipulation of SIP Headers feature that was implemented in 15.1(3)T:

The Support for Conditional Header Manipulation of SIP Headers feature provides the following enhancements to Cisco UBE:

  • The ability to pass unsupported parameters present in a mandatory header from one call leg to another.
  • The ability to copy contents from one header to another header in an outgoing SIP message.

 

Unfortunately the guide contains errors… thanks Cisco.  Here’s a working configuration to meet my requirement below:

Create copy list:

!
voice class sip-copylist 2
sip-header Diversion

!

Apply to copylist to inbound dial-peer:

!
dial-peer voice 200 voip
description *** ITSP ***
session protocol sipv2
session target sip-server
destination dpg 2
destination e164-pattern-map 2
incoming called-number .
voice-class codec 1
voice-class sip options-keepalive profile 2
voice-class sip copy-list 2
dtmf-relay rtp-nte sip-kpml
no vad
!

Copy Diversion in about sip-profile, and apply to RURI and To headers:

!
voice class sip-profiles 1
request INVITE peer-header sip Diversion copy “sip:(.*)@” u01
request INVITE sip-header SIP-Req-URI modify “.*@(.*)” “INVITE sip:\u01@\1″
request INVITE sip-header To modify “.*@(.*)” “To: <sip:\u01@\1″
!

Apply to CUCM dial-peer:

!
dial-peer voice 100 voip
description *** CUCM – SAIG ***
session protocol sipv2
session server-group 1
destination dpg 1
destination e164-pattern-map 1
incoming uri via CUCM
voice-class codec 1
voice-class sip profiles 1
voice-class sip options-keepalive profile 1
dtmf-relay rtp-nte sip-kpml
no vad
!

We still need to add routing for the SIP Account to actually HIT the outbound dial-peer, so we update our CUCM e164-pattern-map accordingly:

!
voice class e164-pattern-map 1
description *** To CUCM ***
e164 4396594
!

 

The final product sent to CUCM looks  good!

 

006848: Mar 17 21:33:56.192: //2592/C9846AB38DFD/SIP/Msg/ccsipDisplayMsg:
Sent:
INVITE sip:27445556666@192.168.1.1 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.254:5060;branch=z9hG4bK8EF1AD4
Remote-Party-ID: “Jonathan   Els” <sip:0112223333@mycube.local>;party=calling;screen=no;privacy=off
From: “Jonathan   Els” <sip:0112223333@myitsp.com>;tag=136DF10-11BA
To: <sip:27445556666@192.168.1.1>
Date: Thu, 17 Mar 2016 21:33:56 GMT
Call-ID: C98506DB-EBBE11E5-8E03ED66-DEC6DF88@mycube.local
Supported: 100rel,timer,resource-priority,replaces,sdp-anat
Min-SE: 1800
Cisco-Guid: 3380898483-3955102181-2382228838-3737575304
User-Agent: Cisco-SIPGateway/IOS-15.5.2.T
Allow: INVITE, OPTIONS, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY, INFO, REGISTER
CSeq: 101 INVITE
Timestamp: 1458250436
Contact: <sip:0112223333@mycube.local:5060>
Expires: 180
Allow-Events: kpml, telephone-event
Max-Forwards: 69
Diversion: <sip:27126575370@41.180.51.2>;privacy=off;reason=unknown;counter=1;screen=no
Content-Type: application/sdp
Content-Disposition: session;handling=required
Content-Length: 298

v=0
o=CiscoSystemsSIP-GW-UserAgent 2555 5070 IN IP4 192.168.1.254
s=SIP Call
c=IN IP4 192.168.1.254
t=0 0
m=audio 17336 RTP/AVP 18 8 101
c=IN IP4 192.168.1.254
a=rtpmap:18 G729/8000
a=fmtp:18 annexb=yes
a=rtpmap:8 PCMA/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15
a=ptime:20

All that’s remaining is the change from 27XXXXXXXXX to 0XXXXXXXXX for called party information – a simple translation in CUCM can sort that out to keep the sip-profiles clean!

 

#dontcalltac

Tagged , , , , , , , , ,

Incorrect SIP Realm – CUBE Not Responding to 401 Unauthorized

Had an issue today where we had to migrate a client as our ITSP migrated the client to a different SBC platforms.  After re-pointing, the SIP Trunk was failing to register.

The sip-ua configuration needed is pretty simple:

!
sip-ua
credentials username <myusername> password 7 <myencryptedpassword> realm myrealm.com
authentication username <myusername> password 7 <myencryptedpassword> realm myrealm.com
nat symmetric check-media-src
nat symmetric role active
registrar dns:myrealm.com expires 3600
sip-server dns:myrealm.com
!

So… what do we see?

Firstly, our SIP trunk is down:

Capture.PNG

So, we made some calls and tried to pick up an error.  The following SIP Ladder showed us a problem:

Capture2.PNG

So, the issue?  CUBE is not re-INVITEing to the ITSP, based on the supplied in the WWW-Authenticate header:

000611: Mar 17 17:11:09.936: //460/3CBC3A000000/SIP/Msg/ccsipDisplayMsg:
Received:
SIP/2.0 401 Unauthorized
Via: SIP/2.0/UDP 44.55.66.77:5060;branch=z9hG4bK12A75C
From: “End User 1” <sip:+27456478349@myrealm.com>;tag=464B7C-1D14
To: <sip:+272347897120@myrealm.com>;tag=gK08bac03c
Call-ID: 14005099-EB9A11E5-81CCED66-DEC6DF88@192.168.1.1
CSeq: 101 INVITE
WWW-Authenticate: Digest realm=”sip-2.ITSP_1″,nonce=”f3582aaf8sdf876b596d4f56a”
Content-Length: 0

Oops!  Looks like our ITSP is still busy developing their new platform?  We’re expecting Digest realm=”myrealm.com” but are getting something else!

So, what’s our solution?

Well…  to answer that, we actually need to look at the realm usage, which is well-defined in the appropriate SIP-UA RFC:

https://tools.ietf.org/html/rfc6011#section-3.1.2

 

On the CUBE, our realm configuration is is actually needed for accommodating Multiple Registrars:

http://www.cisco.com/c/en/us/td/docs/ios-xml/ios/voice/sip/configuration/15-mt/sip-config-15-mt-book/voi-sip-multi-trunks.html

Most specifically, the login applied for Authorization/Authentication is well summed up here:

Determination of Authentication Details
When a SIP INVITE or SIP REGISTER request is challenged, the username and password details for authentication are determined in the following order:

  1. If the realm specified in the challenge matches the realm in the authentication configuration for a POTS dial peer, the system uses the corresponding username and password
  2. If the realm specified in the challenge doesn’t match the configured authentication for the POTS dial peer, then it will check for credentials configured for SIP UA.
  3. If the realm specified in the challenge does not match the realm configured for credentials, then it will check for authentication configurations for SIP UA.
  4. If the system does not find a matching authentication or credential for the received realm, then the request is terminated.
  5. If there is no realm specified for the authentication configuration, then the system uses the username received from the challenge to build the response message

So, in our case, we had a realm mismatch, and since only one realm was applied, and the ITSP didn’t prompt for a username in the challenge, CUBE failed the call.  This is working as designed.

The fix (besides raising this with the ITSP of course!) was to remove the realm config from the SIP User Agent configuration for authentication.  This allowed the CUBE to respond to requests successfully, as it searched the authentication configurations:

!
sip-ua
credentials username <myusername> password 7 <myencryptedpassword> realm myrealm.com
authentication username <myusername> password 7 <myencryptedpassword>
nat symmetric check-media-src
nat symmetric role active
registrar dns:myrealm.com expires 60
sip-server dns:myrealm.com
!

After being applied, the trunk immediately registered, and calls were successful.

#dontcalltac

Tagged , , ,

Implementing Loop Prevention on CUBE

We work quite a lot with a single ITSP in our smaller deployments, but keep hitting a problem with number porting.  We’re repeatedly facing a problem whereby the number porting is done up front, and often in the case of BE6K installations includes numerous number ranges, BRI’s, analog extensions etc.  Often at the time of porting we need to account for 20+ different patterns across 5 or so sites.

The problem crops up when asking for all these ported patterns/ranges in a single list to place on the CUBE.  Quickly it appears that different people requested it, the porting requests were done piecemeal, etc – long story getting all the numbers up front can become a bit tricky.  Not that there is a good reason from it.  It’s a bit of a joke.  But this is what happens.

Come to porting, and we miss a pattern or five.  Now (my favourite part), the upstream provider for our ITSP starts crying because (and wait for it)… we have brought down their network.  They can’t seem to implement loop prevention, and somehow the looping that results from an inbound INVITE only matching the intended outbound dial-peers bombs the providers Media Server – but my little 2RU 2921 stands firm.  I kid you not. 🙂

So, after laughing for about 5min, let’s implement Loop Prevention on our side.  This can be done with COR Lists (vomit), but I prefer to use the newer features in IOS 15.4+, and stick to whats prescribed in the CVD BE6K Edge document.

Here’s the dial plan config that’s pretty much completely scalable – implemented with only 2 dial peers!

 

!
voice class uri 1 sip
host ipv4:<cucm-ip-sub-primary>
host ipv4:<cucm-ip-sub-secondary>
!
voice class uri 2 sip
host ipv4:<itsp-ip>
!
voice class e164-pattern-map 1
description *** To CUCM ***
e164 <internal-dn-range1>
e164 <internal-dn-range2>
e164 <internal-dn-range3>
!
voice class e164-pattern-map 2
description *** To ITSP ***
e164 .T
!
voice class dpg 1
dial-peer 100
!
voice class dpg 2
dial-peer 200
!
voice class server-group 1
ipv4 <cucm-ip-sub-primary>
ipv4 <cucm-ip-sub-secondary> pref 1
description *** CUCM ***
!
voice class server-group 2
ipv4 <itsp-ip>
description *** ITSP ***
!
dial-peer voice 100 voip
description *** CUCM ***
session protocol sipv2
session server-group 1
destination dpg 2
destination e164-pattern-map 1
incoming uri via 1
voice-class codec 1
dtmf-relay rtp-nte sip-kpml
no vad
!
dial-peer voice 200 voip
description *** ITSP ***
session protocol sipv2
session server-group 2
destination dpg 1
destination e164-pattern-map 2
incoming uri via 2
voice-class codec 1
voice-class sip bind control source-interface <external-interface>
voice-class sip bind media source-interface <external-interface>
no vad
dtmf-relay rtp-nte sip-kpml
!

 

Some Notes:

  • The loop prevention hinges on the face that you exclude dial peers using dial-peer groups.  An absolutely fantastic feature.
  • Outbound destinations are serviced by server groups – another brilliant addition.
  • Inbound matching is done using the URI Enhancements provided in 15.x and up
  • I tend to prefer to localize E.164 in CUCM for a Central Breakout Design.  I just like the extensible nature of Called and Calling Transformations.  I believe that this is more in line with the CVD/SRND – could be debated though.

 

A possible modification could drop the server groups (the limitation is that these only support IP), and instead route using DNS SRVs.  I like this approach a lot, and try and implement as such whenever possible.

What’s lovely about this is that the skeleton never changes – I get my patterns added to the e164 pattern map, adjust my IP’s and I’m good to go.

 

Voila!  CUBE implemented in under 5min.  Hope this helps some of you out there.

 

Tagged , , , , ,

Unity Call Extended for Recording Fails

While implementing an Auto Attendent today, we faced a challenge as the client did not want to pay for professional recordings, and needed to implement quickly.

If you’ve done the odd AA, you’ll know that this is a pretty common requirement.  Link to the docs is here.

However, when I did this in the usual way, I faced a call failure, with Error Code 5:

error5.png

 

A pretty useless error code then!  At this point I’m pretty convinced that my CUC config is good, so really it’s time to gather SDL traces and review…

I get an immediate hit in response to the SIP INVITE:

SIP/2.0 433 Anonymity Disallowed
Via: SIP/2.0/TCP 192.168.5.6:5060;branch=z9hG4bK14fda803a44a4d418c4f8301d3fec2b5
From: sip:192.168.5.5;tag=3387e2bbf6114e90b27738f525f251d6
To: sip:0255667787@192.168.5.5;tag=331164~0d10edf8-0553-4009-a728-c065d8394e46-24136465
Date: Mon, 07 Dec 2015 08:38:09 GMT
Call-ID: fedb03ec6b74449ab2dcc8031eb18dc0@192.168.5.5
CSeq: 200 INVITE
Allow-Events: presence
Server: Cisco-CUCM11.0
Session-ID: 00000000000000000000000000000000;remote=22bfe535e32fa04bbd9367a0ab331164
Reason: Q.850; cause=21
Content-Length: 0

 

Now if you’re experienced with SIP, you’ll know that cause=21 means a call rejection – so all call routing root causes are OUT.  CUCM had the ability to route the call, and chose not to.

If we inspect this SIP message (don’t even need to go the INVITE to analyze this one), we see that head From header done not include a user portion – host only!  Something is configured on CUCM to reject the anonymous calls.  Since this is dialling to a device – the first port of call is the DN, which showed this up immediately:

css.png

 

Removing the Reject Anonymous Calls checkbox resolved this immediately.  Silly me – had this set in my User Line Template used for Self-Provisioning! 🙂

 

However… this is not really an eloquent solution.  What if we MUST have the anon rejection in place?  Also – not very useful solution on a large cluster!

The better solution lies on CUC at the source – Setting the Contact Line Name on the Port Group.

 

When this was done, I noted that this correctly updated Contact, From and privacy headers as well.

 

#dontcalltac

 

Tagged , , , ,

Lua Script Solves Call Forward Masking

Had to implement an Auto Attendant in Unity today.  The client had a requirement to send after-hours calls out to the PSTN, but had to be routed in to their Call Centre, which had it’s own IVR which matched on calling number, that needed to be the switchboard number for their site.

Call Flow was as follows:

  1. Inbound call from PSTN
  2. CTI RP re-direct to Unity
  3. Unity Call Handler, with Close and Holiday transfer to 2nd Call Handler
  4. After-Hours Call Handler transfers back to After-Hours CTI RP
  5. After-Hours CTI RP as Call Forward to a PSTN number

 

The behavior that we see is controlled by SIP Trunk Calling Party Selection parameter, which is set to “Originator” by default:

pic1

 

The SIP INVITE sent to the CUBE looked like this:

INVITE sip:0112223344@mygateway.mydomain.com:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.5.5:5060;branch=z9hG4bK55cd222ad94e
From: <sip:0255667787@myhostname.mydomain.com>;tag=336868~0d10edf8-0553-4009-a728-c065d8394e46-24136542
To: <sip:0112223344@mygateway.mydomain.com>
Date: Mon, 07 Dec 2015 10:38:00 GMT
Call-ID: 94dfb980-66516188-5120-247410ac@192.168.5.5
Supported: 100rel,timer,resource-priority,replaces
Min-SE: 1800
User-Agent: Cisco-CUCM11.0
Allow: INVITE, OPTIONS, INFO, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY
CSeq: 101 INVITE
Expires: 180
Allow-Events: presence, kpml
Supported: X-cisco-srtp-fallback
Supported: Geolocation
Call-Info: <sip:192.168.5.5:5060>;method=”NOTIFY;Event=telephone-event;Duration=500″
Call-Info: <urn:x-cisco-remotecc:callinfo>;x-cisco-video-traffic-class=DESKTOP
Session-ID: 97632eb36d62419cbdc5fe71aa336867;remote=00000000000000000000000000000000
Cisco-Guid: 2497689984-0000065536-0000000110-0611586220
Session-Expires: 1800
Diversion: “After-Hours Re-Direct” <sip:**999@mydomain.com>;reason=unconditional;privacy=off;screen=yes
P-Asserted-Identity: <sip:0255667787@myhostname.mydomain.com>
Remote-Party-ID: <sip:0255667787@myhostname.mydomain.com>;party=calling;screen=yes;privacy=off
Contact: <sip:0255667787@192.168.5.5:5060>
Max-Forwards: 69
Content-Type: application/sdp
Content-Length: 227

v=0
o=CiscoSystemsCCM-SIP 336868 1 IN IP4 192.168.5.5
s=SIP Call
c=IN IP4 172.16.115.23
b=TIAS:8000
b=AS:8
t=0 0
m=audio 26842 RTP/AVP 18 101
a=rtpmap:18 G729/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15

 

  • In this case the calling party is sent out at 0255667787.  We want this sent out as 0255667000 to me the client’s requirement.
  • To do this, we need to correct the From, PAI, RPID, and Contact headers
  • The Diversion Header contains the Internal DN of the CTI RP – not very pretty, and something that our ITSP may bark at!  We must change it.
  • The headers MUST ONLY be modified when the call is forwarded FROM THIS CTI RP – my “hook” here will be the offending Diversion header.

 

I opted for a Lua script.  I find complex SIP Profiles unwieldly, which could have been another option.  Vomit.

 

So, here’s the script that achieved it.  Pretty simple in fact:

M = {}

trace.enable()

function M.outbound_INVITE(msg)

— Input for script
local ctirpdn = scriptParameters.getValue(“ctirpdn”)
local mainnumber = scriptParameters.getValue(“mainnumber”)
local rdnis = scriptParameters.getValue(“rdnis”)

— Get Diversion header
local diversion = msg:getHeader(“Diversion”)

— Check if Diversion Header exists and if the CTI RP DN is matched
if diversion and diversion:find(ctirpdn) then
trace.format(“Successful match on diversion – applying masking”)

trace.format(“CTI RP DN is : %s”, ctirpdn)
trace.format(“Main Number is : %s”, mainnumber)

— Apply masking to affected headers – From, PAI, RPID, Contact
msg:applyNumberMask(“From”, mainnumber)
msg:applyNumberMask(“P-Asserted-Identity”, mainnumber)
msg:applyNumberMask(“Remote-Party-ID”, mainnumber)
msg:applyNumberMask(“Contact”, mainnumber)
— Apply masking to Diversion to mask internal CTI RP DN
msg:applyNumberMask(“Diversion”, rdnis)

end
end

return M

The bold script params were applied on the SIP Trunk.  I decided to use Unity as the forwarding station, as set this as the “rdnis”.  The key is the IF STATEMENT, that only applied changes if the CTI RP DN is matched in the header.  Otherwise, the script is skipped.

 

Now, for testing… Let’s open up RTMT and trace this in SDL:

 

 

03149762.001 |13:00:37.979 |AppInfo |//SIP/SIPUdp/wait_SdlSPISignal: Outgoing SIP UDP message to 192.168.1.3:[5060]:
[990360,NET]
INVITE sip:0112223344@mygateway.@mydomain.com:5060 SIP/2.0
Via: SIP/2.0/UDP 192.168.5.5:5060;branch=z9hG4bK5634188efa43
From: <sip:0255667000@myhostname.@mydomain.com>;tag=337995~0d10edf8-0553-4009-a728-c065d8394e46-24136584
To: <sip:0112223344@mygateway.@mydomain.com>
Date: Mon, 07 Dec 2015 11:00:37 GMT
Call-ID: bdb57e00-665166d5-516d-247410ac@192.168.5.5
Supported: 100rel,timer,resource-priority,replaces
Min-SE: 1800
User-Agent: Cisco-CUCM11.0
Allow: INVITE, OPTIONS, INFO, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY
CSeq: 101 INVITE
Expires: 180
Allow-Events: presence, kpml
Supported: X-cisco-srtp-fallback
Supported: Geolocation
Call-Info: <sip:192.168.5.5:5060>;method=”NOTIFY;Event=telephone-event;Duration=500″
Call-Info: <urn:x-cisco-remotecc:callinfo>;x-cisco-video-traffic-class=DESKTOP
Session-ID: 97632eb36d62419cbdc5fe71aa337994;remote=00000000000000000000000000000000
Cisco-Guid: 3182788096-0000065536-0000000119-0611586220
Session-Expires: 1800
Diversion: “After-Hours Re-Direct” <sip:0255667800@@mydomain.com>;reason=unconditional;privacy=off;screen=yes
P-Asserted-Identity: <sip:0255667000@myhostname.@mydomain.com>
Remote-Party-ID: <sip:0255667000@myhostname.@mydomain.com>;party=calling;screen=yes;privacy=off
Contact: <sip:0255667000@192.168.5.5:5060>
Max-Forwards: 69
Content-Type: application/sdp
Content-Length: 227

v=0
o=CiscoSystemsCCM-SIP 337995 1 IN IP4 192.168.5.5
s=SIP Call
c=IN IP4 172.16.115.23
b=TIAS:8000
b=AS:8
t=0 0
m=audio 22640 RTP/AVP 18 101
a=rtpmap:18 G729/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-15

 

Working perfectly! 🙂

 

#dontcalltac

 

 

 

 

Tagged , , , , , ,

Lua Scripting – Replacing FQDN with IP in SIP Headers

A friend of mine at Cisco TAC pinged me a few days ago, asking to assist him with a case he’s working on that required a sip normalization script.

The call flow included a SIP Trunk to a conferencing system that was DNS-enabled.  CUCM was unable to lookup the DNS address (in this case due to a bug), and since the system was integrated directly to CUCM (not via CUBE), the only option for normalization was a Lua script.

The requirements of the script were:

  1. Find/Replace a number of potential FQDN/IP combinations
  2. Apply required normalization to “Contact” header
  3. Contact head must be modified for initial inbound INVITE, and all subsequent inbound responses to the INVITE
  4. Other messages should be ignored

Script:

–[[

Author : Jonathan Els
Email : jonathanelscpt@gmail.com
Version : 3.0

Description:

Find and replace FQDN with IP in Contact headers.
Script is applied to Inbound INVITEs and all Inbound INVITE responses

Future development:

None planned

–]]

M = {}

trace.enable()

— Customer-specific DNS table initialization – edit on per-script basis
local dns = {}
dns[“1.1.1.1”] = “hostname1%.rootdomain%.com”
dns[“2.2.2.2”] = “hostname2%.rootdomain%.com”
dns[“3.3.3.3”] = “hostname3%.subdomain%.rootdomain%.com”
local function process_contact_headers

— Get Contact header
local contact = msg:getHeader(“Contact”)
local iptest = “@(%d+%.%d+%.%d+%.%d+)”

— Check if exists and if URI host portion is FQDN
if contact and not contact:match(iptest) then
trace.format(” — Contact URI host portion matched FQDN”)
trace.format(” — Contact header is : %s”, contact)

— Iterate over domain and substitute if matched
for ip,fqdn in pairs(dns) do
if contact:match(fqdn) then
contact = contact:gsub(fqdn, ip)
trace.format(” — Matched on : %s”, fqdn)
trace.format(” — Modified to : %s”, ip)

— Modify contact header
msg:modifyHeader(“Contact”, contact)
break
end
end
end
end

— Apply to INVITE request and all INVITE responses
M.inbound_INVITE = process_contact_headers
M.inbound_ANY_INVITE = process_contact_headers
return M

Some Notes:

  • The requirement called for both request and response handling
    • M.inbound_INVITE
    • M.inbound_ANY_INVITE
  • The multiple handling requirement resulted in a “purposed-based” function being used to avoid duplication of code.
  • Some checks were added to skip and exit in the event that
    1. Contact header did not exist
    2. URI host portion was an IP Address.
  • Lua does not support full regex (regex is slow), so a standard IP approximation was used.  The “@” prefix in the match is used to ensure the match is on the URI.

Useful Resources:

The last resource from Cisco Live is possibly the best “How-To” out there!

Happy scripting.

#dontcalltac

Tagged , , , ,
Collaboration Engineer

All things Collaboration - Posts to save for when you need them

Gerry Keleghan's Blog

A Blog about Cisco Unified Communications

ccieme

my personal journey to ccie

Striving for greatness

Thoughts on emerging tech, open source, and life

Network Experts Blog

“Knowledge comes by eyes always open and working hands.”

SIP Adventures

A unified communications blog by Andrew Prokop

The Cloverhound Blog

Cloverhound Employees Talk Unified Communications and Contact Center

Warcop

Fog navigator. Get out of the clouds. Down to earth solutions. @Warcop

Cisco Collab Engineering Tips

Michael White - CCIE #26626

Darkroomstory

Photography by Manos,

afterthenumber

Thoughts and experiences of a Cisco Collaboration engineer after clearing the CCIE lab...

Longreads

The best longform stories on the web

The Daily Post

The Art and Craft of Blogging

The WordPress.com Blog

The latest news on WordPress.com and the WordPress community.