Forum Discussion
kman_52500
Nimbostratus
May 01, 2009"syntax error" at character '}'
Hello,
I am trying to add an iRule to our f5 and it loads just fine but I get an error when doing a config sync or b verify load.
The iRule works well and loads just fine, but this error is thrown ever time bigip.conf is loaded:
Reading configuration from /config/profile_base.conf.
rule limit_uri {
/config/bigip.conf: "syntax error" at character '}' in line 217
rule limit_uri {
/config/bigip.conf: "syntax error" at character '}' in line 217
Here is the iRule:
when RULE_INIT {
set ::rate 30
set ::window 300
set ::purge_interval 10
set ::last_purge [clock seconds]
array set ::hit_list {}
array unset ::hit_list
array set ::block_state {}
array unset ::block_state
array set ::hit_count {}
array unset ::hit_count
}
when HTTP_REQUEST {
if { [matchclass [string tolower [HTTP::path]] ends_with $::limit_uris] } {
set current_time [clock seconds]
set request_id "[HTTP::host]_[expr { int(1000000 * rand()) }]"
set ::hit_list($request_id) $current_time
set window_start [expr $current_time - $::window]
if { not [info exists ::block_state([HTTP::host])] } {
set ::block_state([HTTP::host]) 0
set ::hit_count([HTTP::host]) 0
}
if { [expr $current_time - $::last_purge] > $::purge_interval } {
set ::last_purge $current_time
set count 0
foreach { request_id request_time } [array get ::hit_list [HTTP::host]*] {
if { $request_time < $window_start } {
unset ::hit_list($request_id)
} else {
incr count
}
}
set ::hit_count([HTTP::host]) $count
}
if { $::hit_count([HTTP::host]) > $::rate } {
HTTP::respond 503 content "Page LimitedThis page is being limited due to excessive use. Please try again later"
if { $::block_state([HTTP::host]) == 0 } {
log local0. "Started blocking [HTTP::host]"
set ::block_state([HTTP::host]) 1
}
} elseif { $::block_state([HTTP::host]) == 1 } {
log local0. "Stopped blocking [HTTP::host]"
set ::block_state([HTTP::host]) 0
}
}
}
8 Replies
- hoolio
Cirrostratus
Does the error occur when you try to save the iRule or when you try to load the configuration? Which LTM version are you running?
If you replace the set and unsets in the RULE_INIT event:array set ::hit_list {} array unset ::hit_list array set ::block_state {} array unset ::block_state array set ::hit_count {} array unset ::hit_count
with this:if {[array exists ::hit_list]}{ array unset ::hit_list } if {[array exists ::block_state]}{ array unset ::block_state } if {[array exists ::hit_count]}{ array unset ::hit_count }
Do you still see the error?
Aaron - kman_52500
Nimbostratus
Yes, that fixed the problem.
It only happened when loading bigip.conf and not when editing/adding the iRule.
I am running LTM 9.1.2.
Are there any other problems or optimizations you see with this iRule? - kman_52500
Nimbostratus
That change also seems to have made things a little more unstable.
Previously I could get 10K-20K hits no problem for an extended period of time.
With the change you made it no longer reports syntax errors, but it now causes the F5 to fail over at about 8K-10K concurrent connections.
Do you have any other suggestions to get around the syntax problem that might not cause the F5 to fail over so easily? - hoolio
Cirrostratus
The issue wasn't with your rule--it's down to a bug in parsing the iRule. The issue is described in SOL7988 (Click here). I'm not sure why it would matter if you set the array to nothing and then unset it versus just unsetting it. Can you try logging the array size to see if the array isn't getting cleared? You could try replacing the {}s with ""s to avoid the bug from SOL7988 and use your original set/unset.
I've read on DC that the clock command used significant CPU cycles in pre-9.2 versions. I've never seen a CR for this though. There have been so many other fixes since 9.1.2 that it would make a lot of sense to upgrade to a more current, supported version. 9.3.x will be supported for one more year. 9.4.7 is fairly well burned in and is a sustaining version now.
Here are some other suggestions...
You can wrap the operands for expr in curly braces:
[expr $current_time - $::window] ->
[expr {$current_time - $::window}]
http://tmml.sourceforge.net/doc/tcl/expr.html
PERFORMANCE CONSIDERATIONS
Enclose expressions in braces for the best speed and the smallest storage requirements. This allows the Tcl bytecode compiler to generate the best code.
You could also consider not calculating a request ID or adding any specific info on the current request to the arrays until you determine whether the request will be allowed or not. This would cut down on resource usage (but might not provide as accurate of metrics as what you have now).
You can check this post for other performance related suggestions:
http://devcentral.f5.com/wiki/default.aspx/iRules/HowToWriteFastRules.html
Aaron - kman_52500
Nimbostratus
I considered not logging requests that are blocked, but I would still like the accuracy.
We plan on upgrading to 9.4.7 sometime soon.
I got the rule to pass the syntax check, but not crash the f5 by adding back in the array set commands as they where but replacing the unset command with your suggestion.
Are there any alternatives to the clock command that are more efficient?
Can you thing of a better way of creating the request_id so that it is unique but not as resource intensive?
Thanks for all your help. - hoolio
Cirrostratus
So what did you actually end up using in RULE_INIT?
To be honest, I don't know what the exact issue with clock was in pre-9.2 so I can't give any suggestions on that. Here is a post which references the issue ([URL]http://devcentral.f5.com/Default.aspx?tabid=53&forumid=5&tpage=1&view=topic&postid=2444824471[/URL]).
As far as the request_id, if you're just trying to track a request was made at a specific time to a host and then count how many requests to a specific host have been made since the window started, how about starting with an ID of 0 and incrementing from there? Reset the counter at whatever the largest possible number for TCL is minus one. This assumes that the counter will never lap itself during your window. You may want to keep a counter per host.
Aaron - kman_52500
Nimbostratus
I changed it to:
array set ::hit_list {}
if {[array exists ::hit_list]}{
array unset ::hit_list
}
array set ::block_state {}
if {[array exists ::block_state]}{
array unset ::block_state
}
array set ::hit_count {}
if {[array exists ::hit_count]}{
array unset ::hit_count
}
This caused it to crash too so I went back to my original rule and it throws the syntax error, but doesn't cause the F5 to fail over under load.
Any other suggestions on how to get rid of this syntax error without crashing the F5? - kman_52500
Nimbostratus
Never mind. I just noticed your "" suggestion.
Putting
array set ::array_name "" fixed the issue and the rule seems to also be stable now.
Thanks
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