mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
613 lines
18 KiB
613 lines
18 KiB
<?xml version="1.0" encoding='ISO-8859-1'?>
|
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
|
|
|
|
<!-- Include general documentation entities -->
|
|
<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
|
|
%docentities;
|
|
|
|
]>
|
|
<!-- Module User's Guide -->
|
|
|
|
<chapter>
|
|
|
|
<title>&adminguide;</title>
|
|
|
|
<section>
|
|
<title>Overview</title>
|
|
<para>
|
|
This module implements rate limiting for SIP requests. In contrast to
|
|
the PIKE module this limits the flow based on a per SIP request type
|
|
basis and not per source IP. The MI interface can be used to
|
|
change tunables while running &kamailio;.
|
|
</para>
|
|
<para>
|
|
The module implements the pipe/queue policy from BSD's ipfw manual,
|
|
with some simplifications. In principle, each specified method is
|
|
associated with its own queue and a number of queues are connected
|
|
to a certain pipe (see the queue and pipe params).
|
|
</para>
|
|
<para>
|
|
Please also take a look at the <quote>pipelimit</quote> module,
|
|
that implements the pipe policy with database support. Note that it
|
|
doesn't implement the queues that exist in this module.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Use Cases</title>
|
|
<para>
|
|
Limiting the rate messages are processed on a system directly
|
|
influences the load. The ratelimit module can be used to protect a
|
|
single host or to protect an &kamailio; cluster when run on the dispatching
|
|
box in front.
|
|
</para>
|
|
<para>
|
|
A sample configuration snippet might look like this:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
...
|
|
if (is_method("INVITE|REGISTER|SUBSCRIBE") {
|
|
if (!rl_check()) {
|
|
append_to_reply("Retry-After: 5\r\n");
|
|
sl_send_reply("503","Limiting");
|
|
exit;
|
|
};
|
|
};
|
|
...
|
|
</programlisting>
|
|
<para>
|
|
Upon every incoming request listed above <function>rl_check</function>
|
|
is invoked. It returns an OK code if the current per request load is below the
|
|
configured threshold. If the load is exceeded the function returns an
|
|
error and an administrator can discard requests with a stateless
|
|
response.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Static Rate Limiting Algorithms</title>
|
|
<para>
|
|
The ratelimit module supports two different statc algorithms
|
|
to be used by rl_check to determine whether a message should be
|
|
blocked or not.
|
|
</para>
|
|
<section>
|
|
<title>Tail Drop Algorithm (TAILDROP)</title>
|
|
<para>
|
|
This is a trivial algorithm that imposes some risks when used in
|
|
conjunction with long timer intervals. At the start of each interval
|
|
an internal counter is reset and incremented for each incoming
|
|
message. Once the counter hits the configured limit rl_check returns
|
|
an error.
|
|
</para>
|
|
<para>
|
|
The downside of this algorithm is that it can lead to SIP client
|
|
synchronization. During a relatively long interval only the first
|
|
requests (i.e. REGISTERs) would make it through. Following messages
|
|
(i.e. RE-REGISTERs) will all hit the SIP proxy at the same time when a
|
|
common Expire timer expired. Other requests will be retransmitted
|
|
after a given time, the same on all devices with the same firmware/by
|
|
the same vendor.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Random Early Detection Algorithm (RED)</title>
|
|
<para>
|
|
The Random Early Detection Algorithm tries to circumvent the synchronization
|
|
problem imposed by the tail drop algorithm by measuring the average load and
|
|
adapting the drop rate dynamically. When running with the RED algorithm
|
|
(enabled by default) &kamailio; will return errors to the &kamailio;
|
|
routing engine every n'th packet trying to evenly spread the measured
|
|
load of the last timer interval onto the current interval. As a
|
|
negative side effect &kamailio; might drop messages although the limit might
|
|
not be reached within the interval. Decrease the timer interval if you
|
|
encounter this.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Network Algorithm (NETWORK)</title>
|
|
<para>
|
|
This algorithm relies on information provided by network interfaces.
|
|
The total amount of bytes waiting to be consumed on all the network
|
|
interfaces is retrieved once every timer_interval seconds.
|
|
If the returned amount exceeds the limit specified in the modparam,
|
|
rl_check returns an error.
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Dynamic Rate Limiting Algorithms</title>
|
|
<para>
|
|
When running &kamailio; on different machines, one has to adjust the drop
|
|
rates for the static algorithms to maintain a sub 100% load average or
|
|
packets will start getting dropped in the network stack. While this is not
|
|
in itself difficult, it isn't neither accurate nor trivial: another
|
|
server taking a notable fraction of the CPU time will require re-tuning
|
|
the parameters.
|
|
</para>
|
|
<para>
|
|
While tuning the drop rates from the outside based on a certain factor
|
|
is possible, having the algorithm run inside ratelimit permits tuning
|
|
the rates based on internal server parameters and is somewhat more
|
|
flexible (or it will be when support for external load factors - as
|
|
opposed to cpu load - is added).
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>Feedback Algorithm (FEEDBACK)</title>
|
|
<para>
|
|
Using the PID Controller model
|
|
(see <ulink url='http://en.wikipedia.org/wiki/PID_controller'>Wikipedia page</ulink>),
|
|
the drop rate is adjusted dynamically based on the load factor so that
|
|
the load factor always drifts towards the specified limit (or setpoint,
|
|
in PID terms).
|
|
</para>
|
|
<para>
|
|
As reading the CPU load average is relatively expensive (opening /proc/stat,
|
|
parsing it, etc), this only happens once every timer_interval seconds and
|
|
consequently the FEEDBACK value is only at these intervals recomputed. This
|
|
in turn makes it difficult for the drop rate to adjust quickly. Worst case
|
|
scenarios are request rates going up/down instantly by thousands - it takes
|
|
up to 20 seconds for the controller to adapt to the new request rate.
|
|
</para>
|
|
<para>
|
|
Generally though, as real life request rates drift by less, adapting should
|
|
happen much faster.
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Dependencies</title>
|
|
<section>
|
|
<title>&kamailio; Modules</title>
|
|
<para>
|
|
The following modules must be loaded before this module:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>No dependencies on other &kamailio; modules</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</section>
|
|
<section>
|
|
<title>External Libraries or Applications</title>
|
|
<para>
|
|
The following libraries or applications must be installed before
|
|
running &kamailio; with this module loaded:
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<emphasis>None</emphasis>.
|
|
</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Parameters</title>
|
|
<section>
|
|
<title><varname>timer_interval</varname> (integer)</title>
|
|
<para>
|
|
The initial length of a timer interval in seconds. All amounts of
|
|
messages have to be divided by this timer to get a messages per second
|
|
value.
|
|
</para>
|
|
<para>
|
|
IMPORTANT: A too small value may lead to performance penalties due to
|
|
timer process overloading.
|
|
</para>
|
|
<para>
|
|
<emphasis>
|
|
Default value is 10.
|
|
</emphasis>
|
|
</para>
|
|
<example>
|
|
<title>Set <varname>timer_interval</varname> parameter</title>
|
|
<programlisting format="linespecific">
|
|
...
|
|
modparam("ratelimit", "timer_interval", 5)
|
|
...
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section>
|
|
<title><varname>queue</varname> (integer:string)</title>
|
|
<para>
|
|
The format of the queue parameter is "pipe_no:method". For each defined
|
|
method, the algorithm defined by pipe number "pipe_no" will be used.
|
|
</para>
|
|
<para>
|
|
To specify a queue that accepts all methods, use <quote>*</quote> instead of METHOD.
|
|
As queues are matched against request methods, you will usually want to have
|
|
this as the last queue added or other queues with specific methods will never
|
|
match. At this time, glob or regexp patterns are not supported.
|
|
</para>
|
|
<para>
|
|
</para>
|
|
<example>
|
|
<title>Set <varname>queue</varname> parameter</title>
|
|
<programlisting format="linespecific">
|
|
...
|
|
# assign pipe no 0 to method REGISTER
|
|
# assign pipe no 3 to method INVITE
|
|
# assign pipe no 2 to all other methods
|
|
modparam("ratelimit", "queue", "0:REGISTER")
|
|
modparam("ratelimit", "queue", "3:INVITE")
|
|
modparam("ratelimit", "queue", "2:*")
|
|
...
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section>
|
|
<title><varname>pipe</varname> (integer:string:integer)</title>
|
|
<para>
|
|
The format of the pipe param is "pipe_no:algorithm:limit". For each defined
|
|
pipe, the given algorithm with the given limit will be used.
|
|
</para>
|
|
<para>
|
|
A pipe is characterised by its algorithm and limit (bandwidth, in ipfw terms).
|
|
When specifying a limit, the unit depends on the algorithm used and doesn't
|
|
need to be spedified also (eg, for TAILDROP or RED, limit means packets/sec,
|
|
whereas with the FEEDBACK algorithm, it means [CPU] load factor).
|
|
</para>
|
|
<example>
|
|
<title>Set <varname>pipe</varname> parameter</title>
|
|
<programlisting format="linespecific">
|
|
...
|
|
# define pipe 0 with a limit of 200 pkts/sec using TAILDROP algorithm
|
|
# define pipe 1 with a limit of 100 pkts/sec using RED algorithm
|
|
# define pipe 2 with a limit of 50 pkts/sec using TAILDROP algorithm
|
|
# define pipe 3 with a limit of load factor 80 using FEEDBACK algorithm
|
|
# define pipe 4 with a limit of 10000 pending bytes in the rx_queue
|
|
# using NETWORK algorithm
|
|
modparam("ratelimit", "pipe", "0:TAILDROP:200")
|
|
modparam("ratelimit", "pipe", "1:RED:100")
|
|
modparam("ratelimit", "pipe", "2:TAILDROP:50")
|
|
modparam("ratelimit", "pipe", "3:FEEDBACK:80")
|
|
modparam("ratelimit", "pipe", "4:NETWORK:10000")
|
|
...
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
</section>
|
|
<section>
|
|
<title>Functions</title>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl_check([pvar])</function>
|
|
</title>
|
|
<para>
|
|
Check the current request against the matched ratelimit algorithm. If no
|
|
parameter is provided, the queue will be matched based on method type, and
|
|
then the pipe will be identified based on the matched queue. If a pipe number
|
|
is provided as a parameter, then the given pipe number will be used for
|
|
identifying the ratelimit algorithm.
|
|
The pipe number must be provided via a pseudovariable. It is recommended to
|
|
provide the pipe number via an integer pseudovariable.
|
|
</para>
|
|
<para>The method will return an error code if the limit for the matched
|
|
algorithm is reached.
|
|
</para>
|
|
<para>Meaning of the parameters is as follows:</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>pvar</emphasis> - the pseudovariable holding the pipe id to
|
|
be used by ratelimit.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
This function can be used from REQUEST_ROUTE.
|
|
</para>
|
|
<example>
|
|
<title><function>rl_check</function> usage</title>
|
|
<programlisting format="linespecific">
|
|
...
|
|
# perform queue/pipe match for current method
|
|
if (!rl_check()) {
|
|
append_to_reply("Retry-After: 5\r\n");
|
|
sl_send_reply("503","Limiting");
|
|
exit;
|
|
};
|
|
...
|
|
# use pipe no 1 for the current method
|
|
# set int pvar to 1
|
|
$var(p) = 1;
|
|
if (!rl_check("$var(p)")) {
|
|
append_to_reply("Retry-After: 5\r\n");
|
|
sl_send_reply("503","Limiting");
|
|
exit;
|
|
};
|
|
...
|
|
# use pipe no 1 for the current method
|
|
# set str pvar to 1
|
|
$var(p) = "1";
|
|
if (!rl_check("$var(p)") {
|
|
append_to_reply("Retry-After: 5\r\n");
|
|
sl_send_reply("503","Limiting");
|
|
exit;
|
|
};
|
|
...
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl_check_pipe([pipe_no])</function>
|
|
</title>
|
|
<para>
|
|
Check the current request against the matched ratelimit algorithm. If no
|
|
parameter is provided, the queue will be matched based on method type, and
|
|
then the pipe will be identified based on the matched queue. If a pipe number
|
|
is provided as a parameter, then the given pipe number will be used for
|
|
identifying the ratelimit algorithm.
|
|
</para>
|
|
<para>The method will return an error code if the limit for the matched
|
|
algorithm is reached.
|
|
</para>
|
|
<para>Meaning of the parameters is as follows:</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>pipe_no</emphasis> - the pipe id to be used by ratelimit.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
This function can be used from REQUEST_ROUTE.
|
|
</para>
|
|
<example>
|
|
<title><function>rl_check_pipe</function> usage</title>
|
|
<programlisting format="linespecific">
|
|
...
|
|
# perform queue/pipe match for current method
|
|
if (!rl_check_pipe()) {
|
|
append_to_reply("Retry-After: 5\r\n");
|
|
sl_send_reply("503","Limiting");
|
|
exit;
|
|
};
|
|
...
|
|
# use pipe no 1 for the current method
|
|
if (!rl_check_pipe("1") {
|
|
append_to_reply("Retry-After: 5\r\n");
|
|
sl_send_reply("503","Limiting");
|
|
exit;
|
|
};
|
|
...
|
|
</programlisting>
|
|
</example>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Exported RPC Functions</title>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.stats</function>
|
|
</title>
|
|
<para>
|
|
Lists the parameters and variables in the ratelimit module.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.stats</emphasis>
|
|
</para>
|
|
<para>Parameters: <emphasis>none</emphasis></para>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.stats
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.set_pipe</function>
|
|
</title>
|
|
<para>
|
|
Sets the pipe parameters for the given pipe id.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.set_pipe</emphasis>
|
|
</para>
|
|
<para>Parameters:</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>pipe_id</emphasis> - pipe id.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>pipe_algorithm</emphasis> - the
|
|
algorithm assigned to the given pipe id.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>pipe_limit</emphasis> - the limit
|
|
assigned to the given pipe id.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.set_pipe 2 RED 10
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.get_pipes</function>
|
|
</title>
|
|
<para>
|
|
Gets the list of in use pipes.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.get_pipes</emphasis>
|
|
</para>
|
|
<para>Parameters:<emphasis>none</emphasis></para>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.get_pipes
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.set_queue</function>
|
|
</title>
|
|
<para>
|
|
Sets the queue parameters for the given queue id.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.set_queue</emphasis>
|
|
</para>
|
|
<para>Parameters:</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>queue_id</emphasis> - queue id.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>queue_method</emphasis> - the method
|
|
assigned to the given queue id.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>pipe_id</emphasis> - the pipe id
|
|
assigned to the given queue id.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.set_queue 3 INVITE 2
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.get_queues</function>
|
|
</title>
|
|
<para>
|
|
Gets the list of in use queues.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.get_queues</emphasis>
|
|
</para>
|
|
<para>Parameters: <emphasis>none</emphasis></para>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.get_queues
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.set_pid</function>
|
|
</title>
|
|
<para>
|
|
Sets the PID Controller parameters for the Feedback Algorithm.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.set_pid</emphasis>
|
|
</para>
|
|
<para>Parameters:</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>ki</emphasis> - the integral parameter.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>kp</emphasis> - the proportional parameter.
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>kd</emphasis> - the derivative parameter.
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.set_pid 0.5 0.5 0.5
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.get_pid</function>
|
|
</title>
|
|
<para>
|
|
Gets the list of in use PID Controller parameters.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.get_pid</emphasis>
|
|
</para>
|
|
<para>Parameters: <emphasis>none</emphasis></para>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.get_pid
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.push_load</function>
|
|
</title>
|
|
<para>
|
|
Force the value of the load parameter. This method is useful
|
|
for testing the Feedback algorithm.
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.push_load</emphasis>
|
|
</para>
|
|
<para>Parameters:</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>load</emphasis> - the forced value of load
|
|
(it must be greater then 0.0 and smaller then 1.0).
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.push_load 0.85
|
|
</programlisting>
|
|
</section>
|
|
<section>
|
|
<title>
|
|
<function moreinfo="none">rl.set_dbg</function>
|
|
</title>
|
|
<para>
|
|
This function will enable/disable a WARNING debug log exposing the
|
|
internal counters for each pipe (useful in monitoring the ratelimit internals).
|
|
</para>
|
|
<para>
|
|
Name: <emphasis>rl.set_dbg</emphasis>
|
|
</para>
|
|
<para>Parameters:</para>
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>dbg</emphasis> - the debug value (0 means disable and
|
|
1 means enable).
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
<para>
|
|
RPC Command Format:
|
|
</para>
|
|
<programlisting format="linespecific">
|
|
&sercmd; rl.set_dbg 1
|
|
</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section>
|
|
<title>Known limitations</title>
|
|
<para>
|
|
The pipes and queues are stored as static vectors, so no more than
|
|
MAX_PIPES/MAX_QUEUES can be added without recompilation.
|
|
<itemizedlist>
|
|
<listitem><para>
|
|
<emphasis>MAX_PIPES</emphasis> - 16
|
|
</para></listitem>
|
|
<listitem><para>
|
|
<emphasis>MAX_QUEUES</emphasis> - 10
|
|
</para></listitem>
|
|
</itemizedlist>
|
|
</para>
|
|
</section>
|
|
</chapter>
|