Forum Discussion

aj1's avatar
aj1
Icon for Nimbostratus rankNimbostratus
Feb 27, 2015

Selective SNAT using iRule on a standard VS

Hi,

I realize this issue has been addressed in a lot of posts and i have applied those to solve this issue but nothing has worked out so far. Our LTM services two vlans and applications from these vlans talk to each other a lot. Most of them are round-robin and so approx. 50% of the connections are successful and the rest of them are resets (since they end up bypassing the LTM on their return path) We used iRules and a snat pool to selectively SNAT such apps and haven't had any issues since. Although, i would like to create a generic rule for such apps. This rule would SNAT a client request only when the client and the server are in the same vlan. Something like this:

when CLIENT_ACCEPTED {
    set default_pool [LB::server pool]
    log local0. "default pool = $default_pool"

    if {client is in vlanA AND server is in vlanA} {
        snatpool snat_pool
    }
    elseif {client is in vlanB AND server is in vlanB} {
        snatpool snat_pool
    }
    else {
        pool $default_pool
    }
}

I would like to know if this is possible using only the CLIENT_ACCEPTED event. Also, in the app specific rules used so far, the "pool $default_pool" part doesn't work out well. Only when i explicitly specify the name of the default pool, things work. For example the following works:

when CLIENT_ACCEPTED {
    if {[class match -- [IP::client_addr] equals some_hosts]} {
        snatpool snat_pool
    }
    elseif {[class match -- [IP::client_addr] equals some_networks]} {
        pool vs_default_pool
    }
    else {
        pool vs_default_pool
    }
}

But this doesn't:

when CLIENT_ACCEPTED {
    set default_pool [LB::server pool]
    log local0. "default pool = $default_pool"

    if {[class match -- [IP::client_addr] equals some_hosts]} {
        snatpool snat_pool
    }
    elseif {[class match -- [IP::client_addr] equals some_networks]} {
        pool $default_pool
    }
    else {
        pool $default_pool
    }
}

I have also tried Kevin's answer to https://devcentral.f5.com/questions/default-pool-question But that hasn't worked out either. Not sure what is problem is here but i kinda need this to work in order to have a generic iRule for selective SNAT.

TIA !

8 Replies

  • I really think you want to use the

    when LB_SELECTED {
    event in order for the evaluation of the pool member's IP address to work instead of
    when CLIENT_ACCEPTED {
    .

    This allows the LTM to do it's job with health monitors and such in order to ensure a clean result without forcing a pool member selection.

    I could be wrong on this, but that is what I think you are looking for?
    • aj1's avatar
      aj1
      Icon for Nimbostratus rankNimbostratus
      Thanks Brian, i'll do that.
  • Hi aj,

    Brian is right. And I would swear to have seen a solution for this.

    Anyway, here are two alternatives.

    In case your whole networks is using equal length subnets the following one should work i.e. for all networks are 26 bit (255.255.255.192):

    when RULE_INIT {
        set static::network_mask 255.255.255.192
    }
    
    when LB_SELECTED {
        log local0. "client network: [IP::addr [clientside {IP::remote_addr}] mask $static::network_mask] ([clientside {IP::remote_addr}])"
        log local0. "client network: [IP::addr [LB::server addr] mask $static::network_mask] ([LB::server addr])"
        if { [IP::addr [clientside {IP::remote_addr}] mask $static::network_mask] equals [IP::addr [LB::server addr] mask $static::network_mask] } {
            log local0. "client and server in same network: apply snat"
            snat automap
        } else {
            log local0. "client and server in different networks do not snat"
            snat none
        }
    }
    

    In case your network ranges are varying I would use a data-group based approach. It´s of type IP and may contain different lengths subnets (added an "empty" value to avoid related issues but it is not required):

    ltm data-group internal datagroup_local_networks {
        records {
            10.131.131.0/26 {
                data empty
            }
            10.131.131.64/26 {
                data empty
            }
            10.131.131.128/26 {
                data empty
            }
            10.131.131.192/26 {
                data empty
            }
        }
        type ip
    }
    

    The following iRule is using the data-group to compare the network range of client and pool member.

    when LB_SELECTED {
        log local0. "[class match -name -- [clientside {IP::remote_addr}] equals datagroup_local_networks] for [clientside {IP::remote_addr}]"
        log local0. "[class match -name -- [LB::server addr] equals datagroup_local_networks] for [LB::server addr]"
        if { [class match -name -- [clientside {IP::remote_addr}] equals datagroup_local_networks] equals [class match -name -- [LB::server addr] equals datagroup_local_networks] } {
            log local0. "client and server in same network, apply snat"
            snat automap
        } else {
            log local0. "client and server in different networks, do not snat"
            snat none
        }
    }
    

    Things are bit more difficult with routing domains. Not covered by this solution.

    Thanks, Stephan

    PS: Modified (2015-03-03) to override default SNAT configurations by using "snat none" for specific condition.
  • aj1's avatar
    aj1
    Icon for Nimbostratus rankNimbostratus

    Stephan, had a chance to test the rule. It looks like connections on the same vlans are getting snat’d although connections between service nodes in different vlans are getting snat’d too, and we would like to avoid that since LTM is the gateway for all these vlans. Below are some logs and connection table entries.

    iRule:

    when CLIENT_ACCEPTED {
        set default_pool [LB::server pool]
        log local0. "default pool = $default_pool"
    }
    
    when LB_SELECTED {
        log local0. "Client is [clientside {IP::remote_addr}]"
        log local0. "Server is [LB::server addr]"
    
    if {[class match -name -- [clientside {IP::remote_addr}] equals vlanX] equals [class match -name -- [LB::server addr] equals vlanX]} {
        log local0. "client and server in SAME network, apply snat"
        snatpool snat_pool
    }
    elseif {[class match -name -- [clientside {IP::remote_addr}] equals vlanY] equals [class match -name -- [LB::server addr] equals vlanY]} {
        log local0. "client and server in SAME network, apply snat"
        snatpool snat_pool
    }
    else {
        log local0. "client and server in DIFFERENT networks, do not snat"
        pool $default_pool
    }
    }
    

    Data groups:

    ltm data-group internal vlanX {
    records {
        172.16.18.0/24 { }
    }
    type ip
    }
    
    ltm data-group internal vlanY {
    records {
        172.16.19.0/24 { }
    }
    type ip
    }
    

    logs:

    All three log entries are from a client and server in different vlans. I never see an entry for a client and a server in the same vlan, but i do see that record in the connection table getting snat'd.

    Mar  3 11:04:57 slot1/isb-alb-c1 info tmm[10994]: Rule /Common/snat_same_vlan : default pool = test_pool
    Mar  3 11:04:57 slot1/isb-alb-c1 info tmm[10994]: Rule /Common/snat_same_vlan : Client is 172.16.19.12
    Mar  3 11:04:57 slot1/isb-alb-c1 info tmm[10994]: Rule /Common/snat_same_vlan : Server is 172.16.18.24
    Mar  3 11:04:57 slot1/isb-alb-c1 info tmm[10994]: Rule /Common/snat_same_vlan : client and server in SAME network, apply snat
    
    Mar  3 11:05:00 slot1/isb-alb-c1 info tmm3[10994]: Rule /Common/snat_same_vlan : default pool = test_pool
    Mar  3 11:05:00 slot1/isb-alb-c1 info tmm3[10994]: Rule /Common/snat_same_vlan : Client is 172.16.19.12
    Mar  3 11:05:00 slot1/isb-alb-c1 info tmm3[10994]: Rule /Common/snat_same_vlan : Server is 172.16.18.24
    Mar  3 11:05:00 slot1/isb-alb-c1 info tmm3[10994]: Rule /Common/snat_same_vlan : client and server in SAME network, apply snat
    
    Mar  3 11:05:04 slot1/isb-alb-c1 info tmm2[10994]: Rule /Common/snat_same_vlan : default pool = test_pool
    Mar  3 11:05:04 slot1/isb-alb-c1 info tmm2[10994]: Rule /Common/snat_same_vlan : Client is 125.171.11.108
    Mar  3 11:05:04 slot1/isb-alb-c1 info tmm2[10994]: Rule /Common/snat_same_vlan : Server is 172.16.18.24
    Mar  3 11:05:04 slot1/isb-alb-c1 info tmm2[10994]: Rule /Common/snat_same_vlan : client and server in SAME network, apply snat
    

    In the connection table itself, don’t see any snat going on for 125.171.11.108 client though and the logs seem to suggest otherwise !

    show /sys connection cs-client-addr 125.171.11.108
    Sys::Connections
    125.171.11.108:41521  198.82.183.114:389  125.171.11.108:41521  172.16.18.24:10389  tcp  1375      (slot/tmm: 1/0)  none
    

    These are in the same vlan, and a snat is expected here.

    show /sys connection cs-client-addr 172.16.18.12 ss-server-addr 172.16.18.24
    Sys::Connections
    172.16.18.12:58409  198.82.183.114:389  196.81.215.116:58409  172.16.18.24:10389  tcp  17   (slot/tmm: 1/0)  none
    

    Not in the same vlan, but a snat still happens.

    show /sys connection cs-client-addr 172.16.18.12 ss-server-addr 172.16.19.24
    Sys::Connections
    172.16.18.12:58409  198.82.183.114:389  196.81.215.118:58409  172.16.19.24:10389  tcp  17   (slot/tmm: 1/0)  none
    
    • Hi aj, I assume, there is a default snat configured on your system. You can check it with the following command: tmsh list ltm snat To override it, we can use a "snat none" in the iRule and I changed just it in the sample code above for both iRules. Please let me know, if this works for you. Thanks, Stephan
  • aj1's avatar
    aj1
    Icon for Nimbostratus rankNimbostratus

    Thank you for the reply.I do have a wildcard forwarding server that uses the snat pool, not sure how that affects this.

    [admin@isb-alb-c1:/S1-green-P:Active:Standalone] ~  tmsh list /ltm snat
    [admin@isb-alb-c1:/S1-green-P:Active:Standalone] ~  
    

    Used "snat none" in the rule instead of the "pool $default_pool" statement. Still seeing snat happening either way though, same subnet or not. The same logs as before. Can verify the same from the connection table.

    Something that was different this time were the connection table records for the 125.171.11.108 client. No snat in the first record (expected), but snat in the second record.

    show /sys connection cs-client-addr 125.171.11.108
    Sys::Connections
    125.171.11.108:41521  198.82.183.114:389  125.171.11.108:41521  172.16.18.24:10389  tcp  1198  (slot/tmm: 1/0)  none
    125.171.11.108:43228  198.82.183.114:389  198.82.214.125:43228  172.16.19.24:10389  tcp  992  (slot/tmm: 1/1)  none
    Total records returned: 2
    
    • Hi aj, it will not be necessary to have multiple data-groups. You can put all network ranges into a single data-group and please make sure to include all client networks (currently the 125.171.11.0/24 is not covered). This might cause the problem. Thanks, Stephan
    • aj1's avatar
      aj1
      Icon for Nimbostratus rankNimbostratus
      Yes, having every subnet in just one data-group worked ! I guess i had a different idea as to how the irule works and therefore split the two subnets into two data-groups. Thank you Stephan.