Table of Contents
timer_interval
(integer)limit_per_interval
(integer)expire_time
(integer)hash_size
(integer)default_algorithm
(string)cachedb_url
(string)db_prefix
(string)repl_buffer_threshold
(string)repl_timer_interval
(string)repl_timer_expire
(string)pipe_replication_cluster
(integer)window_size
(int)slot_period
(int)List of Tables
List of Examples
timer_interval
parameterlimit_per_interval
parameterexpire_time
parameterhash_size
parameterdefault_algorithm
parametercachedb_url
parameterdb_prefix
parameterrepl_buffer_threshold
parameterrepl_timer_interval
parameterrepl_timer_expire
parameterpipe_replication_cluster
parameterwindow_size
parameterslot_period
parameterrl_check
usagerl_dec_count
usagerl_reset_count
usageThis 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 latest sources allow you to dynamically group several messages into some entities and limit the traffic based on them. The MI interface can be used to change tunables while running OpenSIPS.
This module is integrated with the OpenSIPS Key-Value Interface, providing support for distributed rate limiting using Redis or Memcached CacheDB backends. The internal limiting data will no longer be kept on each OpenSIPS instance. It will be stored in the distributed Key-Value database and queried by each instance before deciding if a SIP message should be blocked or not.
To achieve a distributed ratelimit feature, the module can also replicate its pipes counters to different OpenSIPS instances using the clusterer module. To do that, define the pipe_replication_cluster parameter in your configuration script.
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 OpenSIPS cluster when run on the dispatching box in front.
Distributed limiting is useful when the rate limit should be performed not only on a specific node, but on the entire platform.
NOTE: that this behavior only makes sense when the pipe algorithm used is TAILDROP or RED.
A sample configuration snippet might look like this:
... if (!rl_check($rU, 50, "TAILDROP")) { sl_send_reply(503, "Server Unavailable"); exit; }; ...
Upon every incoming request listed above rl_check is invoked and the entity identified by the R-URI user is checked. 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.
The ratelimit module supports two different static algorithms to be used by rl_check to determine whether a message should be blocked or not.
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.
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 retransmissed after given time, the same on all devices with the same firmware/by the same vendor.
Random Early Detection 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 OpenSIPS will return errors to the OpenSIPS 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 OpenSIPS might drop messages although the limit might not be reached within the interval. Decrease the timer interval if you encounter this.
SBT holds a window consisting of one or more slots. You can set the window_size parameter(seconds) which means for how long we should look back to count the calls and slot_period parameter(miliseconds) which tells how granular the algorithm should be. The number of slots will be window_size/slot_period. If, for example, you have window_size= slot_period=1 second, then after each second you shall lose the call count, but if you set the slot_period to 100 milliseconds, then when your call will be outside the window, the calls in the first 100 milliseconds shall be dropped, and the rest in the next 900 shall be kept.
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.
When running OpenSIPS on different machines, one has to adjust the drop rates for the static algorithms to maintain a sub 100% load average or packets 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.
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).
Using the PID Controller model (see Wikipedia page), 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).
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.
Generally though, as real life request rates drift by less, adapting should happen much faster.
IMPORTANT NOTE: as this algorithm is diven by the load factor, the values for the limits must be between 0 and 100 (as percentages) and the limits for all the checks and pipes must be the same (only one value). Again, this limitation are specific to this algorithm and not to the implementation.
The following modules must be loaded before this module:
No dependencies on other OpenSIPS modules.
The timer interval in seconds when the Network and Feedback algorithms run their queries, and the other algorithms reset their counters.
IMPORTANT: A too small value may lead to performance penalties due to timer process overloading.
Default value is 10.
This parameter configures the way that a pipe's limit is specified in the rl_check function and only affects the Taildrop and RED algorithms. A value of 1 means that the limit is set per-timer_interval while a value of 0 means per-second.
Default value is 0(limit per-second).
Example 1.2. Set limit_per_interval
parameter
... modparam("ratelimit", "limit_per_interval", 1) ...
This parameter specifies how long a pipe should be kept in memory after it becomes idle (no more operations are performed on the pipe) until deleted.
Default value is 3600.
The size of the hash table internally used to keep the pipes. A larger table is much faster but consumes more memory. The hash size must be a power of 2 number.
Default value is 1024.
Specifies which algorithm should be assumed in case it isn't explicitly specified in the rl_check function.
Default value is "TAILDROP".
Example 1.5. Set default_algorithm
parameter
... modparam("ratelimit", "default_algorithm", "RED") ...
Enables distributed rate limiting and specifies the backend that should be used by the CacheDB interface.
Default value is "disabled".
Example 1.6. Set cachedb_url
parameter
... modparam("ratelimit", "cachedb_url", "redis://root:root@127.0.0.1/") ...
Specifies what prefix should be added to the pipe name. This is only used when distributed rate limiting is enabled.
Default value is "rl_pipe_".
Used to specify the length of the buffer used by the binary replication, in bytes, when a flush should be performed - the pipes gathered until then should be sent on the network. This is used to avoid using large amount of memory for pipes replication.
Default value is 32767 bytes.
Example 1.8. Set repl_buffer_threshold
parameter
... modparam("ratelimit", "repl_buffer_threshold", 500) ...
Timer in milliseconds, used to specify how often the module should replicate its counters to the other instances.
Default value is 10 ms.
Example 1.9. Set repl_timer_interval
parameter
... modparam("ratelimit", "repl_timer_interval", 100) ...
Timer in seconds, used to specify when the counter received from a different instance should no longer be taken into account. This is used to prevent obsolete values, in case an instance stops replicating its counters.
Default value is 10 s.
Example 1.10. Set repl_timer_expire
parameter
... modparam("ratelimit", "repl_timer_expire", 10) ...
Specifies the cluster ID where pipes will be replicated to and received from.
Default value is 0. (no replication)
Example 1.11. Set pipe_replication_cluster
parameter
... modparam("ratelimit", "pipe_replication_cluster", 1) ...
How long the history in SBT should be in seconds.
Default value is “10”.
Value of one slot in milliseconds. This parameter determines how granular the algorithm should be. The number of slots will be determined by window_size/slot_period.
Default value is “200”.
Example 1.13. Set slot_period
parameter
... modparam("ratelimit", "window_size", 5) #we will have 50 slots of 100 milliseconds modparam("ratelimit", "slot_period", 100) ...
Check the current request against the pipe identified by name and changes/updates the limit. If no pipe is found, then a new one is created with the specified limit and algorithm, if specified. If the algorithm parameter doesn't exist, the default one is used.
NOTE: A pipe's algorithm cannot be dynamically changed. Only the one specified when the pipe was created will be considered.
NOTE: This function increments the pipe's counter every time it is called, even if the call should be declined. Therefore If you are using ratelimit to limit only successful traffic, you need to explicitely decrease the counter for the declined calls using the rl_dec_count() function.
The method will return an error code if the limit for the matched pipe is reached.
Meaning of the parameters is as follows:
name (string) - this is the name that identifies the pipe which should be checked.
limit (int) - this specifies the threshold limit of the pipe. It is strongly related to the algorithm used. Note that the limit should be specified as per-second, not per-timer_interval.
algorithm (string, optional) - this parameter reffers to the algorithm used to check the pipe. If it is not set, the default value is used.
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE, ERROR_ROUTE, LOCAL_ROUTE, TIMER_ROUTE and EVENT_ROUTE.
Example 1.14. rl_check
usage
... # perform a pipe match for all INVITE methods using RED algorithm if (is_method("INVITE")) { if (!rl_check("pipe_INVITE", 100, "RED")) { sl_send_reply(503, "Server Unavailable"); exit; }; }; ... # use default algorithm for each different gateway $var(limit) = 10; if (!rl_check("gw_$ru", $var(limit))) { sl_send_reply(503, "Server Unavailable"); exit; }; ... # count only successful calls if (!rl_check("gw_$ru", 100)) { rl_dec_count("gw_$ru"); sl_send_reply(503, "Server Unavailable"); exit; }; ...
This function decreases a counter that could have been previously increased by rl_check function.
Meaning of the parameters is as follows:
name (string) - identifies the name of the pipe.
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE, ERROR_ROUTE, LOCAL_ROUTE, TIMER_ROUTE and EVENT_ROUTE.
Example 1.15. rl_dec_count
usage
... if (!rl_check("gw_$ru", 100, "TAILDROP")) { exit; } else { rl_dec_count("gw_$ru"); }; ...
This function resets a counter that could have been previously increased by rl_check function.
Meaning of the parameters is as follows:
name - identifies the name of the pipe.
This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE, ERROR_ROUTE, LOCAL_ROUTE, TIMER_ROUTE and EVENT_ROUTE.
Example 1.16. rl_reset_count
usage
... if (!rl_check("gw_$ru", 100, "TAILDROP")) { exit; } else { rl_reset_count("gw_$ru"); }; ...
Lists the parameters and variabiles in the ratelimit module.
Name: rl_list
Parameters:
pipe (optional) - indicates the name of the pipe. If the parameter doesn't exist, all the active pipes are listed. Otherwise only the one specified.
MI FIFO Command Format:
opensips-cli -x mi rl_list gw_10.0.0.1
Resets the counter of a specified pipe.
Name: rl_reset_pipe
Parameters:
pipe - indicates the name of the pipe whose counter should be reset.
MI FIFO Command Format:
opensips-cli -x mi rl_reset_pipe gw_10.0.0.1
Sets the PID Controller parameters for the Feedback Algorithm.
Name: rl_set_pid
Parameters:
ki - the integral parameter.
kp - the proportional parameter.
kd - the derivative parameter.
MI FIFO Command Format:
opensips-cli -x mi rl_set_pid 0.5 0.5 0.5
Gets the list of in use PID Controller parameters.
Name: rl_get_pid
Parameters: none
MI FIFO Command Format:
opensips-cli -x mi rl_get_pid
Table 2.1. Top contributors by DevScore(1), authored commits(2) and lines added/removed(3)
Name | DevScore | Commits | Lines ++ | Lines -- | |
---|---|---|---|---|---|
1. | Razvan Crainea (@razvancrainea) | 126 | 57 | 3041 | 2678 |
2. | Ovidiu Sas (@ovidiusas) | 39 | 17 | 2481 | 44 |
3. | Bogdan-Andrei Iancu (@bogdan-iancu) | 31 | 27 | 118 | 125 |
4. | Vlad Patrascu (@rvlad-patrascu) | 30 | 17 | 359 | 558 |
5. | Liviu Chircu (@liviuchircu) | 18 | 15 | 53 | 117 |
6. | Eseanu Marius Cristian (@eseanucristian) | 13 | 6 | 329 | 195 |
7. | Daniel-Constantin Mierla (@miconda) | 9 | 7 | 24 | 18 |
8. | Ionel Cerghit (@ionel-cerghit) | 4 | 2 | 34 | 24 |
9. | Henning Westerholt (@henningw) | 4 | 2 | 4 | 2 |
10. | Walter Doekes (@wdoekes) | 4 | 2 | 2 | 2 |
All remaining contributors: Peter Lemenkov (@lemenkov), Ionut Ionita (@ionutrazvanionita), Arnaud Boussus, Sergio Gutierrez, Stanislaw Pitucha, Bill Hau, Konstantin Bokarius, Vlad Paiu (@vladpaiu), Julián Moreno Patiño, Edson Gellert Schubert.
(1) DevScore = author_commits + author_lines_added / (project_lines_added / project_commits) + author_lines_deleted / (project_lines_deleted / project_commits)
(2) including any documentation-related commits, excluding merge commits. Regarding imported patches/code, we do our best to count the work on behalf of the proper owner, as per the "fix_authors" and "mod_renames" arrays in opensips/doc/build-contrib.sh. If you identify any patches/commits which do not get properly attributed to you, please submit a pull request which extends "fix_authors" and/or "mod_renames".
(3) ignoring whitespace edits, renamed files and auto-generated files
Table 2.2. Most recently active contributors(1) to this module
Name | Commit Activity | |
---|---|---|
1. | Bogdan-Andrei Iancu (@bogdan-iancu) | Feb 2008 - Jul 2023 |
2. | Razvan Crainea (@razvancrainea) | Sep 2011 - Oct 2021 |
3. | Peter Lemenkov (@lemenkov) | Jun 2018 - Feb 2020 |
4. | Liviu Chircu (@liviuchircu) | Mar 2014 - Jan 2020 |
5. | Vlad Patrascu (@rvlad-patrascu) | Jul 2016 - Apr 2019 |
6. | Ionel Cerghit (@ionel-cerghit) | Jul 2015 - Dec 2016 |
7. | Julián Moreno Patiño | Feb 2016 - Feb 2016 |
8. | Ionut Ionita (@ionutrazvanionita) | Dec 2015 - Dec 2015 |
9. | Eseanu Marius Cristian (@eseanucristian) | Aug 2015 - Sep 2015 |
10. | Bill Hau | Jul 2014 - Jul 2014 |
All remaining contributors: Walter Doekes (@wdoekes), Vlad Paiu (@vladpaiu), Ovidiu Sas (@ovidiusas), Stanislaw Pitucha, Arnaud Boussus, Sergio Gutierrez, Henning Westerholt (@henningw), Daniel-Constantin Mierla (@miconda), Konstantin Bokarius, Edson Gellert Schubert.
(1) including any documentation-related commits, excluding merge commits
Last edited by: Razvan Crainea (@razvancrainea), Bogdan-Andrei Iancu (@bogdan-iancu), Liviu Chircu (@liviuchircu), Vlad Patrascu (@rvlad-patrascu), Peter Lemenkov (@lemenkov), Ionut Ionita (@ionutrazvanionita), Eseanu Marius Cristian (@eseanucristian), Walter Doekes (@wdoekes), Arnaud Boussus, Daniel-Constantin Mierla (@miconda), Konstantin Bokarius, Henning Westerholt (@henningw), Ovidiu Sas (@ovidiusas), Edson Gellert Schubert.
Documentation Copyrights:
Copyright © 2011 OpenSIPS Foundation
Copyright © 2008 VoIP Embedded Inc.
Copyright © 2006 Freenet Cityline GmbH