The Dispatcher module is used to offer load balancing functionality and intelligent dispatching of SIP messages.
Let’s say you’ve added a second Media Gateway to your network, and you want to send 75% of traffic to the new gateway and 25% to the old gateway, you’d use the load balancing functionality of the Dispatcher module.
Let’s say if the new Media Gateway goes down you want to send 100% of traffic to the original Media Gateway, you’d use the intelligent dispatching to detect status of the Media Gateway and manage failures.
These are all problems the Dispatcher Module is here to help with.
Before we get started….
Your Kamailio instance will need:
- Installed and running Kamailio instance
- Database configured and tables created (We’ll be using MySQL but any backed is fine)
- kamcmd & kamctl working (kamctlrc configured)
- Basic Kamailio understanding
The Story
So we’ve got 4 players in this story:
- Our User Agent (UA) (Softphone on my PC)
- Our Kamailio instance
- Media Gateway 1 (mg1)
- Media Gateway 2 (mg2)
Our UA will make a call to Kamailio. (Send an INVITE)
Kamailio will keep track of the up/down status of each of the media gateways, and based on rules we define pick one of the Media Gateways to forward the INVITE too.
The Media Gateways will playback “Media Gateway 1” or “Media Gateway 2” depending on which one we end up talking too.
Configuration
Parameters
You’ll need to load the dispatcher module, by adding the below line with the rest of your loadmodules:
loadmodule "dispatcher.so"
Next we’ll need to set the module specific config using modparam for dispatcher:
modparam("dispatcher", "db_url", DBURL) #Use DBURL variable for database parameters
modparam("dispatcher", "ds_ping_interval", 10) #How often to ping destinations to check status
modparam("dispatcher", "ds_ping_method", "OPTIONS") #Send SIP Options ping
modparam("dispatcher", "ds_probing_threshold", 10) #How many failed pings in a row do we need before we consider it down
modparam("dispatcher", "ds_inactive_threshold", 10) #How many sucessful pings in a row do we need before considering it up
modparam("dispatcher", "ds_ping_latency_stats", 1) #Enables stats on latency
modparam("dispatcher", "ds_probing_mode", 1) #Keeps pinging gateways when state is known (to detect change in state)
Most of these are pretty self explanatory but you’ll probably need to tweak these to match your environment.
Destination Setup
Like the permissions module, dispatcher module has groups of destinations.
For this example we’ll be using dispatch group 1, which will be a group containing our Media Gateways, and the SIP URIs are sip:mg1:5060 and sip:mg2:5060
From the shell we’ll use kamctl to add a new dispatcher entry.
kamctl dispatcher add 1 sip:mg1:5060 0 0 '' 'Media Gateway 1'
kamctl dispatcher add 1 sip:mg2:5060 0 0 '' 'Media Gateway 2'
Alternately you could do this in the database itself:
INSERT INTO `dispatcher` (`id`, `setid`, `destination`, `flags`, `priority`, `attrs`, `description`) VALUES (NULL, '1', 'sip:mg3:5060', '0', '0', '', 'Media Gateway 3');
Or you could use Siremis GUI to add the entries.
You can use kamctl to show you the database entries:
kamctl dispatcher show
A restart to Kamailio will make our changes live.
Destination Status / Control
Checking Status
Next up we’ll check if our gateways are online, we’ll use kamcmd to show the current status of the destinations:
kamcmd dispatcher.list
Here we can see our two media gateways, quick response times to each, and everything looks good.
Take a note of the FLAGS field, it’s currently set to AP which is good, but there’s a few states:
- AP – Active Probing – Destination is responding to pings & is up
- IP – Inactive Probing – Destination is not responding to pings and is probably unreachable
- DX – Destination is disabled (administratively down)
- AX – Looks like is up or is coming up, but has yet to satisfy minimum thresholds to be considered up (ds_inactive_threshold)
- TX – Looks like or is, down. Has stopped responding to pings but has not yet satisfied down state failed ping count (ds_probing_threshold)
Adding Additional Destinations without Restarting
If we add an extra destination now, we can add it without having to restart Kamailio, by using kamcmd:
kamcmd dispatcher.reload
There’s some sanity checks built into this, if the OS can’t resolve a domain name in dispatcher you’ll get back an error:
Administratively Disable Destinations
You may want to do some work on one of the Media Gateways and want to nicely take it offline, for this we use kamcmd again:
kamcmd dispatcher.set_state dx 1 sip:mg1:5060
Now if we check status we see MG1’s status is DX:
Once we’re done with the maintenance we could force it into the up state by replacing dx with ap.
It’s worth noting that if you restart Kamailio, or reload dispatcher, the state of each destination is reset, and starts again from AX and progresses to AP (Up) or IP (Down) based on if the destination is responding.
Routing using Dispatcher
The magic really comes down to single simple line, ds_select_dst();
The command sets the destination address to an address from the pool of up addresses in dispatcher.
You’d generally give ds_select_dst(); two parameters, the first is the destination set, in our case this is 1, because all our Media Gateway destinations are in set ID 1. The next parameter is is the algorithm used to work out which destination from the pool to use for this request.
Some common entries would be random, round robin, weight based or priority value.
In our example we’ll use a random selection between up destinations in group 1:
if(method=="INVITE"){
ds_select_dst(1, 4); #Get a random up destination from dispatcher
route(RELAY); #Route it
}
Now let’s try and make a call:
UA > Kamailio: SIP: INVITE sip:1111111@Kamailio SIP/2.0
Kamailio > UA: SIP: SIP/2.0 100 trying -- your call is important to us
Kamailio > MG1: SIP: INVITE sip:1111111@MG1 SIP/2.0
MG1 > Kamailio: SIP: SIP/2.0 100 Trying
Kamailio > UA : SIP: SIP/2.0 100 Trying
MG1 > Kamailio: SIP: SIP/2.0 200 OK
Kamailio > UA : SIP: SIP/2.0 200 OK
And bingo, we’re connected to a Media Gateway 1.
If I try it again I’ll get MG2, then MG1, then MG2, as we’re using round robin selection.
Destination Selection Algorithm
We talked a little about the different destination select algorithm, let’s dig a little deeper into the common ones, this is taken from the Dispatcher documentation:
- “0” – hash over callid
- “4” – round-robin (next destination).
- “6” – random destination (using rand()).
- “8” – select destination sorted by priority attribute value (serial forking ordered by priority).
- “9” – use weight based load distribution.
- “10” – use call load distribution.
- “12” – dispatch to all destination in setid at once
For select destination sorted by priority (8) to work you need to include a priority, you can do this when adding the dispatcher entry or after the fact by editing the data. In the below example if MG1 is up, calls will always go to MG1, if MG1 is down it’ll go to the next highest priority (MG2).
For use weight based load distribution (9) to work, you’ll need to set a weight as well, this is similar to priority but allows you to split load, for example you could put weight=25 on a less powerful or slower destination, and weight=75 for a faster or more powerful destination, so the better destination gets 75% of traffic and the other gets 25%. (You don’t have to do these to add to 100%, I just find it easier to think of them as percentages).
use call load distribution (10) allows you to evenly split the number of calls to each destination. This could be useful if you’ve got say 2 SIP trunks with x channels on each trunk, but only x concurrent calls allowed on each. Like adding a weight you need to set a duid= value with the total number of calls each destination can handle.
dispatch to all destination in setid at once (12) allows you to perform parallel branching of your call to all the destinations in the address group and whichever one answers first will handle the call. This adds a lot of overhead, as for each destination you have in that set will need a new dialog to be managed, but it sure is quick for the user. The other major issue is let’s say I have three carriers configured in dispatcher, and I call a landline.
That landline will receive three calls, which will ring at the same time until the called party answers one of the calls. When they do the other two calls will stop ringing. This can get really messy.
Managing Failure
Let’s say we try and send a call to one of our Media Gateways and it fails, we could forward that failure response to the UA, or, better yet, we could try on another Media Gateway.
Let’s set a priority of 10 to MG1 and a priority of 5 to MG2, and then set MG1 to reject the call.
We’ll also need to add a failure route, so let’s tweak our code:
if(method=="INVITE"){
ds_select_dst(1, 12);
t_on_failure("DISPATCH_FAILURE");
route(RELAY);
}
And the failure route:
route[DISPATCH_FAILURE]{
xlog("Trying next destination");
ds_next_dst();
route(RELAY);
}
ds_next_dst() gets the next available destination from dispatcher. Let’s see how this looks in practice:
UA > Kamailio: SIP: INVITE sip:1111111@Kamailio SIP/2.0
Kamailio > UA: SIP: SIP/2.0 100 trying -- your call is important to us
Kamailio > MG1: SIP: INVITE sip:1111111@MG1 SIP/2.0
MG1 > Kamailio: SIP: SIP/2.0 100 Trying
MG1 > Kamailio: SIP: SIP/2.0 404 Not Found
Kamailio > MG1 : SIP: SIP/2.0 ACK
Kamailio > MG2: SIP: INVITE sip:1111111@MG2 SIP/2.0
MG2 > Kamailio: SIP: SIP/2.0 100 Trying
MG2 > Kamailio: SIP: SIP/2.0 200 OK
Kamailio > UA : SIP: SIP/2.0 200 OK
the gateway1 adn gateway2 can be asterisk1 and asterisk2? if yes, rouoting must affect return packes?
That’s right,
You’ll get the return packets for that Transaction, if you want to stay in line for the whole Dialog, you’ll need to use the Record Routing header.
I would like to know if in case of round robin algorithm is other methods like ACK or BYE send to the same destination as a last (for example INVITE) method.
Hi Petr,
For most scenarios (Including the example associated with this post) the ACK / BYE responses (Anything after the INVITE) will be routed using the Via Headers, and will not pass through our request_route {} block, but will instead use the route[WITHINDLG] {} block to determine it’s logic.
You could override it but generally you want in-dialog messages to route to the same endpoint that started handling the call.
Hope that helps,
Nick
Hi, is there a way to add a different tech prefix to be added on each destination. Several providers require such prefix for security and that prefix that is unique per client per provider. So If you want to dial 12345@my and have 5 providers giving you different prefixes you have to change rU before send to each provider adding the prefix like dlg_var(MyPrefix) + rU to make the new ru for each destination. On destinations there is a prefix option is you use text files files (not tested) but, I cannot locate such option if you use DB to store destination sets. On attr field I added rweight=50;weight=50;cc=1;prefix=011; but again no luck. I could not manage to make it work… Any help will be much appreciated.
Hi Ag,
Nothing directly in dispatcher, but if you combine it with the Diaplan module, it can absolutely handle the tech prefixes,
Nick
Hi Nick,
Thanks for the reply. Let me give some more details for this scenario. Let’s say we have one provider offering three different quality levels of service (Bronze, Silver, Gold) from the same SBC he offers you to connect to. The quality levels of service is defined based on an agreed tech prefix. So in this case we use dispatcher module on kamailio to send traffic to this provider having three different destinations on dispatcher table on the same dispatcher set with algorithm 8 (Serial). All 3 destinations in this set are actually the same in terms of IP, Port and protocol. Also the $ru is the same as we try to send the same call to the first destination that accepts this traffic. So the only change, is the tech prefix we need to prepend to the $rU. We cannot try to add the prefix based on destination match after ds_select_dst as the $du is the same in all three destinations in set. Can you please explain how we can implement this scenario and how we can use dialplan for this?
Hi Nick,
Thanks for your posts they are a life saver.
I am trying to setup kamailio to dispatch traffic to another server (172.31.11.32). But I keep getting the following error message.
Mar 11 11:10:46 ip-172-31-34-11 kamailio[13779]: 1(13795) ERROR: tm [ut.h:315]: uri2dst2(): no corresponding socket found for “172.31.11.32” af 2 (udp:172.31.11.32:5060)
Mar 11 11:10:46 ip-172-31-34-11 kamailio[13779]: 1(13795) ERROR: tm [uac.c:452]: t_uac_prepare(): no socket found
Mar 11 11:10:46 ip-172-31-34-11 kamailio[13779]: 1(13795) ERROR: dispatcher [dispatch.c:3120]: ds_ping_set(): unable to ping [sip:172.31.11.32:5060]
Any ideas how I can fix this? it looks like kamailio is looking for a socket open with the other server. I am not sure how to do this.
Hi Sadiq,
What method are you using to check the alive status? ie SIP OPTIONs Pings, ICMP, etc?
Hi Nick,
Thanks for your reply.
I was able to resolve the issue. The root cause was that I was running my Kamailio instance on TCP (listen=tcp) , however, I added a destination gateway over UDP. This was causing the problem, once I changed my Kamailio server to listen on UDP, the issue was resolved.
I have another question, probably not related. I want to setup a HA pair of kamailio in ACTIVE/BACKUP mode sharing a VIP. Is there a tutorial I can follow for this?
Basically what I mean is What will happen to existing calls when a failover occurs? How do we ensure that the call states are replicated b/w the two HA nodes and transactions are handled appropriately by B node after failover?
I am struggling to find configuration guide for it.
Hi Sadiq,
The dispatcher module does not add redundancy to your infrastructure, rather redundant paths to other people’s (like other carriers).
If the machine your Kamailio instance is running on were to have a failover, that would not be helped by Dispatcher, that’s more a job for the DMQ to replicate state between multiple Kamailio instances.
Thanks nick, I will have a look into the DMQ module.
I must add the work you have done is impressive and extremely helpful.
Are you on Linkedin?
Hi Nick,
Thanks for your posts, turns my understanding of kamailio much better.
Dispacter works wich load balance and priority, I not found a module that works with domain forwarding for example, like pbx1.xx.com forward to ast1, pbx2, xx.com to ast2.
Dispatcher do this job?
Thanks for the info Nick, learning a lot with your blog
Hi Nick,
Thank you for info.
I was try to implement some Load Balancer with dispatcher module.
the scheme is looks like
Asterisk -> Kamailio -> Asterisk
Sometimes when callee Asterisk make call transfer with REFER we received 500 Invalid CSeq Message from called Asterisk
It Is look like this
│ │ REFER │
│ │ <──────── │
│ │ BYE │
│ │ <──────── │
│ BYE │ │
│ <────────│ │
│ REFER │ │
│ │ │
│ 500 Invalid C│ │
│ ───────> │ │
│ │ 200 OK │
│ │ ────────> │
│ │ 500 Invalid C │
│ │ ──────── > │
As you can see Kamailio send BYE message before REFER mesage to caled Asterisk. And this Asterisk replied with 500 Invalid CSeq.
What am I doing wrong?
Oh, I don’t know how I can send a diagram)
HI Nick,
Thank you for your helpful posts. Is it possible to reinitiate the session so that we can save active calls from dropping?
The scenario is that we have one Kamailio and 2 asterisks or FreeSWITCH and we have some active calls on Box1 – Box1 is going down and we don’t want the active calls to drop. What modules in kamailio we can use to achive this ?
Hi Omid,
If you’re not relaying the audio in Asterisk (Direct media) then you can do this, but the hangup probably won’t go through to the other side.
Hi Nick, We were trying to test the dispatcher module, it works expected routing traffic in a round robin fashion but we are not able to see the status using kamcmd command. We are using the dispatcher file to load entries and not manually add via command line. Can you please advise why we are unable to see the realtime status ? Thank you
DK
Hi Nick,
I have a scenario where I will be using 2 kamailio SIP server and a SBC device.
So the set up would be as follows
Kamailio 1(192.168.50.24) => SBC device (192.168.2.31) => Kamailio 2(192.168.55.25).
Now I want to establish the call from my Kamailio 1 to Kamailio 2 with SBC, where I have configured SIP proxy and IP to IP routing in SBC.
I need to send the call to SBC, SBC will do all the routing stuff and send the call to the anothe SIP server.
I tried everything possible, but I am not able to establish my call.
Can you please help me out.
Hi Nick,
Thankyou for your post, I am trying to use dispatcher module for load balancing but getting some error during configuration.
When I runs command–> kamcmd dispatcher.list
Getting below error,
[root@localhost kamailio]# kamcmd dispatcher.list
error: 500 – command dispatcher.list not found
I am using centos7 server and kamailio veriosn 5.9.3
dispatcher.list file was not there in /etc/kamailio/ directory so I copied from kamailio source directory
Please help me