Forum Discussion

Brad_Otlin's avatar
Brad_Otlin
Icon for Employee rankEmployee
Mar 06, 2013

Exchange 2010 SNAT Persistence iRule on Multiple VLANs

My BIGIP 11000s on V11.2.1 is fronting 16 Exchange 2010 CAS servers for Outlook Anywhere. The virtual server is using SNAT iRule to ensure SNAT IP persistence similar to this:

 

********

 

when RULE_INIT {

 

Use a local array to configure SNAT addresses.

 

These addresses must be defined in a SNAT pool to ensure TMM

 

sends gratuitous ARPs during a failover.

 

In this example, we use three addresses. Replace

 

these with the IP addresses used in your SNAT Pool.

 

Follow the pattern of the existing addresses to add more than three.

 

set static::snat_ips(0) 10.0.0.1

 

set static::snat_ips(1) 10.0.0.2

 

set static::snat_ips(2) 10.0.0.3

 

}

 

when HTTP_REQUEST {

 

Calculate the crc32 checksum of the client IP.

 

Use the modulo of the checksum and the number of SNAT IPs in the array

 

to select a SNAT IP address.

 

snat $static::snat_ips([expr {[crc32 [IP::client_addr]] % [array size static::snat_ips]}])

 

}

 

********

 

(These SNAT IPs are also in the SNAT Pool assigned to the VS)

 

We are now introducing more CAS servers on a different subnet that will be in a different VLAN which will also connect to the BIGIPs. So I will need SNAT IPs for the new subnet to talk to the new CAS servers. The iRule is NOT intelligent enough to choose a SNAT from the same subnet as the chosen pool member. So I edited the above iRule to add new SNATs to a different static variable (NEW_snat_ips) and then an "if" conditional statement to assign a SNAT IP based on the load balanced server's network it belongs to.

 

Does this look correct? valid? Will it work? (oh, and can the set static commands be consolidated with some type of range command?)

 

********

 

when RULE_INIT {

 

set static::snat_ips(0) 10.1.1.138

 

set static::snat_ips(1) 10.1.1.139

 

set static::snat_ips(2) 10.1.1.140

 

set static::snat_ips(3) 10.1.1.141

 

set static::snat_ips(4) 10.1.1.142

 

set static::snat_ips(5) 10.1.1.143

 

set static::NEW_snat_ips(0) 10.2.2.225

 

set static::NEW_snat_ips(1) 10.2.2.226

 

set static::NEW_snat_ips(2) 10.2.2.227

 

set static::NEW_snat_ips(3) 10.2.2.228

 

set static::NEW_snat_ips(4) 10.2.2.229

 

set static::NEW_snat_ips(5) 10.2.2.230

 

}

 

when HTTP_REQUEST {

 

if {

 

IP::addr [LB::server addr] starts_with "10.1.1" }

 

{

 

snat $static::snat_ips([expr {[crc32 [IP::client_addr]] % [array size static::snat_ips]}])

 

}

 

else {

 

snat $static::NEW_snat_ips([expr {[crc32 [IP::client_addr]] % [array size static::snat_ips]}])

 

}

 

}

 

********

 

3 Replies

  • when HTTP_REQUEST {

    i understand this should be LB_SELECTED event because pool member has not yet been selected in HTTP_REQUEST event.

     

  • actually, nitass, the iRule in the v4.4 deployment guide http://www.f5.com/pdf/deployment-gu...010-dg.pdf says to use "when CLIENT_ACCEPTED". However, devcentral article https://devcentral.f5.com/wiki/iRul...tence.ashx states "For instance, if using HTTP and OneConnect, you could change CLIENT_ACCEPTED to HTTP_REQUEST" We've had to change ours to HTTP_REQUEST due to some OneConnect issues we were having that has since beeen resolved. This was recommeneded by F5 Support.

     

    But, my main concern is how to assign different SNAT IPs based on the pool member selected. So I am hoping this modified iRule works?

     

    ********

     

    when RULE_INIT {

     

    set static::snat_ips(0) 10.1.1.138

     

    set static::snat_ips(1) 10.1.1.139

     

    set static::snat_ips(2) 10.1.1.140

     

    set static::snat_ips(3) 10.1.1.141

     

    set static::snat_ips(4) 10.1.1.142

     

    set static::snat_ips(5) 10.1.1.143

     

    set static::NEW_snat_ips(0) 10.2.2.225

     

    set static::NEW_snat_ips(1) 10.2.2.226

     

    set static::NEW_snat_ips(2) 10.2.2.227

     

    set static::NEW_snat_ips(3) 10.2.2.228

     

    set static::NEW_snat_ips(4) 10.2.2.229

     

    set static::NEW_snat_ips(5) 10.2.2.230

     

    }

     

    when HTTP_REQUEST {

     

    if {

     

    [$IP::addr [LB::server addr] starts_with '10.1.1']}

     

    {

     

    snat $static::snat_ips(expr {[crc32 [IP::client_addr]] % [array size static::snat_ips]})

     

    }

     

    else {

     

    snat $static::NEW_snat_ips(expr {[crc32 [IP::client_addr]] % [array size static::snat_ips]})

     

    }

     

    }

     

    ********

     

  • sorry i did not say clearly. actually, what i meant is LB::server addr commamnd. i understand it may return null in HTTP_REQUEST event because pool member has not yet been determined in that event.

    e.g.

    [root@ve10:Active] config  b rule myrule list
    rule myrule {
       when HTTP_REQUEST {
      log local0. ""
      log local0. "client [IP::client_addr]:[TCP::client_port] server [LB::server addr]"
    }
    when LB_SELECTED {
      log local0. "client [IP::client_addr]:[TCP::client_port] server [LB::server addr]"
    }
    when HTTP_RESPONSE {
      log local0. "conn [IP::client_addr]:[TCP::client_port] > [clientside {IP::local_addr}]:[clientside {TCP::local_port}] > [IP::remote_addr]:[TCP::remote_port]"
    }
    }
    
    [root@ve10:Active] config  tail -f /var/log/ltm
    Mar  8 08:39:13 local/tmm info tmm[22185]: Rule myrule :
    Mar  8 08:39:13 local/tmm info tmm[22185]: Rule myrule : client 172.28.19.251:42612 server
    Mar  8 08:39:13 local/tmm info tmm[22185]: Rule myrule : client 172.28.19.251:42612 server 200.200.200.111
    Mar  8 08:39:13 local/tmm info tmm[22185]: Rule myrule : conn 172.28.19.251:42612 > 172.28.19.252:80 > 200.200.200.111:80
    Mar  8 08:39:14 local/tmm info tmm[22185]: Rule myrule :
    Mar  8 08:39:14 local/tmm info tmm[22185]: Rule myrule : client 172.28.19.251:42613 server
    Mar  8 08:39:14 local/tmm info tmm[22185]: Rule myrule : client 172.28.19.251:42613 server 200.200.200.101
    Mar  8 08:39:14 local/tmm info tmm[22185]: Rule myrule : conn 172.28.19.251:42613 > 172.28.19.252:80 > 200.200.200.101:80