Dynamic Routing Module

   Voice Sistem SRL

Edited by

Anca-Maria Vamanu

   Copyright © 2005-2008 voice-system.ro
   Revision History
   Revision $Revision: 6131 $ $Date: 2009-07-21 10:45:05 +0300
                              (Tue, 21 Jul 2009) $
     __________________________________________________________

   Table of Contents

   1. Admin Guide

        1.1. Overview

              1.1.1. Introduction
              1.1.2. Features
              1.1.3. Performance
              1.1.4. Routing Rule Definition
              1.1.5. Routing Rule Processing

        1.2. Dependencies

              1.2.1. OpenSIPS Modules
              1.2.2. External Libraries or Applications

        1.3. Exported Parameters

              1.3.1. db_url(str)
              1.3.2. drd_table(str)
              1.3.3. drr_table(str)
              1.3.4. drg_table(str)
              1.3.5. drl_table(str)
              1.3.6. ruri_avp (str)
              1.3.7. attrs_avp (str)
              1.3.8. define_blacklist (str)
              1.3.9. use_domain (int)
              1.3.10. drg_user_col (str)
              1.3.11. drg_domain_col (str)
              1.3.12. drg_grpid_col (str)
              1.3.13. fetch_rows (int)
              1.3.14. force_dns (int)

        1.4. Exported Functions

              1.4.1. do_routing([[groupID],sort])
              1.4.2. use_next_gw()/next_routing()
              1.4.3. goes_to_gw([[type],flags])
              1.4.4. is_from_gw( [type, [flag]])

        1.5. Exported MI Functions

              1.5.1. dr_reload

        1.6. Installation

   2. Developer Guide

   List of Tables

   1.1. Definition of table dr_gateways
   1.2. Sample dr_gateways records
   1.3. Definition of dr_rules table
   1.4. Time recurrence attributes
   1.5. Sample dr_rules records

   List of Examples

   1.1. Set db_url parameter
   1.2. Set drd_table parameter
   1.3. Set drr_table parameter
   1.4. Set drg_table parameter
   1.5. Set drl_table parameter
   1.6. Set ruri_avp parameter
   1.7. Set attrs_avp parameter
   1.8. Set define_blacklist parameter
   1.9. Set use_domain parameter
   1.10. Set drg_user_col parameter
   1.11. Set drg_domain_col parameter
   1.12. Set drg_grpid_col parameter
   1.13. Set fetch_rows parameter
   1.14. Set force_dns parameter
   1.15. do_routing usage
   1.16. use_next_gw usage
   1.17. goes_to_gw usage
   1.18. is_from_gw usage

Chapter 1. Admin Guide

1.1. Overview

1.1.1. Introduction

   Dynamic Routing is a module for selecting (based on multiple
   criteria) the the best gateway/destination to be used for
   delivering a certain call. Least Cost Routing (LCR) is a
   special case of dynamic routing - when the rules are ordered
   based on costs. Dynamic Routing comes with many features
   regarding routing rule selection:
     * prefix based
     * caller/group based
     * time based
     * priority based

   , processing :
     * stripping and prefixing
     * default rules
     * inbound and outbound processing
     * script route triggering

   and failure handling:
     * serial forking
     * weight based GW selection
     * random GW selection

1.1.2. Features

   The dynamic routing implementation for OpenSIPS is designed
   with the following properties:
     * routing info (destinations, rules, groups) are stored in a
       database and loaded into memory at start up time; reload at
       runtime via MI command
     * load balancing or random selection of the destinations
       (from a given set)
     * able to handle large volume of routing info (300K of rules)
       with minimal speed/time and memory consumption penalties
     * script integration - Pseudo variables support in functions;
       scripting route triggering when rules are matched
     * bidirectional behavior - inbound and outbound processing
       (strip and prefixing when sending and receiving from a
       destination/GW)
     * blacklisting - the module allows definition of backlists
       based on the destination IPs. This blacklists are to be
       used to prevent malicious forwarding to GWs (based on DNS
       lookups) when the script logic does none-GE forwarding
       (like foreign domains).

1.1.3. Performance

   There were several tests performed regarding the performance of
   the module when dealing with a large number of routing rules.

   The tests were performed with a set of 383000 rules and to
   values were measured:
     * time to load from DB
     * used shared memory

   The time to load was varying between 4 seconds and 8 seconds,
   depending of the caching of the DB client - the first load was
   the slowest (as the DB query hits the disk drive); the
   following are faster as data is already cached in the DB
   client. So technically speaking, the time to load (without the
   time to query which is DB type dependent) is ~4 seconds

   After loading the data into shared memory ~ 96M of memory were
   used exclusively for the DR data.

1.1.4. Routing Rule Definition

   Dynamic routing rules are stored in a database, in four tables:
     * one for storing the gateway definitions
     * one for storing the routing rule definitions
     * one for storing the users mappings over groups
     * one for storing a list of gateways, so you don't have to
       enter all the elements every time you need it

1.1.4.1. Gateway Addresses

   Default name for the table storing gateway addresses is
   "dr_gateways". Gateway addresses are stored in a separate table
   because of need to access them independent of Dynamic Routing
   processing (e.g., adding/ removing gateway PRI prefix
   before/after performing other operation -- receiving/relaying
   to gateway).

   Table 1.1. Definition of table dr_gateways
   Column name     Type     Default value         Description
   gwid        integer      auto increment unique identifier for GW
   type        unsigned int 0              type/class of GW
   address     varchar(128)                address of the gateway
   strip       unsigned int 0              no of digits to strip
   pri_prefix  varchar(255)                PRI prefix of the gateway
   description varchar(128)                description of the gateway

   Once a rule is matched, the STRIP number of digits are removed
   from the username part of the RURI and then the PRI prefix has
   to be added to the request URI before forwarding the call to
   the gateway.

   Table 1.2. Sample dr_gateways records
   gwid type     address      strip pri_prefix description
   1    10   10.10.10.10:5080 0     2222       Gateway 1
   2    10   10.10.10.10      2     3333       Gateway 2
   3    20   10.10.10.11      0                Gateway 3

1.1.4.2. Destination/GW lists

   For each rule, you can set a list of destinations to be used.
   The list is comma or pipe separated enumeration of the
   destinations. The module will use (one by one) each destination
   from the list (in the given order).

   Also the module allows the usage of groups in the destination
   lists. A group of destinations is delimited by semi-colon char.
   inside the whole destination list ( like: 2,4;5,78,23;4;7;2 ).
   The destinations from within a group may be act differently
   (like load-balancing, random selection, etc), depending of the
   "sort_order" parameter - more about this is available under the
   "do_routing()" function section.

1.1.4.3. Routing Rules

   Default name for the table storing rule definitions is
   "dr_rules".

   Table 1.3. Definition of dr_rules table
   Column name     Type     Default            Description
   ruleid      integer      auto    UID of the rule
   groupid     varchar(255)         list of routing group IDs
   prefix      varchar(64)          destination prefix for this route
   timerec     varchar(255)         time recurrence for this rule
   priority    integer      0       priority of the rule
   routeid     integer      0       route block to be execute
   gwlist      varchar(255)         the list with GWs to be used
   description varchar(128)         description of this rule

    a. groupid column
       Each user must be member of only one routing group. It must
       be specified in user's profile.
    b. prefix column
       Destination URI must start with prefix value to match the
       rule.
    c. time rec column
       A date-time expression that defines the time recurrence to
       match for current rule. Time recurrences are based closely
       on the specification of recurring intervals of time in the
       Internet Calendaring and Scheduling Core Object
       Specification (calendar COS), RFC 2445. The set of
       attributes used in routing rule specification is subset of
       time recurrence attributes used by Call Processing Language
       (CPL). These attributes are (extracted from CPL draft 09):
       Table 1.4. Time recurrence attributes

       Attribute                     Description
       dastard    Start of interval (RFC 2445 DATE-TIME)
       duration   Length of interval (RFC 2445 DURATION)
       freq       Frequency of recurrence (secondly,minutely,hourly,
                  daily,weekly, monthly, or yearly).
       until      bound of recurrence (RFC 2445 DATE-TIME)
       interval   How often the recurrence repeats
       byday      List of days of the week
       bymonthday List of days of the month
       byyearday  List of days of the year
       byweekno   List of weeks of the year
       bymonth    List of months of the year
       The value stored in database has the format of:
       <dtstart>|<duration>|<freq>|<until>|<interval>|<byday>|<bym
       onthday>|<byyearday>|<byweekno>|<bymonth>
       When an attribute is not specified, the corresponding place
       must be left empty, whenever another attribute that follows
       in the list has to be specified.
       Detailed description of time recurrence attributes:
          + dtstart - specifies the beginning of the first period.
          + duration - specifies the duration of the period. For a
            recurring interval, the "duration" parameter MUST be
            small enough such that subsequent intervals do not
            overlap. For non-recurring intervals, durations of any
            positive length are permitted, zero-length duration
            means "forever". Negative-length durations are not
            allowed.
          + freq - takes one of the following values: "daily", to
            specify repeating periods based on an interval of a
            day or more; "weekly", to specify repeating periods
            based on an interval of a week or more; "monthly", to
            specify repeating periods based on an interval of a
            month or more; and "yearly", to specify repeating
            periods based on an interval of a year or more. These
            values are not case-sensitive.
          + until - defines an iCalendar COS DATE or DATE-TIME
            value which bounds the recurrence rule in an inclusive
            manner. If the value specified by "until" is
            synchronized with the specified recurrence, this date
            or date-time becomes the last instance of the
            recurrence. If not present, the recurrence is
            considered to repeat forever.
          + interval - contains a positive integer representing
            how often the recurrence rule repeats. The default
            value is "1", meaning every day for a "daily" rule,
            every week for a "weekly" rule, every month for a
            "monthly" rule and every year for a "yearly" rule.
          + interval - contains a positive integer representing
            how often the recurrence rule repeats. The default
            value is "1", meaning every day for a "daily" rule,
            every week for a "weekly" rule, every month for a
            "monthly" rule and every year for a "yearly" rule.
          + byday - specifies a comma-separated list of days of
            the week. "MO" indicates Monday; "TU" indicates
            Tuesday; "WE" indicates Wednesday; "TH" indicates
            Thursday; "FR" indicates Friday; "SA" indicates
            Saturday; "SU" indicates Sunday. These values are not
            case-sensitive.
            Each "byday" value can also be preceded by a positive
            (+n) or negative (-n) integer. If present, this
            indicates the nth occurrence of the specific day
            within the "monthly" or "yearly" recurrence. For
            example, within a "monthly" rule, +1MO (or simply 1MO)
            represents the first Monday within the month, whereas
            -1MO represents the last Monday of the month. If an
            integer modifier is not present, it means all days of
            this type within the specified frequency. For example,
            within a "monthly" rule, MO represents all Mondays
            within the month.
          + bymonthday - parameter specifies a comma-separated
            list of days of the month. Valid values are 1 to 31 or
            -31 to -1. For example, -10 represents the tenth to
            the last day of the month.
          + byyearday - specifies a comma-separated list of days
            of the year. Valid values are 1 to 366 or -366 to -1.
            For example, -1 represents the last day of the year
            (December 31st) and -306 represents the 306th to the
            last day of the year (March 1st).
          + byweekno - specifies a comma-separated list of
            ordinals specifying weeks of the year. Valid values
            are 1 to 53 or -53 to -1.
          + bymonth - parameter specifies a comma-separated list
            of months of the year. Valid values are 1 to 12.
       A recurrence is specified by including the "freq"
       parameter, which indicates the type of recurrence rule.
       Parameters other than "dtstart" and "duration" SHOULD NOT
       be specified unless "freq" is present.
       If byxxx parameter values are found which are beyond the
       available scope (ie, bymonthday="30" in February), they are
       simply ignored.
       Byxxx parameters modify the recurrence in some manner.
       Byxxx rule parts for a period of time which is the same or
       greater than the frequency generally reduce or limit the
       number of occurrences of the recurrence generated. For
       example, freq="daily" bymonth="1" reduces the number of
       recurrence instances from all days (if the "bymonth"
       parameter is not present) to all days in January. Byxxx
       parameters for a period of time less than the frequency
       generally increase or expand the number of occurrences of
       the recurrence. For example, freq="yearly" bymonth="1,2"
       increases the number of days within the yearly recurrence
       set from 1 (if "bymonth" parameter is not present) to 2.
       If multiple Byxxx parameters are specified, then after
       evaluating the specified "freq" and "interval" parameters,
       the Byxxx parameters are applied to the current set of
       evaluated occurrences in the following order: "bymonth",
       "byweekno", "byyearday", "bymonthday", "byday"; then
       "until" is evaluated.
       Here is an example of evaluating multiple Byxxx parameters.
       dtstart="19970105T083000" duration="10M" freq="yearly"
       interval="2" bymonth="1" byday="SU"
       First, the interval="2" would be applied to freq="yearly"
       to arrive at "every other year" . Then, bymonth="1" would
       be applied to arrive at "every January, every other year".
       Then, byday="SU" would be applied to arrive at "every
       Sunday in January, every other year, from 8:30 to 8:40 ".
       The appropriate minutes and hours have been retrieved from
       the "dtstart" and "duration" parameters.
    d. priority column
       If many rules are eligible, choose the one with highest
       priority.
    e. routeid column
       If different than 0, then execute the route with the
       specified ID. That is, a route which can be used to perform
       custom operations on message. At this route, no
       modification is performed at signaling level.
    f. gwlist column
       A comma separated list of gateway identifiers corresponding
       to a row in table "dr_gateways". The first gateway is tried
       first and if failure the second one, and so one. If no
       gateway is left a negative response is sent back to the
       user. You can use a predefined list from the table
       "dr_gw_lists" preceded by the character "#".
    g. Routing Rules Examples
       Table 1.5. Sample dr_rules records

   ruleid group prefix timerec priority routeid gwlist description
   1 6 0049 20040101T083000|10H|weekly|||MO,TU,WE,TH,FR 5 23 1,2
   Rule 1
   2 8 0049 20040101T083000 0 0 1,2 Rule 2
   3 7,8,9 0049 20040101T083000 0 0 3 Rule 3
       (The time recurrence for first rule is:
       "20040101T083000|10H|weekly|||MO,TU,WE,TH,FR")

1.1.5. Routing Rule Processing

   The module can be used to find out which is the best gateway to
   use for new calls terminated to PSTN. The algorithm to select
   the rule is as follows:
     * the module discovers the routing group of the originating
       user. This step is skipped if a routing group is passed
       from the script as parameter.
     * once the group is known, in the subset of the rules for
       this group the module looks for the one that matches the
       destination based on "prefix" column. The set of rules with
       the longest prefix is chosen. If no digit from the prefix
       matches, the default rules are used (rules with no prefix)
     * within the set of rules is applied the time criteria, and
       the rule which has the highest priority and matches the
       time criteria is selected to drive the routing.
     * Once found the rule, it may contain a route ID to execute.
       If a certain flag is set, then the processing is stopped
       after executing the route block.
     * The rule must contain a gateway chain. The module will
       execute serial forking for each address in chain. The next
       address in chain is used only if the previously has failed.
     * With the right gateway address found, the prefix (PRI) of
       the gateway is added to the request URI and then the
       request is forwarded.

   If no rule is found to match the selection criteria an default
   action must be taken (e.g., error response sent back). If the
   gateway in the chain has no prefix the request is forwarded
   without adding any prefix to the request URI.

1.2. Dependencies

1.2.1. OpenSIPS Modules

   The following modules must be loaded before this module:
     * a database module.

1.2.2. External Libraries or Applications

     * none.

1.3. Exported Parameters

1.3.1. db_url(str)

   The database url.

   Default value is "NULL".

   Example 1.1. Set db_url parameter
...
modparam("drouting", "db_url",
        "mysql://opensips:opensipsrw@localhost/opensips")
...

1.3.2. drd_table(str)

   The name of the db table storing gateway addresses.

   Default value is "dr_gateways".

   Example 1.2. Set drd_table parameter
...
modparam("drouting", "drd_table", "dr_gateways")
...

1.3.3. drr_table(str)

   The name of the db table storing routing rules.

   Default value is "dr_rules".

   Example 1.3. Set drr_table parameter
...
modparam("drouting", "drr_table", "rules")
...

1.3.4. drg_table(str)

   The name of the db table storing groups.

   Default value is "dr_groups".

   Example 1.4. Set drg_table parameter
...
modparam("drouting", "drg_table", "groups")
...

1.3.5. drl_table(str)

   The name of the db table storing definitions of destination
   lists (to be used directly by the routing rules). You will have
   a identifier to a group of gateways instead of having all the
   members of the group as a individual elements. Very useful to
   reuse a list of gateways in different places.

   Default value is "dr_gw_lists".

   Example 1.5. Set drl_table parameter
...
modparam("drouting", "drl_table", "my_gw_lists")
...

1.3.6. ruri_avp (str)

   The name of the avp for storing Request URIs to be later used
   (alternative destiantions for the current one).

   Default value is "NULL".

   Example 1.6. Set ruri_avp parameter
...
modparam("drouting", "ruri_avp", '$avp(dr_ruri)')
modparam("drouting", "ruri_avp", '$avp(i:33)')
...

1.3.7. attrs_avp (str)

   The name of the avp for storing the attribute of the current
   selected destination - once a new destination is selected (via
   the use_next_gw() function), the AVP will be updated with the
   attrs of the new used destination.

   Default value is "NULL".

   Example 1.7. Set attrs_avp parameter
...
modparam("drouting", "attrs_avp", '$avp(dr_attrs)')
modparam("drouting", "atrrs_avp", '$avp(i:67)')
...

1.3.8. define_blacklist (str)

   Defines a backlist based on a list of GW types - the list will
   contain the IPs (no port, all protocols) of the GWs with the
   specified types.

   Multiple instances of this param are allowed.

   Default value is "NULL".

   Example 1.8. Set define_blacklist parameter
...
modparam("drouting", "define_blacklist", 'bl_name= 3,5,25,23')
modparam("drouting", "define_blacklist", 'list= 4,2')
...

1.3.9. use_domain (int)

   Flag to configure whether to use domain match when querying
   database for user's routing group.

   Default value is "1".

   Example 1.9. Set use_domain parameter
...
modparam("drouting", "use_domain", 0)
...

1.3.10. drg_user_col (str)

   The name of the column in group db table where the username is
   stored.

   Default value is "username".

   Example 1.10. Set drg_user_col parameter
...
modparam("drouting", "drg_user_col", "user")
...

1.3.11. drg_domain_col (str)

   The name of the column in group db table where the domain is
   stored.

   Default value is "domain".

   Example 1.11. Set drg_domain_col parameter
...
modparam("drouting", "drg_domain_col", "host")
...

1.3.12. drg_grpid_col (str)

   The name of the column in group db table where the group id is
   stored.

   Default value is "groupid".

   Example 1.12. Set drg_grpid_col parameter
...
modparam("drouting", "drg_grpid_col", "grpid")
...

1.3.13. fetch_rows (int)

   The number of rows that should be fetched from the result of a
   query in rules db table.

   Default value is "2000".

   Example 1.13. Set fetch_rows parameter
...
modparam("drouting", "fetch_rows", 1500)
...

1.3.14. force_dns (int)

   Force DNS resolving of GW/destination names (if not IPs) during
   startup. If not enabled, the GW name will be blindly used
   during routing.

   Default value is "1 (enabled)".

   Example 1.14. Set force_dns parameter
...
modparam("drouting", "force_dns", 0)
...

1.4. Exported Functions

1.4.1.  do_routing([[groupID],sort])

   Function to trigger routing of the message according to the
   rules in the database table and the configured parameters.

   This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.

   The function can take two optional parameters:
     * groupID - the routing group the caller belongs to - this
       may be a static numerical value or an AVP specification. If
       none specified, the function will automatically try to
       query the dr_group table to get this information;
     * sort_order - defines how the destination list should be
       processed (ordering of the elements). Possible modes are
          + 0 - destination groups are ignored and all the
            destinations are tried in the given order; Ex: list
            1,2;3,4,5;6 will lead to usage as 1,2,3,4,5,6
          + 1 - the destinations from each group are randomly
            arranged (only the two elements are randomly
            selected); groups do maintain their order (as given);
            the resulting list is used (with all the defined
            destinations). Ex: 1,2;3,4,5;6 -> randomizer -> (A)
            2,1;4,3,5;6 -> usage 2,1,4,3,5,6 (B) 1,2;3,5,4;6 ->
            usage 1,2,3,5,4,6
          + 2 - from each destination group, only a single
            destination is randomly selected; groups do maintain
            their order (as given); Ex: 1,2;3,4,5;6 -> randomizer
            -> (A) 2;4;6 -> usage 2,4,6 (B) 1;5;6 -> usage 1,5,6

   Example 1.15. do_routing usage
...
# all groups, sort 0
do_routing();
...
# group id 0, sort 0
do_routing("0");
...
# group id from $avp(i:10), sort 0
do_routing("$avp(i:10)");
...
# all groups, sort 1
do_routing("","1");
...
# group id 2, sort 2
do_routing("2","2");
...

1.4.2.  use_next_gw()/next_routing()

   The function takes the next available destination (set by
   do_routing, as alternative destinations) and push it into RURI.
   Note that the function just sets the RURI (nothing more).

   If a new RURI is set, the used destination is removed from the
   pending set of alternative destinations.

   This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.

   The function returns true only if a new RURI was set. False is
   returned is no other alternative destinations are found or in
   case of internal processing error.

   Example 1.16. use_next_gw usage
...
if (use_next_gw()) {
        t_relay();
        exit;
}
...

1.4.3.  goes_to_gw([[type],flags])

   Function returns true if the destination of the current request
   (destination URI or Request URI) points (as IP) to one of the
   gateways. There no DNS lookups done if the domain part of the
   URI is not an IP.

   This function does not change anything in the message.

   This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.

   The function can take two optional parameters:
     * type (optional) - GW/destination type to be checked
     * flags (optional) - what operations should be performed when
       a GW matches:
          + 's' (Strip) - apply to the username of RURI the strip
            defined by the GW
          + 'p' (Prefix) - apply to the username of RURI the
            prefix defined by the GW
          + 'a' (Attributes) - return the attributes string
            defined by the GW

   Example 1.17. goes_to_gw usage
...
if (goes_to_gw("1")) {
        sl_send_reply("403","Forbidden");
        exit;
}
...

1.4.4.  is_from_gw( [type, [flag]])

   The function checks if the sender of the message is a gateway
   from a certain group.

   This function can be used from REQUEST_ROUTE and FAILURE_ROUTE.

   The function can take two optional parameters:
     * type (mandatory) - GW/destination type to be checked
     * flags (optional) - what operations should be performed when
       a GW matches:
          + 's' (Strip) - apply to the username of RURI the strip
            defined by the GW
          + 'p' (Prefix) - apply to the username of RURI the
            prefix defined by the GW
          + 'a' (Attributes) - return the attributes string
            defined by the GW

   Example 1.18. is_from_gw usage
...
if (is_from_gw("3","1") {
}
...

1.5. Exported MI Functions

1.5.1.  dr_reload

   Command to reload routing rules from database.

   It takes no parameter.

   MI FIFO Command Format:
                :dr_reload:fifo_reply
                _empty_line_

1.6. Installation

   The module requires 3 table in OpenSIPS database: dr_groups,
   dr_gateways, dr_rules. The SQL syntax to create them can be
   found in drouting-create.sql script in the database directories
   in the opensips/scripts folder. You can also find the complete
   database documentation on the project webpage,
   http://www.opensips.org/html/docs/db/db-schema-devel.html.

Chapter 2. Developer Guide

   The module provides no function to be used by other OpenSIPS
   modules.
