Skip to main content

Advanced SBC with mod_lcr and mod_easyroute

About

by Meftah Tayeb

Below you'll find a step by step guide for installing FreeSWITCH™ as a SBC. The LCR engine is provided by mod_lcr. The DID routing is done by mod_easyroute

This is all still development work and needs testing.

Installation

Install Debian stable netinstall

https://www.debian.org/releases/jessie/debian-installer/

Upgrade debian distribution

  apt-get update

apt-get dist-upgrade


Install SSH Server for remote administration

  apt-get install ssh

This will add MySQL enter a password etc.

  apt-get install gcc bison flex make openssl libmysqlclient15-dev libradiusclient-ng2 libradiusclient-ng-dev mysql-server libxmlrpc-c3-dev

Install FreeSWITCH dependencies

  apt-get install subversion subversion-tools automake1.9 gcc-4.1 autoconf make wget libtool g++ libncurses5 libncurses5-dev
 apt-get install debhelper automake1.9 autoconf libtool unixodbc-dev libasound2-dev libcurl4-openssl-dev libssl-dev libogg-dev
libvorbis-dev libperl-dev libgdbm-dev libdb-dev libgnutls-dev libspandsp-dev libtiff4-dev
 apt-get install screen bridge-utils libmysql++-dev libconfuse-dev libpcre3-dev curl libcurl4-gnutls-dev

  apt-get install libxml2-dev libmemcache-dev

Restart server

  reboot

Install utils for compilation

  apt-get install build-essential

Download FreeSWITCH latest trunk and put them in /usr/src/freewitch

cd /usr/src/

wget -O - https://files.freeswitch.org/repo/deb/debian/freeswitch_archive_g0.pub | apt-key add -
echo "deb http://files.freeswitch.org/repo/deb/debian-unstable/ jessie main" >> /etc/apt/sources.list.d/freeswitch.list
apt-get update
apt-get install -y --force-yes freeswitch-video-deps-most


git config --global pull.rebase true
git clone https://freeswitch.org/stash/scm/fs/freeswitch.git /usr/src/freeswitch

cd /usr/src/freeswitch
./bootstrap.sh

Edit modules.conf depending on your needs but you must enable mod_easyroute and mod_lcr modules. I recommend disabling mod_voicemail and mod_conferencing this is an SBC not a softswitch.

Enable mod_easyroute & mod_lcr in trunk/modules.conf by uncommenting the lines.

#applications/mod_easyroute 
#applications/mod_lcr
 ./configure -prefix=/usr/local/freeswitch --enable-core-odbc-support 
make
make install
make sounds-install
make moh-install

Upgrade to latest git

 cd /usr/src/freeswitch
make current

and that's it you get the latest git in /usr/src/freeswitch

Edit sip_profiles to use our outside IP

cd /usr/local/freeswitch/conf/sip_profiles

edit external.xml and replace $${local_ip_v4} and $${external_rtp_ip} your external IP. You will use external profiles for all endpoints. We will need to add security later. I also recommend you swap the internal port 5060 with the default port 5080. Most providers use 5060.

Optimizations before launching FreeSwitch

  ulimit -c unlimited
ulimit -d unlimited
ulimit -f unlimited
ulimit -i unlimited
ulimit -n 999999
ulimit -q unlimited
ulimit -u unlimited
ulimit -v unlimited
ulimit -x unlimited
ulimit -s 240
ulimit -l unlimited
ulimit -a

Start FreeSWITCH verify it works before we go too far.

 cd /usr/local/freeswitch/bin/
./freeswitch -hp

-hp stands for high priority

You may see errors about ODBC not loaded

To connect to FreeSWITCH via fs_cli Command Line

  cd /usr/local/freeswitch/bin/
./fs_cli

with this tool you'll be able to get a console connection to FS the log level has not been changed so it could be very verbose to disable log, type /nolog in console

To Check if FS is running

 netstat -unlp 

Tell FreeSWITCH to actually use MOD_Easyroute & MOD_LCR module when running. Add the modules to modules.conf.xml in /usr/local/freeswitch/conf/autoload_configs.

  <load module="mod_easyroute"/>
<load module="mod_lcr"/>

Also disable any unused codecs, mod_voicemail and mod_conferencing

Now we need to enable odbc. This is for a mysql database.

  apt-get install unixodbc
apt-get install libmyodbc

Configuring ODBC

Basic odbcinst.ini:

This is where you configure your various odbc drivers. On Debian systems the file was in /etc/odbcinst.ini

   [MySQL]
Description = MySQL driver
Driver = /usr/lib/odbc/libmyodbc.so
Setup = /usr/lib/odbc/libodbcmyS.so
CPTimeout =
CPReuse =
FileUsage = 1

Note: you may have to change the path to the .so files depending on where they are installed. Default location for Debian: /usr/lib/odbc/

Basic odbc.ini:

This is where you configure your datasources. Your configs will reference [MySQL-free] since this is an ODBC connection. On Debian systems the file was in /etc/odbc.ini```

   [MySQL-free] <--note free is a database we will create -->
Description = MySQL ODBC Database
TraceFile = stderr
Driver = MySQL
SERVER = localhost
USER = root
PASSWORD = password
DATABASE = free <-- Your DSN -- >

easyroute.conf.xml

This file is in /usr/local/freeswitch/conf/autoload_configs The easyroute.conf.xml file will need to be configured with the settings for your database:

   <param name="db-username" value="root"/>
<param name="db-password" value="password"/>
<param name="db-dsn" value="MySQL-free"/>
<param name="default-techprofile" value="sofia/default"/>
<param name="default-gateway" value="192.168.66.6"/>

NOTE: The default technology profile and default gateway will be returned if the db lookup fails.

lcr.conf.xml & switch.conf.xml & db.conf.xml

These files are in /usr/local/freeswitch/conf/autoload_configs They will need to be configured with the settings for your database:

  <param name="odbc-dsn" value="MySQL-free:root:password"/>

Create MySQL database

    mysql --user=root --password=password
create database free;

Okay now we need to create the tables - check the latest code first. There should be .sql files in the trunk but they normally are Postgresql or need tweaked.

 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

DROP TABLE IF EXISTS `gateways`;
CREATE TABLE `gateways` (
`gateway_id` int(10) unsigned NOT NULL auto_increment,
`gateway_ip` varchar(16) NOT NULL,
`group` varchar(15) NOT NULL,
`limit` int(10) unsigned NOT NULL,
`techprofile` varchar(128) NOT NULL,
PRIMARY KEY (`gateway_id`),
KEY `gateway_ip` (`gateway_ip`,`group`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='Gateways Table';
LOCK TABLES `gateways` WRITE;

/*!40000 ALTER TABLE `gateways` DISABLE KEYS */;
INSERT INTO `gateways` VALUES (1,'192.168.99.1','mustang',50,'sofia/default');

/*!40000 ALTER TABLE `gateways` ENABLE KEYS */;
UNLOCK TABLES;

DROP TABLE IF EXISTS `numbers`;
CREATE TABLE `numbers` (
`number_id` int(10) unsigned NOT NULL auto_increment,
`gateway_id` int(10) unsigned NOT NULL,
`number` varchar(16) NOT NULL,
`acctcode` varchar(16) NOT NULL,
`translated` varchar(16) NOT NULL,
PRIMARY KEY (`number_id`),
UNIQUE KEY `number` (`number`),
KEY `gateway_id` (`gateway_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Numbers Table';
LOCK TABLES `numbers` WRITE;

/*!40000 ALTER TABLE `numbers` DISABLE KEYS */;
INSERT INTO `numbers` VALUES (1,1,'19018577141','999999', '9018577141'),(2,1,'19995551212','666666', '9995551212');

/*!40000 ALTER TABLE `numbers` ENABLE KEYS */;
UNLOCK TABLES;

DROP TABLE IF EXISTS `lcr`;
CREATE TABLE `lcr` (
`id` int(11) NOT NULL auto_increment,
`digits` varchar(15) default NULL,
`rate` float(11,5) unsigned NOT NULL,
`intrastate_rate` float(11, 5) unsigned NOT NULL,
`intralata_rate` float(11, 5) unsigned NOT NULL,
`carrier_id` int(11) NOT NULL,
`lead_strip` int(11) NOT NULL,
`trail_strip` int(11) NOT NULL,
`prefix` varchar(16) NOT NULL,
`suffix` varchar(16) NOT NULL,
`lcr_profile` varchar(32) default NULL,
`date_start` datetime NOT NULL DEFAULT '1970-01-01',
`date_end` datetime NOT NULL DEFAULT '2030-12-31',
`quality` float(10,6) NOT NULL,
`reliability` float(10,6) NOT NULL,
`cid` varchar(32) NOT NULL DEFAULT ,
`enabled` boolean NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `carrier_id` (`carrier_id`),
KEY `digits` (`digits`),
KEY `lcr_profile` (`lcr_profile`),
KEY `rate` (`rate`),
KEY `digits_profile_cid_rate` USING BTREE (`digits`,`rate`),
CONSTRAINT `carrier_id` FOREIGN KEY (`carrier_id`) REFERENCES `carriers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `carriers`;
CREATE TABLE `carriers` (
`id` int(11) NOT NULL auto_increment,
`carrier_name` varchar(255) default NULL,
`enabled` boolean NOT NULL DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=latin1;

DROP TABLE IF EXISTS `npa_nxx_company_ocn`;
CREATE TABLE npa_nxx_company_ocn (
npa smallint NOT NULL,
nxx smallint NOT NULL,
company_type text,
ocn text,
company_name text,
lata integer,
ratecenter text,
state text
);
CREATE UNIQUE INDEX npanxx_idx USING BTREE ON npa_nxx_company_ocn (npa, nxx);

DROP TABLE IF EXISTS `carrier_gateway`;
CREATE TABLE `carrier_gateway` (
`id` int(11) NOT NULL auto_increment,
`carrier_id` int(11) default NULL,
`prefix` varchar(255) NOT NULL,
`suffix` varchar(255) NOT NULL,
`codec` varchar(255) NOT NULL,
`enabled` boolean NOT NULL DEFAULT '1',
PRIMARY KEY (`id`),
KEY `carrier_id` (`carrier_id`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=latin1;

/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

Create some table data

Now we have tables. You will want to populate the npa_nxx_company_ocn table

http://files.freeswitch.org/npa-nxx-companytype-ocn.csv

download this via ftp to you server. Enter into MySQL

  mysql --user=root --password=password 
connect free;
load data local infile 'npa-nxx-companytype-ocn.csv' into table npa_nxx_company_ocn
fields terminated by ','
enclosed by '"'
lines terminated by '\n';

That should have populated the database table with the NPA data.

Sample data for lcr

  -- insert two carriers
INSERT INTO carriers (id, carrier_name, enabled) VALUES (1, 'carrier1', 1);
INSERT INTO carriers (id, carrier_name, enabled) VALUES (2, 'carrier2', 1);

-- insert some gateway info
INSERT INTO carrier_gateway (id, carrier_id, prefix, suffix) VALUES (1, 1, 'sofia/gateway/carrier1/', );
INSERT INTO carrier_gateway (id, carrier_id, prefix, suffix) VALUES (2, 2, 'sofia/external/', '@proxy.carrier2.net:5060');

-- insert some lcr data
INSERT INTO lcr (id, digits, rate, carrier_id, lead_strip, trail_strip, prefix, suffix, date_start, date_end, quality, reliability)
VALUES (1, '1', 0.15, 1, 0, 0, , , current_timestamp - interval 1 year, current_timestamp + interval 1 year , 0, 0);
INSERT INTO lcr (id, digits, rate, carrier_id, lead_strip, trail_strip, prefix, suffix, date_start, date_end, quality, reliability)
VALUES (2, '1', 0.12, 2, 1, 0, '0', , current_timestamp - interval 1 year, current_timestamp + interval 1 year , 0, 0);
INSERT INTO lcr (id, digits, rate, carrier_id, lead_strip, trail_strip, prefix, suffix, date_start, date_end, quality, reliability)
VALUES (3, '1234', 0.05, 1, 0, 0, , , current_timestamp - interval 1 year, current_timestamp + interval 1 year , 0, 0);
INSERT INTO lcr (id, digits, rate, carrier_id, lead_strip, trail_strip, prefix, suffix, date_start, date_end, quality, reliability)
VALUES (4, '1234', 0.02, 2, 1, 0, '0', , current_timestamp - interval 1 year, current_timestamp + interval 1 year , 0, 0);

Testing our database connections

From the freeswitch command line issue something similar to:

 lcr 12145551111

Which would respond with something like:

   API CALL [lcr(12145551111)] output:
| Digit Match | Carrier | Rate | Dialstring |
| 1214 | carrier1 | 0.01000 | sofia/gateway/carrier1/12145551111 |
| 1 | carrier2 | 0.01440 | sofia/gateway/carrier2/12145551111

From the freeswitch command line issue something similar to:

  easyroute 19018577141
  Number          Limit           Group           AcctCode        Dialstring
19018577141 50 mustang 999999 sofia/default/9018577141@192.168.99.1

If this comes back our databases are working.

Okay now we need to use this data to route traffic. I don’t know if this is the best way to do this but hey we are all learning. I route my traffic based on the sending IP. This is also a means of security. If the sending IP isn’t in the dialplan it won’t route in theory.

Each SIP Trunk endpoint will need an extension in the dialplan Providers will need an easyroute extension & Customers will need a LCR extension.

This is a provider that sends me traffic and I route based on IP then DID database lookup. I have also added ringback and audio error if out of trunks just like a wireline carrier..

  <extension name="verizon">
<condition field="network_addr" expression="^216\.185\.35\.25$" break="on-false"/>
<condition field="destination_number" expression="^1?(\d{10})$" break="on-true">
<action application="set" data="instant_ringback=true"/>
<action application="set" data="ringback=%(2000,4000,440.0,480.0)"/>
<action application="easyroute" data="$1"/>
<action application="limit" data="db easyroute ${easy_group} ${easy_limit} LE-$1"/>
<action application="bridge" data="${easy_dialstring}"/>
</condition>
</extension>

Then we check that we are not over the limit for this trunk

   <extension name="easyroute_limit_exceeded">
<condition field="destination_number" expression="^LE-(\d{10})$" break="on-true">
<action application="answer" />
<action application="playback" data="/usr/local/freeswitch/sounds/en/us/callie/misc/8000/circuitsbusy.wav"/>
<action application="respond" data="503 Out of Channels"/>
</condition>
</extension>

This is a customer that sends me traffic and I route based on IP then LCR database lookup.

   <extension name="Customer_Outbound to PSTN 11 Digits">
<condition field="network_addr" expression="^192\.168\.1\.1$"/>
<condition field="destination_number" expression="^(1[2-9][0-9]{2}[2-9]{7})$">
<action application="lcr" data="$1"/>
<action application="bridge" data="${lcr_auto_route}"/>
</condition>
</extension>

Optimizations Stop FreeSWITCH /usr/local/freeswitch/bin/freeswitch -stop

Lowering FS Log Level vi /usr/local/freeswitch/conf/autoload_configs/switch.conf.xml

   <param name="loglevel" value="err"/>

Set Call Admission Control vi /usr/local/freeswitch/conf/autoload_configs/switch.conf.xml

 <param name="max-sessions" value="1000"/>
<param name="sessions-per-second" value="100"/>

With these settings, we have defined a maximum of 500 bridged calls (2*500 channels) and a maximum of 100 new sessions per second. You should set these parameters according to your hardware

Creation of a ramdisk for the FS database

   mv /usr/local/freeswitch/db /usr/local/freeswitch/db_old 
mkdir /usr/local/freeswitch/db
mount -t tmpfs tmpfs /usr/local/freeswitch/db

Use Proxy Media to keep FS in the RTP media path (topology hiding) but without analyzing RTP or DTMF vi /usr/local/freeswitch/conf/sip_profiles/external.xml

   <param name="inbound-late-negotiation" value="true"/>

Disable Presence Support in SIP_Profiles vi /usr/local/freeswitch/conf/sip_profiles/internal.xml

  <param name="manage-presence" value="false"/>

Okay at this point we have the general setup complete. You will need to add gateways and clean up the dialplan and add cdrs into the mix.. If you need help let me know I'm happy to help. This setup is the basic way most ITSP use SBCs. I need help with some things so If we want to start an SBC group I would be happy to help.

I’m really open to help on making a web interface for all this and making it more efficient. I pulled a lot of data from other posts please help move this along Thanks to all the Devel Teams' great work

Right now I use phpmyadmin to manage the SBC database.

Can I know you? I am Tayeb (aka DelphiWorld)