<!-- Module User's Guide -->

<chapter>

<title>&adminguide;</title>

<section id="overview" xreflabel="Overview">
	<title>Overview</title>
	<para>
	<emphasis>qrouting</emphasis> is a module which sits on top of
	<ulink url="../drouting/doc/drouting.html">drouting</ulink>,
	<ulink url="../dialog/doc/dialog.html">dialog</ulink> and
	<ulink url="../tm/doc/tm.html">tm</ulink> and performs live
	tracking of a series of essential gateway signaling quality indicators
	(i.e. ASR, CCR, PDD, AST, ACD -- more details below).  Thus, qrouting is
	able to adjust the prefix routing behavior at runtime, by dynamically
	re-ordering the gateways based on how well they perform during live
	traffic, such that:
	<itemizedlist>
		<listitem><para>
			well-performing gateways get prioritized for routing
		</para></listitem>
		<listitem><para>
			gateways which show a degradation in signaling quality are
			demoted to the end of the routing list
		</para></listitem>
	</itemizedlist>
	</para>
</section>

<section id="monitored_statistics" xreflabel="Monitored Statistics">
	<title>Monitored Statistics</title>
	<para>
	The module keeps track of a series of statistics, for each drouting
	<emphasis role='bold'>(prefix, destination)</emphasis> pair, where a
	"destination" may be either a gateway or a carrier.  The statistics are:
	<itemizedlist>
		<listitem>
			<para>ASR (Answer Seizure Ratio) - the percentage of telephone
				calls which are answered (200 reply status code).
			</para>
		</listitem>
		<listitem>
			<para>CCR (Call Completion Ratio) - the percentage of telephone
				calls which are answered back by the gateway, excluding
				5xx, 6xx reply codes and internal 408 timeouts.  The following
				is always true: CCR >= ASR.
			</para>
		</listitem>
		<listitem>
			<para>PDD (Post Dial Delay) - the duration, in milliseconds,
				between the receival of the initial INVITE and the receival
				of the first 180/183 provisional reply (the call state
				advances to <emphasis>"ringing"</emphasis>).
			</para>
		</listitem>
		<listitem>
			<para>AST (Average Setup Time) - the duration, in milliseconds,
				between the receival of the initial INVITE and the receival
				of the first 200 OK reply (the call state advances to
				<emphasis>"answered"</emphasis>).  The following is always
				true: AST >= PDD.
			</para>
		</listitem>
		<listitem>
			<para>ACD (Average Call Duration) - the duration, in seconds,
				between the receival of the initial INVITE and the receival
				of the first BYE request from either participant (the call
				state advances to <emphasis>"ended"</emphasis>).
			</para>
		</listitem>
	</itemizedlist>
	</para>
</section>

<!-- ============================= PARAM ================================  -->

<section id="dependencies" xreflabel="Dependencies">
	<title>Dependencies</title>
	<section id="deps_modules" xreflabel="OpenSIPS Module Dependencies">
		<title>&osips; Modules</title>
		<para>
		The following modules must be loaded for this module to work:
		<itemizedlist>
			<listitem><para><emphasis>an SQL DB module, offering access to the
						"qr_profiles" table</emphasis></para></listitem>
			<listitem><para><emphasis>tm</emphasis></para></listitem>
			<listitem><para><emphasis>dialog</emphasis></para></listitem>
			<listitem><para><emphasis>drouting</emphasis></para></listitem>
		</itemizedlist>
		</para>
	</section>
</section>

<section id="exported_parameters" xreflabel="Exported Parameters">
	<title>Exported Parameters</title>

	<section id="param_db_url" xreflabel="db_url">
		<title><varname>db_url</varname> (string)</title>
		<para>
		An SQL database URL.
		</para>
		<para>
			<emphasis>
			Default value is <emphasis role='bold'>NULL</emphasis>.
			</emphasis>
		</para>
		<example>
		<title>Setting the <varname>db_url</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "db_url", "mysql://opensips:opensipsrw@localhost/opensips")
	</programlisting>
		</example>
	</section>

	<section id="param_table_name" xreflabel="table_name">
		<title><varname>table_name</varname> (string)</title>
		<para>
		The name of the quality-based routing profiles table.
		</para>
		<para>
			<emphasis>
			Default value is <emphasis role='bold'>"qr_profiles"</emphasis>.
			</emphasis>
		</para>
		<example>
		<title>Setting the <varname>table_name</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "table_name", "qr_profiles_bak")
	</programlisting>
		</example>
	</section>

	<section id="param_algorithm" xreflabel="algorithm">
		<title><varname>algorithm</varname> (integer)</title>
		<para>
			Quality-based destination selection/balancing algorithm to use.
		</para>
		<para>
			Possible values:
			<itemizedlist>
				<listitem>
					<para>
					<emphasis role='bold'>"dynamic-weights"</emphasis> -
					for each prefix, all destinations start with equal
					weights and receive an equal share of the traffic.  As
					signaling statistics are gathered for the destinations, the
					ones which underperform will receive less traffic,
					based on the "penalty" columns of the
					<emphasis>qr_profiles</emphasis> table
					</para>
				</listitem>
				<listitem>
					<para>
					<emphasis role='bold'>"best-dest-first"</emphasis> - for each
					prefix, the 1st (i.e. <emphasis>best scoring</emphasis>)
					destination will receive all the traffic as long as its
					quality stays the same.  Initially, all destinations start
					with a perfect score.  This score may degrade if one or
					more signaling statistics fall below the "warn" or "crit"
					thresholds during routing, case in which the destinations
					will be sorted accordingly and traffic will be routed to
					the newly determined 1st position in the list
					</para>
					<para>
						<emphasis>NOTE</emphasis>:  for optimal results when
						using the "best-dest-first" algorithm, the destinations
						must be provisioned in descending order of their
						expected quality! (i.e. best quality gateways must be
						placed towards the start of the list)
					</para>
				</listitem>
			</itemizedlist>
		</para>
		<para>
			<emphasis>
			Default value is <emphasis role='bold'>"dynamic-weights"</emphasis>.
			</emphasis>
		</para>
		<example>
		<title>Setting the <varname>algorithm</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "algorithm", "best-dest-first")
	</programlisting>
		</example>
	</section>

	<section id="param_history_span" xreflabel="history_span">
		<title><varname>history_span</varname> (integer)</title>
		<para>
		The duration (in minutes) that a gateway's statistics for a given call
		will be kept for.
		</para>
		<para>
			<emphasis>
			Default value is <emphasis role='bold'>30</emphasis> minutes.
			</emphasis>
		</para>
		<example>
		<title>Setting the <varname>connection_timeout</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "history_span", 15)
	</programlisting>
		</example>
	</section>

	<section id="param_sampling_interval" xreflabel="sampling_interval">
		<title><varname>sampling_interval</varname> (integer)</title>
		<para>
		The duration (in seconds) of the statistics sampling window.  Every
		<emphasis><xref linkend="param_sampling_interval"/></emphasis> seconds,
		the accumulated statistics during the most recent sampling window get
		added to each gateway, while the oldest sampled interval statistics are
		subtracted (rotated away) from each gateway.
		</para>
		<para>
		A lower value will lead to a closer to realtime adjustment to traffic
		changes, but it will also increase CPU usage and internal contention
		due to locking.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>5</emphasis> seconds.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>connect_poll_interval</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "sampling_interval", 5)
	</programlisting>
		</example>
	</section>

	<section id="param_extra_stats" xreflabel="extra_stats">
		<title><varname>extra_stats</varname> (string)</title>
		<para>
		A semicolon-separated list of custom statistics to be additionally kept
		and monitored by the module.  In order to gather these statistics, the
		module expects the script writer to call
		<xref linkend="func_qr_set_xstat"/> whenever they want to increment a
		custom statistic for a (prefix, destination) tuple.
		</para>

		<para>
		Extra statistics come in two flavours: <emphasis>positive</emphasis>
		(a higher value is better, e.g. ASR) or <emphasis>negative</emphasis>
		(a lower value is better, e.g. PDD).  The flavour determines the
		comparison operator to be used against the statistics's thresholds, and
		can be specified by prepending <emphasis role='bold'>"+"</emphasis> or
		<emphasis role='bold'>"-"</emphasis>, respectively, in front
		of the statistic's name (see example below).
		</para>

		<para>
		The minimally accepted number of samples for each statistic may be
		changed using the optional <emphasis role='bold'>/&lt;min_samples&gt;</emphasis>
		suffix.  Default value: <emphasis role='bold'>30</emphasis> samples
		(minimum).
		</para>

		<para>
		The thresholds and penalties for a custom statistic must be provided
		via the <emphasis>qr_profiles</emphasis> table, by extending it with 4
		columns for each extra statistic, named according to these
		templates:
		<itemizedlist>
		<listitem><para>warn_threshold_<emphasis>&lt;STAT&gt;</emphasis></para></listitem>
		<listitem><para>crit_threshold_<emphasis>&lt;STAT&gt;</emphasis></para></listitem>
		<listitem><para>warn_penalty_<emphasis>&lt;STAT&gt;</emphasis></para></listitem>
		<listitem><para>crit_penalty_<emphasis>&lt;STAT&gt;</emphasis></para></listitem>
		</itemizedlist>
		</para>

		<para>
		<emphasis>
			Default value is <emphasis role='bold'>NULL</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>extra_stats</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "extra_stats", "+mos/60; +r_factor; -503_replies/100")
	</programlisting>
		</example>
	</section>

	<section id="param_min_samples_asr" xreflabel="min_samples_asr">
		<title><varname>min_samples_asr</varname> (integer)</title>
		<para>
		The minimally accepted amount of sampled ASR statistics for each
		(prefix, destination) pair before they can be taken into account.  As
		long as the number of samples stays below this limit, the ASR statistic
		of the pair is assumed to be healthy.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>30</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>min_samples_asr</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "min_samples_asr", 50)
	</programlisting>
		</example>
	</section>

	<section id="param_min_samples_ccr" xreflabel="min_samples_ccr">
		<title><varname>min_samples_ccr</varname> (integer)</title>
		<para>
		The minimally accepted amount of sampled CCR statistics for each
		(prefix, destination) pair before they can be taken into account.  As
		long as the number of samples stays below this limit, the CCR statistic
		of the pair is assumed to be healthy.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>30</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>min_samples_ccr</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "min_samples_ccr", 50)
	</programlisting>
		</example>
	</section>

	<section id="param_min_samples_pdd" xreflabel="min_samples_pdd">
		<title><varname>min_samples_pdd</varname> (integer)</title>
		<para>
		The minimally accepted amount of sampled PDD statistics for each
		(prefix, destination) pair before they can be taken into account.  As
		long as the number of samples stays below this limit, the PDD statistic
		of the pair is assumed to be healthy.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>10</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>min_samples_pdd</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "min_samples_pdd", 15)
	</programlisting>
		</example>
	</section>

	<section id="param_min_samples_ast" xreflabel="min_samples_ast">
		<title><varname>min_samples_ast</varname> (integer)</title>
		<para>
		The minimally accepted amount of sampled AST statistics for each
		(prefix, destination) pair before they can be taken into account.  As
		long as the number of samples stays below this limit, the AST statistic
		of the pair is assumed to be healthy.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>10</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>min_samples_ast</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "min_samples_ast", 15)
	</programlisting>
		</example>
	</section>

	<section id="param_min_samples_acd" xreflabel="min_samples_acd">
		<title><varname>min_samples_acd</varname> (integer)</title>
		<para>
		The minimally accepted amount of sampled ACD statistics for each
		(prefix, destination) pair before they can be taken into account.  As
		long as the number of samples stays below this limit, the ACD statistic
		of the pair is assumed to be healthy.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>20</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>min_samples_acd</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "min_samples_acd", 30)
	</programlisting>
		</example>
	</section>

	<section id="param_event_bad_dst_threshold" xreflabel="event_bad_dst_threshold">
		<title><varname>event_bad_dst_threshold</varname> (string)</title>
		<para>
		The minimally accepted quality of a (prefix, destination) combination,
		given as a quoted floating point number in the [0, 1] interval.
		Whenever a (prefix, destination) combination receives a score below
		this threshold, the <xref linkend="event_E_QROUTING_BAD_DST"/> event
		will be triggered.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>NULL</emphasis> (not set).
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>event_bad_dst_threshold</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "event_bad_dst_threshold", "0.5")
	</programlisting>
		</example>
	</section>

	<section id="param_decimal_digits" xreflabel="decimal_digits">
		<title><varname>decimal_digits</varname> (string)</title>
		<para>
		The amount of decimal digits to use in logging or MI output.
		</para>
		<para>
		<emphasis>
			Default value is <emphasis role='bold'>2</emphasis>.
		</emphasis>
		</para>
		<example>
		<title>Setting the <varname>decimal_digits</varname> parameter</title>
		<programlisting format="linespecific">

modparam("qrouting", "decimal_digits", 4)
	</programlisting>
		</example>
	</section>

</section>

<!-- ============================= FUNC ================================  -->

<section id="exported_functions" xreflabel="exported_functions">
	<title>Exported Functions</title>

	<section id="func_qr_set_xstat" xreflabel="qr_set_xstat()">
		<title>
			<function moreinfo="none">qr_set_xstat(rule_id, gw_name, stat_name,
										inc_by, [part], [inc_total])</function>
		</title>
		<para>
		Provide a new sample value for an extra statistic on a given (prefix,
		gateway) combination.  Extra statistics may be defined using the
		<xref linkend="param_extra_stats"/> module parameter.
		</para>
		<para>Parameters:</para>
		<itemizedlist>
			<listitem><para>
				<emphasis>rule_id (integer)</emphasis> - database id of the
				drouting rule holding the prefix and its destinations
			</para></listitem>
			<listitem><para>
				<emphasis>gw_name (string)</emphasis> - gateway to account the
				statistic for.  The gateway must be part of the above rule's
				destinations.
			</para></listitem>
			<listitem><para>
				<emphasis>stat_name (string)</emphasis> - statistic to account
			</para></listitem>
			<listitem><para>
				<emphasis>inc_by (string)</emphasis> - quoted floating point
				number, representing the amount to add to the stat
			</para></listitem>
			<listitem><para>
				<emphasis>part (string, optional, default: 'Default')</emphasis> -
				the drouting partition to use
			</para></listitem>
			<listitem><para>
				<emphasis>inc_total (string, optional, default: 1)</emphasis> -
				the amount to add to the total stat counter.  Usually, this
				value should be 1, but it may make sense to set it to 0 when a
				custom statistic needs to be set a 2nd, 3rd, etc. time across
				the duration of the same established call.
			</para></listitem>
		</itemizedlist>
		<para>
		This function can be used from any route.
		</para>
		<example>
		<title><function>qr_set_xstat()</function> usage</title>
		<programlisting format="linespecific">

# the MoS is set exactly once per call, so we can omit "inc_total"
$var(rule_id) = 1574;
$var(gw_name) = "GW-28";
$var(mos_score) = "4.28";
qr_set_xstat($var(rule_id), $var(gw_name), "mos", $var(mos_score));
	</programlisting>
		</example>
	</section>

	<section id="func_qr_disable_dst" xreflabel="qr_disable_dst()">
		<title>
		<function moreinfo="none">qr_disable_dst(rule_id, dst_name, [part])</function>
		</title>
		<para>
		Within a given routing rule, temporarily remove the given gateway or
		carrier from routing, until they are re-enabled via
		<xref linkend="func_qr_enable_dst"/> or <xref linkend="mi_qr_enable_dst"/>.
		The removal effect will be lost on an OpenSIPS restart.
		</para>
		<para>Parameters:</para>
		<itemizedlist>
			<listitem><para>
				<emphasis>rule_id (integer)</emphasis> - database id of the
				drouting rule
			</para></listitem>
			<listitem><para>
				<emphasis>dst_name (string)</emphasis> - gateway or carrier
					to disable
			</para></listitem>
			<listitem><para>
				<emphasis>part (string, optional)</emphasis> - drouting partition
			</para></listitem>
		</itemizedlist>
		<para>
		This function can be used from any route.
		</para>
		<example>
		<title><function>qr_disable_dst()</function> usage</title>
		<programlisting format="linespecific">

# the signaling quality for @rule_id through @dst_name is degrading, remove it!
event_route [E_QROUTING_BAD_DST]
{
	qr_disable_dst($param(rule_id), $param(dst_name), $param(partition));
}
	</programlisting>
		</example>
	</section>

	<section id="func_qr_enable_dst" xreflabel="qr_enable_dst()">
		<title>
		<function moreinfo="none">qr_enable_dst(rule_id, dst_name, [part])</function>
		</title>
		<para>
		Within a given routing rule, re-introduce the given gateway or
		carrier into the routing process.
		</para>
		<para>Parameters:</para>
		<itemizedlist>
			<listitem><para>
				<emphasis>rule_id (integer)</emphasis> - database id of the
				drouting rule
			</para></listitem>
			<listitem><para>
				<emphasis>dst_name (string)</emphasis> - gateway or carrier
					to disable
			</para></listitem>
			<listitem><para>
				<emphasis>part (string, optional)</emphasis> - drouting partition
			</para></listitem>
		</itemizedlist>
		<para>
		This function can be used from any route.
		</para>
		<example>
		<title><function>qr_enable_dst()</function> usage</title>
		<programlisting format="linespecific">

# the ban has expired, let's re-enable this gateway and see how it behaves
qr_enable_dst($param(rule_id), $param(dst_name), $param(partition));
	</programlisting>
		</example>
	</section>

</section>

<!-- ================================ MI =================================  -->

<section id="exported_mi_functions" xreflabel="Exported MI Functions">
	<title>Exported MI Functions</title>

	<section id="mi_qr_reload" xreflabel="qr_reload">
		<title><function moreinfo="none">qr_reload</function></title>

		<para>
		Reload all quality-based routing rules from the SQL database.
		</para>
		<para>
		MI FIFO Command Format:
		</para>

		<programlisting  format="linespecific">

opensips-cli -x mi qr_reload
		</programlisting>
	</section>

	<section id="mi_qr_status" xreflabel="qr_status">
		<title><function moreinfo="none">qr_status</function></title>

		<para>
		Inspect the signaling quality statistics of the current
		<xref linkend="param_history_span"/> for all drouting gateways in all
		partitions, with various levels of filtering.
		</para>
		<para>Parameters:</para>
		<itemizedlist>
			<listitem><para>
				<emphasis>partition (optional)</emphasis> - a specific
				drouting partition to list statistics for
			</para></listitem>
			<listitem><para>
				<emphasis>rule_id (optional)</emphasis> - a specific drouting
				rule database id to list statistics for
			</para></listitem>
			<listitem><para>
				<emphasis>dst_name (optional)</emphasis> - a specific gateway or
				carrier name to list statistics for
			</para></listitem>
		</itemizedlist>
		<para>
		MI FIFO Command Format:
		</para>

		<programlisting  format="linespecific">

opensips-cli -x mi qr_status
opensips-cli -x mi qr_status pstn
opensips-cli -x mi qr_status pstn 11 MY-GW-3
opensips-cli -x mi qr_status pstn 17 MY-CARR-7
		</programlisting>
	</section>

	<section id="mi_qr_disable_dst" xreflabel="qr_disable_dst">
		<title><function moreinfo="none">qr_disable_dst</function></title>

		<para>
		Within a given routing rule, temporarily remove the given gateway or
		carrier from routing, until they are re-enabled manually.  The removal
		effect will be lost on an OpenSIPS restart.
		</para>
		<para>Parameters:</para>
		<itemizedlist>
			<listitem><para>
				<emphasis>partition (optional)</emphasis> - drouting partition
			</para></listitem>
			<listitem><para>
				<emphasis>rule_id</emphasis> - database id of the drouting rule
			</para></listitem>
			<listitem><para>
				<emphasis>dst_name</emphasis> - gateway or carrier to disable
			</para></listitem>
		</itemizedlist>
		<para>
		MI FIFO Command Format:
		</para>

		<programlisting  format="linespecific">

opensips-cli -x mi qr_disable_dst 14 MY-CARR-7
opensips-cli -x mi qr_disable_dst pstn 81 MY-GW-3
		</programlisting>
	</section>

	<section id="mi_qr_enable_dst" xreflabel="qr_enable_dst">
		<title><function moreinfo="none">qr_enable_dst</function></title>

		<para>
		Within a given routing rule, re-introduce the given gateway or
		carrier into the routing process.
		</para>
		<para>Parameters:</para>
		<itemizedlist>
			<listitem><para>
				<emphasis>partition (optional)</emphasis> - drouting partition
			</para></listitem>
			<listitem><para>
				<emphasis>rule_id</emphasis> - database id of the drouting rule
			</para></listitem>
			<listitem><para>
				<emphasis>dst_name</emphasis> - gateway or carrier to enable
			</para></listitem>
		</itemizedlist>
		<para>
		MI FIFO Command Format:
		</para>

		<programlisting  format="linespecific">

opensips-cli -x mi qr_enable_dst 14 MY-CARR-7
opensips-cli -x mi qr_enable_dst pstn 81 MY-GW-3
		</programlisting>
	</section>

</section>

<!-- ============================= EVENT ================================  -->

<section id="exported_events" xreflabel="Exported Events">
	<title>Exported Events</title>
	<section id="event_E_QROUTING_BAD_DST" xreflabel="E_QROUTING_BAD_DST">
		<title>
		<function moreinfo="none">E_QROUTING_BAD_DST</function>
		</title>
		<para>
		This event may be raised during routing, asynchronously, whenever the
		score of a (prefix, destination) pair falls below
		<xref linkend="param_event_bad_dst_threshold"/>.
		</para>
		<para>Parameters:</para>
		<itemizedlist>
			<listitem><para>
					<emphasis>partition</emphasis> - drouting partition name
			</para></listitem>
			<listitem><para>
					<emphasis>rule_id</emphasis> - database id of the drouting rule
			</para></listitem>
			<listitem><para>
					<emphasis>dst_name</emphasis> - name of the concerned gateway or carrier
			</para></listitem>
		</itemizedlist>
	</section>

</section>

</chapter>
