Forum Discussion
11 Replies
- Kevin_Davies_40Nacreous
Try this and let me know how it performs for you...
when CLIENT_ACCEPTED { this will give you 20 connections per second per source IP address set cid [clock clicks] set conns 20 set rate 1 table set -subtable [virtual]:[IP::client_addr] $cid 0 indef $rate if {[table keys -subtable [virtual]:[IP::client_addr] -count] > $conns} { table delete -subtable [virtual]:[IP::client_addr] $cid TCP::close } }
In a BIGIP there will be many other instances of this iRule (one per TCP connection) running at the same time. When we get to the IF condition they could all say they are under the connection limit because they perform the test at the same moment in time.
To allow for this, we allocate the connection entry (table set), then backout (table delete) if we are over the limit (table keys -count). Since the table is always the source of truth, we never exceed the rate limit.
- Kevin_Davies_40NacreousOne second is the lowest resolution of table expiry timer. You may want to up this a little so if its 20 connections per second, you may get better results with 200 per 10 seconds.
- Kevin_Davies_40NacreousIf any of the above posts have provided a solution to your issue, please indicate so by clicking the tick to the left of them. This gives feedback and recognition to the volunteers who responded to your issue
- Bruce_BronczykAltostratusThanks for the suggestion. I am not very experienced with editing iRules, so does your suggested change insert into the iRule at a specific spot or does it replace some of the existing iRule below the 'when CLIENT_ACCEPTED' point? Thanks.
- Kevin_Davies_40Nacreous
Some results from apachebench testing...
20 requests in .23 seconds, all succeeded.
Concurrency Level: 1 Time taken for tests: 0.238 seconds Complete requests: 20 Failed requests: 0 Write errors: 0 Total transferred: 9320 bytes HTML transferred: 1860 bytes Requests per second: 83.98 [/sec] (mean) Time per request: 11.908 [ms] (mean) Time per request: 11.908 [ms] (mean, across all concurrent requests) Transfer rate: 38.22 [Kbytes/sec] received
40 requests in .36 seconds, 20 succeeded.
Concurrency Level: 1 Time taken for tests: 0.366 seconds Complete requests: 40 Failed requests: 20 (Connect: 0, Receive: 0, Length: 20, Exceptions: 0) Write errors: 0 Total transferred: 9320 bytes HTML transferred: 1860 bytes Requests per second: 109.26 [/sec] (mean) Time per request: 9.152 [ms] (mean) Time per request: 9.152 [ms] (mean, across all concurrent requests) Transfer rate: 24.86 [Kbytes/sec] received
40 requests (10 threads) in .08 seconds, 20 succeeded
Concurrency Level: 10 Time taken for tests: 0.084 seconds Complete requests: 40 Failed requests: 20 (Connect: 0, Receive: 0, Length: 20, Exceptions: 0) Write errors: 0 Total transferred: 9320 bytes HTML transferred: 1860 bytes Requests per second: 477.45 [/sec] (mean) Time per request: 20.945 [ms] (mean) Time per request: 2.094 [ms] (mean, across all concurrent requests) Transfer rate: 108.64 [Kbytes/sec] received
- bensvobodny_923Nimbostratus
Thanks very much Kevin. Our early testing looks good. Will keep you posted.
One question for you. If we have multiple vips with this irule applied, will the table be different for each vip? or shared.
Example. source ip 1.2.3.4
we want 1.2.3.4 to have 20 connections/sec to vip 1 and 20 connections/sec to vip 2.
Will it work that way, or will it only allow 20 connections from that source ip total.
we added a few tweaks for tcp::respond and logging.
when CLIENT_ACCEPTED { set static::whitelist_class vsratelimit_whitelist_class
if {[class match [IP::client_addr] equals vsratelimit_whitelist_class]}{
return
}
this will give you 20 connections per second per source IP address set cid [clock clicks] set conns 10 set rate 1 set key "[IP::client_addr]:[TCP::client_port]" set current [table keys -subtable [virtual]:[IP::client_addr] -count] table set -subtable [virtual]:[IP::client_addr] $cid 0 indef $rate
if {$current > $conns} { table delete -subtable [virtual]:[IP::client_addr] $cid log local0. "$key: Connection to [IP::local_addr]:[TCP::local_port]\ ([virtual name]). At limit, rejecting (current: $current / max: $conns)" TCP::respond "Your request is being rate limited. Please reduce the frequency of your requests and try again later"
TCP::close } }thanks, Ben
- bensvobodny_923Nimbostratus
when CLIENT_ACCEPTED {
set static::whitelist_class vsratelimit_whitelist_class
if {[class match [IP::client_addr] equals vsratelimit_whitelist_class]}{
return
}
set cid [clock clicks] set conns 20 set rate 1 Track this connection in the subtable using the client IP:port as a key set key "[IP::client_addr]:[TCP::client_port]" set current [table keys -subtable [virtual]:[IP::client_addr] -count] table set -subtable [virtual]:[IP::client_addr] $cid 0 indef $rate
if {$current > $conns} { table delete -subtable [virtual]:[IP::client_addr] $cid log local0. "$key: Connection to [IP::local_addr]:[TCP::local_port]\ ([virtual name]). At limit, rejecting (current: $current / max: $conns)" TCP::respond "Your request is being rate limited. Please reduce the frequency of your requests and try again later"
TCP::close } } - Kevin_Davies_40Nacreous
Different sets of tables for each virtual.
- Kevin_Davies_40NacreousThe table name actually is made up of [virtual]:[IP::client_addr] which is the name if your virtual with the clients IP address.
- bensvobodny_923Nimbostratus
Thanks again Kevin. our customers are very happy now.