Forum Discussion

Mike_Lowell_456's avatar
Mike_Lowell_456
Historic F5 Account
Sep 09, 2005

hash-based load balancing; aton() and pool member index's

Hi guys,

 

 

I've searched through the existing forum topics, and I couldn't seem to find an answer for this type of question.

 

 

My end goal is to distribute all traffic fairly evenly between two gateways, but ensure that a given client network (/24) always goes to the same gateway as long as the gateway is up (I only have two gateways). If one gateway goes down, I want to select the other gateway (i.e. send all traffic to the one gateway).

 

 

My idea for how to achieve this is as follows:

 

GATEWAY_INDEX = (CLIENT_IP_ADDRESS & 0xffffff00) % NUMBER_OF_ACTIVE_NODES

 

use pool "gateways" member GATEWAY_INDEX

 

 

This is "kind of" achievable, but I'm performing each step in a very inefficient manner that I think can be much better.

 

 

First, does anybody know a better way to convert an IP address to a number? So far I'm doing this:

 

regexp {(\d+)\.(\d+)\.(\d+)\.(\d)+} [IP::remote_addr] -> a b c d

 

set client_ip [expr [expr [expr $a << 24] + [expr $b << 16 ]] + [expr $c << 8]]

 

 

I was expecting to find a function like aton(), or a special format()/printf() format type, but I couldn't seem to find such a thing. Is there a better way to turn an IP address into a number? Also, notice that I'm intentionally only capturing the top 24 bits.

 

 

Next, I want to select pool members based on their index within a pool. i.e.

 

 

use pool mypool member index 0

 

..would select the first pool member, whereas:

 

use pool mypool member index 1

 

...would select the second pool member.

 

 

The goal being to generate a dynamic index into the pool based on how many members are available:

 

set active_member_count [active_members $pool_name]

 

 

 

So far I've worked around this by using specific server IP addresses starting at 1 that are in a row, such as 1.1.1.1 and 1.1.1.2.

 

 

My current rule looks like this:

 

 

 

when CLIENT_ACCEPTED {

 

regexp {(\d+)\.(\d+)\.(\d+)\.(\d)+} [IP::remote_addr] -> a b c d

 

set client_ip [expr [expr [expr $a << 24] + [expr $b << 16 ]] + [expr $c << 8]]

 

set gateway_network "10.10.1"

 

set pool_name "gate_pool"

 

set active_member_count [active_members $pool_name]

 

set gateway_hash [expr [expr $branch_client_ip % $active_member_count] + 1]

 

set gateway "$gateway_network.$gateway_hash"

 

 

pool $pool_name member $gateway

 

}

 

 

 

I do realize that much of this could be combined into a single step without variable assignements, but I've separated the individual steps for (some) additional clarity.

 

 

I'm not very good with TCL (as you can see!), so I think there must be a better way. Any help appreciated!

 

 

a1l0s2k9

 

 

 

3 Replies

  • Mike_Lowell_456's avatar
    Mike_Lowell_456
    Historic F5 Account
    One correction, the client network address needs to be shifted right 8 bits before the modulus is computed, which is not done in the pseudo-code, or the example iRule...the example above could never work as expected with such a small modulus. Whoops!
  • If you use least connections on your gateway pool and build a child profile to the srcaddr persistence profile with a mask of /24, you shouldn't need an iRule at all to achieve your goals. If one gateway that has persistent records goes down, the persistent information is deleted and new connections will flow to your only available gateway.

    iRule comparison below:

    
    when CLIENT_ACCEPTED {
       use pool gate_pool
       persist srcaddr mask 255.255.255.0 
    }

  • Mike_Lowell_456's avatar
    Mike_Lowell_456
    Historic F5 Account
    Thanks!

     

     

    I originally thought to use persistence in this manner, but the problem is actually a bit more complicated than I originally explained.

     

     

    There are actually two pairs of BIG-IP's load balancing VPN's (one pair on top, one pair at the bottom, like a firewall sandwich), like this:

     

     

    [BRANCH1] [BRANCH2]

     

    | /

     

    [BIG-IP ext]

     

    | |

     

    [VPN1] [VPN2]

     

    | |

     

    [BIG-IP int]

     

    |

     

    [HQ network]

     

     

     

    Also, there are actually 500 branch offices. A VPN tunnel is only established to one VPN at a time, so the only way to get from a given branch into the "HQ network" is via the VPN which has the tunnel established. Similarly, the only way to get to a given branch FROM the HQ network is via the VPN which has a tunnel established.

     

     

    As you can see, both pairs of BIG-IP's (top and bottom) need to have the same persistence information so they both pick the same VPN, regardless of the direction of the traffic (whether a connection is originated from the branch, or from the HQ).

     

     

    This is why I thought to use a hash based on the network of the branch office, but maybe there is a better way? My plan was for traffic coming FROM the branch, I would use a rule that looked at the SOURCE network. On traffic going TO the branch, I would use a rule that looked at the DESTINATION network. Both pairs of BIG-IP's would have essentially the same rule, except that one would inspect the source network, while the other would inspect the destination network (in both cases, the branch office network). Does that make sense?

     

     

    I'm very open to alternate ways to solve this problem. As always, any help is greatly appreciated!

     

     

    a1l0s2k9