Forum Discussion

Mike_Pimlott_61's avatar
Mike_Pimlott_61
Icon for Nimbostratus rankNimbostratus
Nov 28, 2006

Limit connections to node IP after load balancing

Hi

 

 

I have been trawling through the examples on the site and seem to have tried everythin to no avail.

 

 

I am trying to generate an iRule that will monitor the connections to a NODE after load balancing to limit the number of active connections. the node exists across 2 pools, so if there is a way of getting this information that would be good, otherwise a member based limit would be OK.

 

 

My requirement is to limit the connections to an MTA to 20 active sessions, and if an LB decision is made that passes a connection to a "full" member, then I need to to reselect the LB to get access to a different member.

 

 

Is there a way of doing this? everything I seem to try to get the conencted member IP I get errors in the log like.

 

 

Nov 28 10:23:22 tmm tmm[1754]: 01220001:3: TCL error: Rule IP_Address_mapping - Error: No connection established IP::remote_addr needs an established connection! (line 1) invoked from within "IP::remote_addr"

 

 

 

HELP!!!!

9 Replies

  • Hi,

     

     

    You can use connection limits per node without rules: (Click here)

     

     

    Regardless, if you're using a standard VIP, IP::remote_addr or IP::server_addr should return the server IP address in the SERVER_CONNECTED event. Check this post for details on the IP:: commands in the different contexts: (Click here)

     

     

    Are you using a standard VIP? Can you post your rule and VIP configuration?

     

     

    Thanks,

     

    Aaron
  • this is fine thanks - it appeared that the connection limit was enforcing an artificial maximum number of connections rather than max concurrent, but it appears this may have been due to the testing software we have been using. although it still marked the members as unavailable due to connection limit (yellow triangle)

     

     

    I also found out that I could use LB::server addr to give me the member that was chosen for LB, so this gave me a very basic check which I could perform.

     

     

    thanks for the replies
  • Actually... it looks like there is a bug with iRules and the FastL4 profile:

     

     

     

    CR61257

     

     

    Several rule commands are broken for SERVER_CONNECTED with a fastL4 virtual. The problem is that the SERVER_CONNECTED event is raised before there is a serverside filter context.

     

     

     

    This will be fixed in 9.4. If you want to, you can request via support to have this included in past versions. Else, the LB::server addr workaround should get you the data you want.

     

     

    The oddities you were seeing with connection counts might be a result of connections not being closed cleanly. Such connections would be reaped by BIG-IP based on the idle timeout configured in the TCP profile associated with the VIP. You can view the global current connections and their idle timeouts using 'b conn show all'. Check the 'b conn help' output for filtering options. Else, you can use b virtual to get stats for the VIP.

     

     

    Aaron
  • I am using the iRule which appears at http://devcentral.f5.com/wiki/default.aspx/iRules/LimitConnectionsFromClient.html as follows:

     

     

    when RULE_INIT {

     

    array set ::active_clients { }

     

    array set white_client {

     

    10.0.0.1

     

    }

     

    }

     

     

    when CLIENT_ACCEPTED {

     

    set client_ip [IP::remote_addr]

     

    if { [info exists ::active_clients($client_ip)] && ![info exist ::white_client($client_ip)] } {

     

    if {$::active_clients($client_ip) > 10 } {

     

    reject

     

    log local0. "Reject IP $client_ip ($::active_clients($client_ip))"

     

    return

     

    } else {

     

    incr ::active_clients($client_ip)

     

    }

     

    } else {

     

    set ::active_clients($client_ip) 1

     

    }

     

    }

     

    when CLIENT_CLOSED {

     

    set client_ip [IP::remote_addr]

     

    if { [info exists ::active_clients($client_ip)] && ![info exist ::white_client($client_ip)] } {

     

    incr ::active_clients($client_ip) -1

     

    if { $::active_clients($client_ip) <= 0 } {

     

    unset ::active_clients($client_ip)

     

    }

     

    }

     

    }

     

     

    the problem is that connections are still being rejected from 10.0.0.1 and 10.0.0.2. I am running BIG-IP 9.4.3 and the log file is showing a lot of "Reject IP 10.0.0.1 (6)" I copied and pasted the iRule straight from here (and changed the IP's) Any clues why this might be happening?
  • I think there is a typo in the second Codeshare example. Can you replace 'info exist' with 'info exists' in the rule you're testing?

     

     

    Thanks,

     

    Aaron
  • I think it would also be more efficient to add the white list clients to a datagroup of the type address and then use matchclass (Click here) to check the client IP against the class.

     

     

    Aaron
  • Actually, even though the TCL man page doesn't list it, 'info exist variable_name' works.

    I'm not sure how you the iRule you posted could log "Reject IP 10.0.0.1 (6)" if the check on the client IP connection count was still set to 10.

    There seem to be a few logic errors in the Codeshare example though. The first test was to see if the client IP existed in the connection count array and if the client wasn't in the whitelist array. If a new client in the whitelist array made a request that test would be false, but then in the else clause they'd still get added to the connection count array.

    I removed the $client_ip references, as the IP::client_addr value is cached for the duration of the connection. Also, you should increment the connection count if the client is in the connection count array regardless of whether you're going to reset the connection (when you reset the connection, their connection count will be decremented in CLIENT_CLOSED). Lastly, I don't think you need to check if the client is in the white list in CLIENT_CLOSED, as white listed IP's will never be added to the connection count array.

    Aaron

       
       when RULE_INIT {   
          
           Clear the array of clients with open connections to the VIP   
          array set ::active_clients { }   
          
           Replace this array with a datagroup once done testing!   
          array set white_client {   
            10.41.0.610   
            10.0.0.2   
          }   
       }   
          
       when CLIENT_ACCEPTED {   
          
          log local0. "\$::active_clients: [array get ::active_clients] (size: [array size ::active_clients])"   
          
           Check if the client is already in the active clients array   
          if { ([info exists ::active_clients([IP::client_addr])]) } {   
          
              Regardless of whether we reject this client, we've already accepted the TCP connection.   
              so increment the counter for this client.  The count will be decremented when the connection is closed.   
             incr ::active_clients([IP::client_addr])   
             log local0. "Incremented \$::active_clients([IP::client_addr]) to: $::active_clients([IP::client_addr])"   
          
              Check if client is already over the maximum   
             if {$::active_clients([IP::client_addr]) > 10 } {   
          
                 Send TCP reset to client   
                reject   
          
                log local0. "Rejected IP [IP::client_addr], count ($::active_clients([IP::client_addr]))"   
          
             }   
              Don't need an else clause here.  The default action will be to allow the connection to continue.   
          
          } elseif { ![info exists ::white_client([IP::client_addr])] }{   
          
              Client wasn't already in the array and isn't in the white list, so add them to the array with a count of 1.   
             set ::active_clients([IP::client_addr]) 1   
             log local0. "Initialised \$::active_clients([IP::client_addr]) to: 1"   
          }   
       }   
       when CLIENT_CLOSED {   
          
           Check if the client has a count in the array   
          if { [info exists ::active_clients([IP::client_addr])]} {   
          
              Decrement the count by 1   
             incr ::active_clients([IP::client_addr]) -1   
          
              Check if the count is 0 or negative   
             if { $::active_clients([IP::client_addr]) <= 0 } {   
          
                 Clear the array element   
                unset ::active_clients([IP::client_addr])   
             }   
          }   
       }   
       

  • Aaron,

     

     

    Great job! I have tested it and it is working perfectly now.

     

    Regarding the 6 count ... I should have said that the only changes I made were to the IP addresses in the whitelist AND the connection count which I set to 5!

     

     

    Thanks again,

     

    Mike
  • Hi Mike,

     

     

    Thanks for testing it and the confirmation. I updated the Codeshare example with this example.

     

     

    Aaron