Forum Discussion

Kannan_Thalaia1's avatar
Sep 27, 2014

Need a iRule for VIP connection limit

The idea is:

 

  • We want to limit the access to the load balancer to X number of concurrent users
  • After X concurrent users, the system will not accept anymore connections
  • Users which were on the system already, shouldn’t be kicked out after X (e.g. they have to finish paying)

Appreciate any help on this.

 

3 Replies

  • two build in features could help, but it's not making sur current users are not impacted :

     

    • Connection limit: Specifies the maximum number of concurrent connections allowed for the virtual server. Setting this to 0 turns off connection limits. The default is 0.
    • Connection Rate Limit: Specifies the maximum number of connections-per-second allowed for a virtual server. When the number of number of connections-per-second reaches the limit for a given virtual server, the system redirects additional connection requests.

    They are available per VS or per pool member.

     

    If you want to go with an irule you can start from this one : https://devcentral.f5.com/wiki/iRules.virtual_server_connection_limit_with_HTTP_response.ashx.

     

    You need then to add existing user concept by creating a table with either IP addresses or user's ID to bypass the logic.

     

  • Hello Arnaud,

    Thanks for your time to look on this.

    We created the below iRule to achieve this. But it is not working as expected.

    Do you see any mistake on our irule?

    !!!!!!!

    when RULE_INIT {

    log local0. "Running RULE_INIT" All of these parameters SHOULD be set from a class... So you can vary them and only require ONE iRule for all...

    Max session count set static::max_active_clients 10

    Prefix for session cookie (VS name will be appended) set static::sessionCookiePrefix "session"

    Session (Idle) timeout in seconds set static::sessionTimeout 600

    HTML content for limit notification page set static::html_content "over limit"

    base64 enconded sorry page set ::sorrypage {

    We're Sorry. Our servers are currently over capacity and certain areas of our site may be temporarily unavailable. We're working to resolve the issue as quickly as possible. } log local0. "rule session_limit initialized: max: $static::max_active_clients cookieprefix: $static::sessionCookiePrefix timeout: $static::sessionTimeout" } when HTTP_REQUEST { set subtableName "sessionLimit-[virtual name]" set sessionCookieName "$static::sessionCookiePrefix-[virtual name]" set need_cookie 0 set URI [string tolower [HTTP::uri]]

    ; test cookie presence if {[HTTP::cookie exists $sessionCookieName]} { set client_id [HTTP::cookie $sessionCookieName] Check the session still exists set sessiondata [table lookup -subtable $subtableName $client_id] if { $sessiondata != "" } { We have a valid session... The lookup has reset the timer on it so just finish processing Optional processing in here to check or validate the client session via IP etc if required... log local0. "Valid session $client_id - continuing" return } } No valid session... So do we have a free 'slot'? log local0. "No session. Checking for free slot (Max $static::max_active_clients)" set sessionCount [table keys -subtable $subtableName -count] log local0. "No session. Checking for free slot (Current $sessionCount)"

    if {($sessionCount < $static::max_active_clients) or ($URI contains "ops")} { Yes we have a free slot... Allocate it and note that we need to set the cookie on the client set need_cookie 1 set client_id [format "%08d" [expr { int(100000000 * rand()) }]] set sessionValue [IP::client_addr]

           avoid /ops/ to be added on count table
      if { !($URI contains "ops") } {
      table add -subtable $subtableName $client_id $sessionValue $static::sessionTimeout
      }            
      log local0. "New Session ($client_id) added value $sessionValue Timeout $static::sessionTimeout"
    

    } else { Send a response HTTP::respond 200 content $static::html_content HTTP::respond 200 content [b64decode $::sorrypage]

       Close the connection
      TCP::close
    
       Log a message to /var/log/ltm if debug is enabled
      if {$::debug}{log local0. "Over limit showing limiter page"}
    

    } }

    when HTTP_RESPONSE { ; insert cookie if needed if {$need_cookie == 1} { HTTP::cookie insert name $sessionCookieName value $client_id path "/" } }

    !!!!!

  • when RULE_INIT {
    
       log local0. "Running RULE_INIT"
        All of these parameters SHOULD be set from a class... So you can vary them and only require ONE iRule for all...
    
        Max session count
       set static::max_active_clients 10
    
        Prefix for session cookie (VS name will be appended)
       set static::sessionCookiePrefix "session"
    
        Session (Idle) timeout in seconds
       set static::sessionTimeout 600
    
        HTML content for limit notification page
       set static::html_content "over limit"
    
        base64 enconded sorry page
       set ::sorrypage {    
                We're Sorry.  Our servers are currently over capacity and certain areas of our site may be temporarily unavailable.  We're working to resolve the issue as quickly as possible.
        }
       log local0. "rule session_limit initialized: max: $static::max_active_clients cookieprefix: $static::sessionCookiePrefix timeout: $static::sessionTimeout"
    }
    when HTTP_REQUEST {
       set subtableName "sessionLimit-[virtual name]"
       set sessionCookieName "$static::sessionCookiePrefix-[virtual name]"
       set need_cookie 0
       set URI [string tolower [HTTP::uri]]
       
       ; test cookie presence
       if {[HTTP::cookie exists $sessionCookieName]} {
          set client_id [HTTP::cookie $sessionCookieName]
              Check the session still exists
             set sessiondata [table lookup -subtable $subtableName $client_id]
             if { $sessiondata != "" } {
              We have a valid session... The lookup has reset the timer on it so just finish processing
              Optional processing in here to check or validate the client session via IP etc if required...
             log local0. "Valid session $client_id - continuing"
             return
          }
       }
        No valid session... So do we have a free 'slot'?
       log local0. "No session. Checking for free slot (Max     $static::max_active_clients)"
       set sessionCount [table keys -subtable $subtableName -count]
       log local0. "No session. Checking for free slot (Current $sessionCount)"
    
       if {($sessionCount < $static::max_active_clients) or ($URI contains "ops")} {
           Yes we have a free slot... Allocate it and note that we need to set the cookie on the client
          set need_cookie 1
          set client_id [format "%08d" [expr { int(100000000 * rand()) }]]
          set sessionValue [IP::client_addr]
              
               avoid /ops/ to be added on count table
          if { !($URI contains "ops") } {
          table add -subtable $subtableName $client_id $sessionValue $static::sessionTimeout
          }            
          log local0. "New Session ($client_id) added value $sessionValue Timeout $static::sessionTimeout"
       } else {
           Send a response
          HTTP::respond 200 content $static::html_content
              HTTP::respond 200 content [b64decode $::sorrypage]  
    
           Close the connection
          TCP::close
    
           Log a message to /var/log/ltm if debug is enabled
          if {$::debug}{log local0. "Over limit showing limiter page"}
       }
    }
    
    when HTTP_RESPONSE {
       ; insert cookie if needed
       if {$need_cookie == 1} {
          HTTP::cookie insert name $sessionCookieName value $client_id path "/"
       }
    }