Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

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

0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
You might be better off running this in the "when CLIENT_ACCEPTED" event.

I also find that data groups are a lot easier to use in situations like this.

Make an "address" type datagroup called "vlan2" for instance and have your rule check against that.


when CLIENT_ACCEPTED {
if { ( [matchclass [IP::addr [IP::client_addr]]]  eq $::vlan2) } 
 {
     snatpool SNAT_POOL_LB1 
                                      } 
                              }

My syntax is probably a bit messy, but I'm sure Hoolio will be along to correct me soon. <img src='/DesktopModules/ActiveForums/themes/ActiveSocial//emoticons/smile.gif' align="absmiddle" border="0" />
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
A forwarding virtual server by definition doesn't do load balancing, so LB_SELECTED won't ever trigger. As Chris suggested, if you can define the hosts/subnets you want to SNAT for in a datagroup, you can check the client IP (or destination IP using (IP::local_addr]) and apply SNAT accordingly.

Chris, I think [IP::addr [IP::client_addr]] is either going to return a runtime error or 1. Either way, it won't work <img src='/DesktopModules/ActiveForums/themes/ActiveSocial//emoticons/smile.gif' align="absmiddle" border="0" />. You don't need to use IP::addr in a class command against an address type datagroup. LTM will do an address comparison by default for when using an address type datagroup.


when CLIENT_ACCEPTED {
   if { [matchclass [IP::client_addr]  eq vlan2] } {
      snatpool SNAT_POOL_LB1 
   }
}


Aaron
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
Posted By hoolio on 07/04/2010 06:44 AM
A forwarding virtual server by definition doesn't do load balancing, so LB_SELECTED won't ever trigger. As Chris suggested, if you can define the hosts/subnets you want to SNAT for in a datagroup, you can check the client IP (or destination IP using (IP::local_addr]) and apply SNAT accordingly.

Chris, I think [IP::addr [IP::client_addr]] is either going to return a runtime error or 1. Either way, it won't work . You don't need to use IP::addr in a class command against an address type datagroup. LTM will do an address comparison by default for when using an address type datagroup.

when CLIENT_ACCEPTED {
   if { [matchclass [IP::client_addr]  eq vlan2] } {
      snatpool SNAT_POOL_LB1 
   }
}


Aaron


Thanks for the explanation! I'll try and remember I don't need to use IP::ip_addr when I'm using matchclass. Can you remind me when we need to reference the datagroup names with $:: in front of them?
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
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
}
}
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
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.
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
On the port issue. SNAT to the virtual obviously doesn't eliminate the port exhaustion issue. It just changes the dynamic. A SNATPOOL for all virtuals just requires a larger pool. Not sure how one monitors either situation to be proactive at measuring the ephemeral port usage. For me, I highly doubt I will have an isse with the virtual SNAT and if I do, it will be isolate to an application and potentially easier to troubleshoot. With the SNATPOOL, this might become a universal problem generating more management stress than is necessary.

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 have a feeling if I ask, he won't be able to tell me. I asked him is snat $VirtualIP was going to use the virtual IP for the SNAT address and he was quite certain it would not, until we traced it. For me it works, I'm a router jocky managing load balancers and the majority of this is Greek to me
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER
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
0