Forum Discussion

Perry_71428's avatar
Perry_71428
Icon for Nimbostratus rankNimbostratus
Mar 12, 2009

Global variables question

Hi

 

 

In the following rule from the CodeBase, is there a way that ::max_active_clients can be changed without the RULE_INIT being fired? When RULE_INIT gets fired the ::total_active_clients will get reset to 0 which is not what I want to happen.

 

 

What I want to do is to have a similar rate limiting rule, but be able to manually tweak the ::max_active_clients clients value as the rule is running.

 

 

Can a global variable be set in one irule, and then used in another irule?

 

 

Also, as I am new to this, do global vaiables have a scope across the whole F5 (all virtual servers / pools) or just the virtual server where they were initialised?

 

 

I basically want to have a rule with different values of ::max_active_clients per virtual server - so do I need to use a different global variable name per rule for each virtual server?

 

 

Thanks for any help you can give.

 

 

rule HTTP_session_limit {

 

when RULE_INIT {

 

set ::total_active_clients 0

 

set ::max_active_clients 100

 

log local0. "rule session_limit initialized: total/max: $::total_active_clients/$::max_active_clients"

 

}

 

when HTTP_REQUEST {

 

; test cookie presence

 

if {[HTTP::cookie exists "ClientID"]} {

 

set need_cookie 0

 

set client_id [HTTP::cookie "ClientID"]

 

; if cookie not present & connection limit not reached, set up client_id

 

} else {

 

if {$::total_active_clients < $::max_active_clients} {

 

set need_cookie 1

 

set client_id [format "%08d" [expr { int(100000000 * rand()) }]]

 

incr ::total_active_clients

 

; otherwise redirect

 

} else {

 

HTTP::redirect "http://sorry.domain.com/"

 

return

 

}

 

}

 

}

 

when HTTP_RESPONSE {

 

; insert cookie if needed

 

if {$need_cookie == 1} {

 

HTTP::cookie insert name "ClientID" value $client_id path "/"

 

}

 

}

 

when CLIENT_CLOSED {

 

; decrement current connection counter for this client_id

 

if {$::total_active_clients > 0} {

 

incr ::total_active_clients -1

 

}

 

}

 

}

6 Replies

  • A global variable is accessible from any iRule on any connection. You can create a separate iRule with a RULE_INIT event and reset the value of the global variable:

     
     when RULE_INIT { 
      
         Update the ::max_active_clients value without affecting the other iRule 
        set ::max_active_clients 2000 
     } 
     

    There is an issue with that Codeshare example though:

    In the current iteration of the rule, a new session is created and the total session count incremented on each HTTP request which doesn't already have a session cookie. The only time the total count is decremented is when the TCP connection is closed. So if there are multiple clients connecting over the same TCP connection (ie, coming in via a proxy), "session leakage" would occur. For proxied users, multiple sessions would be created, but only one session removed when the TCP connection is closed. To account for this, you'd have to count the number of new sessions created per TCP connection and then decrement the session count by this count in CLIENT_CLOSED.

    Aaron
  • Thanks

    Yes I did see the rule caveat, so no worries there.

    So in the scenario that I have two virtual servers VS1 and VS2 and I wax max connections for VS1 to be 100 and for VS2 to be two hundred if could do something like this....

    SET_MAX_LIMITS Irule

      
      when RULE_INIT {  
          Set Global variables value without affecting the other iRule  
         set ::max_active_clients_vs1 100 
         set ::max_active_clients_vs2 200 
      } 
     

    I would then have 2 copies of the main irule (one assigned to VS1 and one assigned to VS2) that would have RULE_INIT sections like this...

      
      when RULE_INIT {  
          Set Global variables value without affecting the other iRule  
         set ::total_active_clients_vs1 0 
      } 
      remainder of vs1 irule checking against ::max_active_clients_vs1 
     

      
      when RULE_INIT {  
          Set Global variables value without affecting the other iRule  
         set ::total_active_clients_vs2 0 
      } 
      remainder of vs2 irule checking against ::max_active_clients_vs2 
     

    When I want to adjust the ::max_active_clients_xxx I just amend the initial irule through the F5 control centre.

    The only question I have is do I need to associate the "SET_MAX_LIMITS" irule to VS1 and/or VS2 or can it just sit standalone?

    Thanks again.

  • It looks like a good understanding of how to handle global variables in multiple iRules. You need to name them uniquely in all iRules to prevent trampling. If you've intentionally named them the same so you can configure one iRule from another, you only need to set the global variable in one iRule. As the global variable can be referenced from any iRule on any virtual server, the rule doesn't need to be added to any specific virtual server. Though, to make it simpler for someone else reading your iRule it might be clearer to explicitly set it in the request limiting iRule on each virtual server, as well as the "configuration" iRule:

     

     

    vs1_limit_rule

     

     

     
     when RULE_INIT { 
      
         This max is set here and in the set_max_limits_rule iRule 
        set ::vs1_max 1000 
     } 
     when HTTP_REQUEST { 
      
         Rest of iRule code... 
     } 
     

     

     

    vs2_limit_rule

     

     

     
     when RULE_INIT { 
      
         This max is set here and in the set_maxes_rule iRule 
        set ::vs2_max 2000 
     } 
     when HTTP_REQUEST { 
      
         Rest of iRule code... 
     } 
     

     

     

    set_max_limits_rule

     

     

     
     when RULE_INIT { 
      
         This max is set here and in the set_maxes_rule iRule 
        set ::vs1_max 1000 
        set ::vs2_max 2000 
     } 
     

     

     

    Aaron
  • Thanks Aaron

     

     

    I have a test only virtual server set up so I'll try this out over the next day or so. Just got to work out the fix for the CLIENT_CLOSED that you mentioned.
  • Just a thought....

     

     

    Can you access IRULE global variables through iControl? If so I could create a management panel that would show me current values, alert me when say connections are > 90% of max allowed, and reset them as needed.

     

     

    Thanks
  • I don't think you can access a global variable from the iControl API. But you should be able to access/modify a datagroup or stats profile from iControl. You can poll a stats profile via SNMP as well.

     

     

    Aaron