Forum Discussion

Rick_Turner_771's avatar
Rick_Turner_771
Icon for Nimbostratus rankNimbostratus
Jul 02, 2010

Same Segment Load Balancing

I have a new requirement to provide same segment load balancing. Up till now we've used the LTMs only for pass-thru load balancing. Basically client on VLAN1 to servers on VLAN2.

 

Now I have web servers that need access to application servers, both on VLAN2. Due to the asynchronous routing it doesn't work. I've figured out how to SNAT against a given virtual server to make this work.

 

As there are more and more requirements for this type of load balancing, I'd prefer to SNAT anything coming from VLAN2 destined to a pool on VLAN2. The catch is that I don't want to SNAT any traffic destined to VLAN3 from VLAN1 or VLAN2. Need to maintain addresses to avoid breaking firewall rules.

 

 

The following iRule works against an individual virtual server:

 

 

when LB_SELECTED { if {[IP::addr "[IP::client_addr]/24" equals "[LB::server addr]/24"]} { snatpool SNAT_POOT_LB1 } }

 

 

I tried to apply this to a wildcard_forwarding virtual, no go.

 

 

Any suggestions?

 

 

Thanks,

 

 

Rick

 

 

3 Replies

  • Thanks for the replies. I've had a couple conversations with my SE and he has encouraged us to perform the SNAT against a virtual server rather than all traffic like I was driving. There are pros and cons for both directions. The SE is conviced that this will be more difficult than SNAT against a virtual. He did come back with an iRule that SNATs to the virtual address rather than the SNATPOOL. I like this in that it virtually eliminates my concern to running out of ephemeral ports. This tested out nicely in my lab.

     

     

    when LB_SELECTED {

     

    set ClientIP [clientside {IP::remote_addr}]

     

    set VirtualIP [clientside {IP::local_addr}]

     

    set NodeIP [LB::server addr]

     

    log local0. "Client: $ClientIP VIP: $VirtualIP Node: $NodeIP"

     

    if { [IP::addr $ClientIP/24 equals $NodeIP/24] } {

     

    log local0. "Going to SNAT Client: $ClientIP to VIP: $VirtualIP targeting Node: $NodeIP"

     

    snat $VirtualIP

     

    }

     

    }

     

  • Posted By Rick Turner on 07/15/2010 02:20 PM

     

    Thanks for the replies. I've had a couple conversations with my SE and he has encouraged us to perform the SNAT against a virtual server rather than all traffic like I was driving. There are pros and cons for both directions. The SE is conviced that this will be more difficult than SNAT against a virtual. He did come back with an iRule that SNATs to the virtual address rather than the SNATPOOL. I like this in that it virtually eliminates my concern to running out of ephemeral ports. This tested out nicely in my lab.

     

     

    when LB_SELECTED {

     

    set ClientIP [clientside {IP::remote_addr}]

     

    set VirtualIP [clientside {IP::local_addr}]

     

    set NodeIP [LB::server addr]

     

    log local0. "Client: $ClientIP VIP: $VirtualIP Node: $NodeIP"

     

    if { [IP::addr $ClientIP/24 equals $NodeIP/24] } {

     

    log local0. "Going to SNAT Client: $ClientIP to VIP: $VirtualIP targeting Node: $NodeIP"

     

    snat $VirtualIP

     

    }

     

    }

     

     

     

    I hear a lot of SEs recommending this method now as it makes logging easier since you'll know for which VIP your traffic is sent. I'm not sure how this helps with port exhaustion since you're now limited to a single IP and it's associated 64.5K ports versus a SNAT pool to which you could add IPs whenever you want. Also, why is he recommending using the LB_SELECTED event here rather than CLIENT_ACCEPTED? Finally - why do we need to set variables to things that are already in memory...Why can't we simply use local_addr, server_addr, and remote_addr for our test? Anywho - looking forward to hearing Hoolio's thoughts.
  • Not sure how one monitors either situation to be proactive at measuring the ephemeral port usage.

    The only thing I can think of is spot checks or a custom script which checks the 'b conn ss client 1.1.1.1' where 1.1.1.1 is the SNAT IP that you want to check for serverside connections from.

    As to why he selected LB_SELECTED vs CLIENT_ACCEPTED, I think he stumbled upon this iRule on devcentral and it happened to work.

    I'd guess he took a Codeshare example which checked the selected server in LB_SELECTED and applied SNAT only if the client and server IP's were on the same subnet and modified that to use the VS address instead of SNAT automap. If you do want to enable SNAT based on the selected server, you'd either need to use LB_SELECTED or force a load balancing decision earlier using LB::select. It's much simpler and potentially more efficient to use LB_SELECTED as you let LTM make the load balancing decision just once when it would by default. Here is some useful info Jason got on this:

    The downside [to using LB::select in CLIENT_ACCEPTED or HTTP_REQUEST] is that any further upstream filter won’t have an ability to influence the load-balancing selection (yes, that’s right, HTTP is not always the top-level filter – there are others like ramcache, deflate, plugins ala ASM, WAM, etc). However, in the basic case where HTTP is the last filter or none of the other filters will be influencing the LB pick, then it is totally fine. This is also why the load balancing selection isn’t available – it hasn’t occurred yet. We put off the LB pick until the proxy gets the accept notification, thus allowing all the filters on the way up to change the selection criteria. The LB pick is actually one of the most performance costly events that occur in processing a flow. So, we don’t want to make it, and then throw it away because it either wasn’t needed (think ramcache), or it was wrong because selection criteria was subsequently changed.

    I asked him is snat $VirtualIP was going to use the virtual IP for the SNAT address...

    This will definitely work in that LTM will use any IP you specify in the snat command to source traffic. If you're using a multi-VLAN implementation layout, this might not be a good solution as LTM will be sending traffic destined for an internal VLAN out the external VLAN with a source IP of the virtual server. As a result, the server would probably have to respond to a router instead of directly back to the LTM on the server's VLAN. This can add unnecessary connections to the router and more complexity to troubleshooting.

    As Chris suggested, you could eliminate all of the intermediate variables as these just use up extra memory:

    
    when LB_SELECTED {
        When a load balancing selection is made, check if the client IP is on the same /24 subnet as the selected server
       if { [IP::addr [IP::client_addr]/24 equals [LB::server addr]] } {
    
           Snat using the VS address
          snat [IP::local_addr]
          log local0. "SNATing client: [IP::client_addr] to VIP: [IP::local_addr] targeting pool IP: [LB::server addr]"
       }
    }
    

    If the servers were on a different VLAN than the VS, you could adapt this iRule to use the same last octet as the VS (assuming this IP is free) but on the server's VLAN:

    
    when LB_SELECTED {
    
       if { [IP::addr [IP::client_addr]/24 equals [LB::server addr]] } {
    
          log local0. "SNATing client: [IP::client_addr] to VIP's last octet:\
             1.2.3.[getfield [IP::local_addr] "." 4] targeting pool IP: [LB::server addr]"
    
          snat 1.2.3.[getfield [IP::local_addr] "." 4]
       }
    }
    

    If you wanted to do this more programmatically, you could take the first three octets of the server IP and the last octet of the VS IP:

    
    when LB_SELECTED {
    
       if { [IP::addr [IP::client_addr]/24 equals [LB::server addr]] } {
    
           Get the first three octets of the server IP address
          scan [LB::server add] {%d.%d.%d.%d} a b c d
    
           Snat using the first three octets of the server IP with the last octet of the VS IP
          snat $a.$b.$c.[getfield [IP::local_addr] "." 4]
    
          log local0. "SNATing client: [IP::client_addr] to VIP's last octet:\
             $a.$b.$c.[getfield [IP::local_addr] "." 4] targeting pool IP: [LB::server addr]"
       }
    }
    

    Aaron