Forum Discussion
engtmk
Nimbostratus
Dec 27, 2007bigip1 panic: unable to alloc 4194304 bytes
I found this error in my LTM log, when I asked the support he said:
that TCL was trying to resize the ::users array (internal hash table) with an index of "time,200.35.63.129", and it crossed the 4MB boundary
so I need to know if there is a way to prevent this variable from exceeding the 4MB memory limit
below you will find the iRule that caused the error:
when RULE_INIT {
set ::maxconnect 80
set ::blocktime 120
array set ::users { }
array set ::spammers { }
}
when CLIENT_ACCEPTED {
set clientip [IP::remote_addr]
log local0. "the client ip is $clientip"
if { [matchclass [IP::remote_addr] equals $::smtp_whitelist ] } {
Accept unlimited connections from the whitelist users
return
}
set clientip [IP::remote_addr]
set now [clock second]
if { [ info exists ::spammers($clientip) ] } {
if { $::blocktime > [expr { $now - $::spammers($clientip) }] } {
the user tries to connect in the blocktime period
set ::spammers($clientip) $now
TCP::respond "550 Message Rejected - Too Much spam/r/n"
log local0. "The user tries to send while in the block period - $clientip"
drop
return
}
else {
the timeout has expired free the user from the list
unset ::spammers($clientip)
log local0. "The user has been removed from the list - $clientip"
}
}
if { [ info exists ::users(nb,$clientip)] } {
if { [expr { $now - $::users(time,$clientip) }] > $::blocktime } {
the last connection was before the timeout period
set ::users(nb,$clientip) 1
set ::users(time,$clientip) $now
return
}
else {
the connection was in the timeout
incr ::users(nb,$clientip)
set t $::users(nb,$clientip)
log local0. "the user - $clientip - has been connected $t times"
set ::users(time,$clientip) $now
if { $::users(nb,$clientip) > $::maxconnect } {
the user has exceeded the max no of connections
add him to the spam list
set ::spammers($clientip) $now
set ::users(nb,$clientip) 1
set ::users(time,$clientip) $now
TCP::respond "550 Message Rejected - Too much spam\r\n"
log local0. "this user has started spamming us $clientip "
drop
return
}
}
} else {
new client
set ::users(nb,$clientip) 1
set ::users(time,$clientip) $now
log local0. "this is user has just connected - $clientip"
}
}
Thanks for the help
12 Replies
- hoolio
Cirrostratus
You're using two array entries for each client IP: "$::users(nb,IP)" and "$::users(time,IP)". I think you could combine these to $::users(IP) = "count:timer" to save some memory.
For example, to insert a new client into the array, you could use:
set ::users($clientip) "1:$now"
To check if the client exists in the array, you could use:
if { [info exists ::users($clientip)] } {
To get the count, you could use:
getfield $::users($clientip) : 1
To increment the count, you could use:
set ::users($clientip) [incr [getfield $::users($clientip) : 1]]:$now
And to get the timeout, you could use:
if { [expr { $now - [getfield $::users($clientip) : 2] } ] > $::blocktime } {
Aaron - engtmk
Nimbostratus
we are testing the iRule now after the modification
but drop command here will only drop the new connection only, so what if I want to drop all the connection for that IP that was perviously opened is it possible - hoolio
Cirrostratus
Hi,
There isn't a way within iRules to instantaneously close all existing TCP connections for a client IP address, if some case is true for one of their connections.
It's not a very complete solution, but I suppose you could add checks in other iRule events to see if a "drop" variable has been set for one client IP on another connection. For a TCP-based connection where you aren't collecting the request data or response data, there are five events triggered:
CLIENT_ACCEPTED
LB_SELECTED
SERVER_CONNECTED
SERVER_CLOSED
CLIENT_CLOSED
For details on the events available, check the wiki page for TCP events (Click here).
Adding a check in LB_SELECTED or SERVER_CONNECTED should allow you to close a connection if the client IP was marked as one to drop before the server connection has been established (LB_SELECTED) or when the server side connection is established (SERVER_CONNECTED). This wouldn't help if the server side connection was already established though. I don't think this is an ideal solution as it wouldn't affect connections which are already sending data.
You might be able to use iControl to remove all entries for a client IP from the connection table if some condition is true for one connection. I'm not certain on this, but you could post in the iControl forum asking for suggestions.
Else, you could just live with the existing connections that a client may have open and only prevent them from opening new ones.
Aaron - engtmk
Nimbostratus
The irule is not working
an't use empty string as operand of "-" while executing "expr { $now - $usertime } "
when I log usertime it sometimes returrns nothing
and also the increment I dont think it save
here is the irule
when RULE_INIT {
set ::maxconnect 80
set ::blocktime 120
array set ::users { }
array set ::spammers { }
}
when CLIENT_ACCEPTED {
set clientip [IP::remote_addr]
log local0. "the client ip is $clientip"
if { [matchclass [IP::remote_addr] equals $::smtp_whitelist ] } {
Accept unlimited connections from the whitelist users
return
}
set now [clock second]
if { [ info exists ::spammers($clientip) ] } {
if { $::blocktime > [expr { $now - $::spammers($clientip) }] } {
the user tries to connect in the blocktime period
set ::spammers($clientip) $now
TCP::respond "550 Message Rejected - Too Much spam/r/n"
log local0. "The user tries to send while in the block period - $clientip"
drop
return
}
else {
the timeout has expired free the user from the list
unset ::spammers($clientip)
log local0. "The user has been removed from the list - $clientip"
}
}
if { [info exists ::users($clientip)] } {
set usertime [getfield $::users($clientip) ":" 2]
log local0. "the user time is $usertime"
if { [expr { $now - $usertime } ] > $::blocktime } {
the last connection was before the timeout period
set ::users($clientip) "1:$now"
return
}
else {
the connection was in the timeout
set t [getfield $::users($clientip) ":" 1]
set ::users($clientip) "[incr [getfield $::users($clientip) ":" 1]]:$now"
log local0. "the user - $clientip - has been connected $t times before"
incr t
set ::users($clientip) "$t,$now"
log local0. "the user - $clientip - has been connected $t times after"
if { [getfield $::users($clientip) ":" 1] > $::maxconnect } {
the user has exceeded the max no of connections
add him to the spam list
set ::spammers($clientip) $now
set ::users($clientip) "1:$now"
TCP::respond "550 Message Rejected - Too much spam\r\n"
log local0. "this user has started spamming us $clientip "
drop
return
}
}
} else {
new client
set ::users($clientip) "1:$now"
set ::users(nb,$clientip) 1
set ::users(time,$clientip) $now
log local0. "this is user has just connected - $clientip"
}
} - hoolio
Cirrostratus
Sorry the suggestions haven't worked so far. Can you try logging the value of the array after you try to add new entries to see if they're being added correctly? You can use a foreach loop with array get to write the keys and values out:foreach {key value} [array get ::users { log local0. "$key = $value" }
Aaron - engtmk
Nimbostratus
well I loged the array
foreach {clientarrcount clientarrtime} [array get ::users] {
log local0. "New user $clientarrcount is conneected at $clientarrtime"
}
the output was something like that:
CLIENT_ACCEPTED: New user 41.196.190.217 is conneected at 1:1200559113
but due to the heavy traffic the bigip cpu utilization raise to 100% then it went done with the following in log:
bigip1 LOGIN: Re-starting bcm56xxd
so I need a way to run this irule and to test it without restarting the bigip - hoolio
Cirrostratus
Sorry if this caused a TMM restart. I didn't realize you were testing this on a live system. I'd suggest using a test unit or testing during a maintenance window.
What version are you running this rule on? There was an issue with performance of the clock command in versions before 9.2.
It looks like the IP and other client details are being added to the array correctly at least under normal circumstances. If you are on a version greater than 9.2, I'd suggest testing outside of production, adding debug logging to the iRule and trying to reproduce the problem. Looking at your rule, I don't see where the values would only be added correctly sometimes.
Aaron - engtmk
Nimbostratus
ernel:
Linux 2.4.21-9.4.1.29.0smp
Package:
BIG-IP Version 9.4.1 34.0
Hotfix HF1 Edition
Hot fixes:
CR68549
CR73316
CR75012
CR75638
CR77126
CR77233
CR77679
CR78575
CR78695
CR79616
CR79629
CR79708
CR80120
CR80154
CR80412
CR80637
CR81601
CR81731
CR81797
CR81811
CR81945
CR82672
CR82834
CR83175
CR83397
CR83564 - hoolio
Cirrostratus
So you wouldn't be affected by the clock issue. Are you able to try testing either on a non-production unit or on a production unit during a maintenance window?
If you are on a version greater than 9.2, I'd suggest testing outside of production, adding debug logging to the iRule and trying to reproduce the problem. Looking at your rule, I don't see where the values would only be added correctly sometimes.
Aaron - engtmk
Nimbostratus
I am afraid not, we only got the Acive/standby single pair
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects
