Forum Discussion

kman_52500's avatar
kman_52500
Icon for Nimbostratus rankNimbostratus
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

  • 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
  • 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?
  • 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?
  • 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
  • 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.
  • 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
  • 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?

     

     

  • 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