Least-Cost Routing with Kamailio v4.1

The goal of this document is to explain how to get Kamailio to route traffic to the carrier with the least cost. This is part 2 in our Kamailio series.

 Getting Started

You don’t need much for this tutorial. All you’ll need is 2 carrier endpoints and their rates for calling a certain area code. Other than a Kamailio server, you can proceed with the rest of the tutorial.

 Configuring Kamailio 

Before we start setting up the LCR module, we first need to make some changes to the Kamailio configuration file. First off, we will need to modify the listen parameter. Open up your Kamailio configuration (kamailio.cfg) and look for the “listen” line.

If your Kamailio instance is behind a firewall make your line look like this:

listen=udp:<internal address>:5060 advertise <external address>:5060

Else if your Kamailio instance is on the public internet make it look like this:

listen=udp:<external address>:5060

By default Kamailio does not load the LCR module so we will need to add it.  In the same config file, locate the section where it says “loadmodule” and go to the bottom of that list and add:

loadmodule “lcr.so”

We can now begin setting up the LCRs module parameters.

Configuring LCR Module 

Now that we’ve configured Kamailio, we need to configure the LCR module. Back in the configuration file, look for the module parameters section.  At the bottom of that section, add the following values:

modparam("lcr", "db_url", "mysql://kamailioro:kamailioro@localhost/kamailio")
modparam("lcr", "gw_uri_avp", "$avp(i:709)")
modparam("lcr", "ruri_user_avp", "$avp(i:500)")
modparam("lcr", "tag_avp", "$avp(lcr_tag)")
modparam("lcr", "flags_avp", "$avp(i:712)")
modparam("lcr", "lcr_id_avp", "$avp(s:lcr_id_avp)")
modparam("lcr", "defunct_gw_avp", "$avp(s:defunct_gw_avp)")

With the module configured, it’s time to setup the actual routing of the SIP requests. In the “request_route” above the line that says:

 # dispatch request to foreign domains

Add the following line:

 route(LCR);

Then add a new route using the code below, put this at the end of the file:

route[LCR] {
if (status=="200")
{
  xlog("LCR: Inside the LCR routen");
}

if(method=="INVITE")
{
  xlog("We got an invite");
  if(!load_gws(1, $rU, $var(caller_uri))) {
    xlog("Couldn't load gateways");
    sl_send_reply("500", "Server Internal Error - Cannot load gateways");
    exit;
  } else {
        xlog("GW Selected '$avp(i:709)'n");
        xlog("Domain of destination: $ddn");
        xlog("To URI: $tun");
  }

  if(!next_gw()) {
    xlog("Couldn't proceed to next gateway");
    sl_send_reply("503", "Service not available, no gateways found");
    exit;
  } else {
        xlog("Calling the first matched gatewayn");
        xlog("ruri_user_avp: '$avp(i:500)'n");
        xlog("To URI after next_gw: $tun");
        xlog("Request URI: $rUn");

  }

}
}

 

Adding LCR Data

With our routing code in place, we need to add some data to LCR tables. Before we do that let’s go over what tables the LCR module uses and how they all fit together.

There are 3 tables that the LCR module uses:

  • lcr_gw  – holds the gateways or endpoints where we can send our requests
  • lcr_rule – holds all the rules we will match against. Our area codes. 
  • lcr_rule_target – holds the rule to gateway matchings.

The most important table is the lcr_rule_target table. In this table, we take the ID of the rule from the lcr_rule table and connect it to the ID of the gateway we want all requests to go out of of it the request matches that rule.

For instance, if we setup a rule in the table that matches all request that start with 734 with an ID of 12, we can match that to a gateway ID in the lcr_rule_target table. So when a request comes in that starts with 734, it will be sent to that gateway.

For this example, we will be using 734 as the area code and 192.168.1.112 as the carrier. You can replace these values with your own in the steps below.

  1.   Login to MySQL
 # mysql -u root -p
  1.   Connect to the Kamailio DB
 mysql> use kamailio;
  1.   Let’s insert a gateway.
mysql> INSERT INTO lcr_gw (lcr_id, gw_name, ip_addr, port, uri_scheme, transport, strip, flags) VALUES (1, “Carrier1”, “192.168.1.112”, 5060, 1, 1, 0, 1);
  1.   Next let’s add an LCR rule.
mysql> INSERT INTO lcr_rule (lcr_id, prefix, stopper, enabled) VALUES (1, “734”, 1, 1);
  1.   Finally let’s add rule to gateway matching.
mysql> INSERT INTO lcr_rule_target (lcr_id, rule_id, gw_id, priority, weight) VALUES (1, 1, 1, 1, 1);

Repeat these steps for each of your carriers. Increase the weight for the carrier with the cheaper weight.

Testing Kamailio

Before we begin testing we need to make sure a few other things are in order. You’ll need to make sure that your ITSP knows you’re going to be sending traffic from your Kamailio IP address. You’ll also need a SIP phone pointed at Kamailio or have Kamailio setup as a trunk in a PBX.

With that said, we need to refresh what Kamailio has in memory. We can do this with:

# kamctl lcr reload

 

Now just call that area code from a phone and your call should go out of the carrier with the higher weight.