Forum Discussion

lboogie25_20449's avatar
lboogie25_20449
Icon for Nimbostratus rankNimbostratus
Feb 17, 2016

VIP with multiple pools and TCP ports

Hello, all. I'm hoping to configure a single VIP to serve multiple pools. I'm using data groups to separate the port objects (not sure if I did that right). Here is my config, with the data groups first.

  1. Name - App901 address record 1.1.1.1:=901
  2. name - App902 address record 1.1.1.1:=902
  3. name - App903 address record 1.1.1.1:=903

    when CLIENT_ACCEPTED {
    if {[class match [TCP::local_port] equals App901]}
     {
    pool pl_901
    } elseif {[class match [TCP::local_port] equals App902]}
    {
    pool pl_902
    }
     elseif {[class match [TCP::local_port] equals App903]}
    {
    pool pl_903
    } else {
    reject
    }
    }
    

7 Replies

  • There's no need to do this. You can simply create three different Virtual Servers pointing to different pools. A Virtual Server includes a Virtual IP, port and protocol. Something like this:

     tmsh create ltm virtual vs-901 destination 1.1.1.1:901 ip-protocol tcp mask 255.255.255.255 pool pl_901 profiles add { tcp { } } source 0.0.0.0/0
     tmsh create ltm virtual vs-902 destination 1.1.1.1:902 ip-protocol tcp mask 255.255.255.255 pool pl_902 profiles add { tcp { } } source 0.0.0.0/0
     tmsh create ltm virtual vs-903 destination 1.1.1.1:903 ip-protocol tcp mask 255.255.255.255 pool pl_903 profiles add { tcp { } } source 0.0.0.0/0
    
  • Vernon, thanks for your input. The reason I'm approaching it this way is this is an implementation that's going to scale to a few hundred ports. I'm thinking it would be more of a headache to create a few hundred vservers than to just create the pools and have the iRule direct traffic. Will my implementation parse properly?

     

  • It seems inefficient to me, but if you must use an iRule, I would probably use a switch statement. Since it's a simple mapping, I'm not sure I would feel the need for a data group.

    when CLIENT_ACCEPTED {
        switch [TCP::local_port] {
            "901" { pool pl_901 }
            "902" { pool pl_902 } 
            "903" { pool pl_903 } 
            "904" { pool pl_904 } 
            "905" { pool pl_905 }
            }
    }
    

    I would also wonder if there is a need for separate pools. If the VS uses the ANY port and the pool members are all the same between ports and use the same port as the VS, just use the ANY port on the pool and let it carry over.

    • lboogie25_20449's avatar
      lboogie25_20449
      Icon for Nimbostratus rankNimbostratus
      Josh, you're saying it would be more efficient to create the couple of hundred vservers? Can you elaborate?
  • It seems inefficient to me, but if you must use an iRule, I would probably use a switch statement. Since it's a simple mapping, I'm not sure I would feel the need for a data group.

    when CLIENT_ACCEPTED {
        switch [TCP::local_port] {
            "901" { pool pl_901 }
            "902" { pool pl_902 } 
            "903" { pool pl_903 } 
            "904" { pool pl_904 } 
            "905" { pool pl_905 }
            }
    }
    

    I would also wonder if there is a need for separate pools. If the VS uses the ANY port and the pool members are all the same between ports and use the same port as the VS, just use the ANY port on the pool and let it carry over.

    • lboogie25_20449's avatar
      lboogie25_20449
      Icon for Nimbostratus rankNimbostratus
      Josh, you're saying it would be more efficient to create the couple of hundred vservers? Can you elaborate?
  • The use of an iRule will be non-trivially slower than using separate Virtual Servers. Incidentally, if the pools all contain the same set of nodes and differ only by listening port, you could define a single Virtual Server and single pool, where all members (and the VS) use the wildcard port, and disable port translation.

    Having said that, the use of a data-group will be faster than a

    switch
    . I'm assuming that there is a single VS IP address, but multiple pools. In that case, the best structure for the data-group is:

     create ltm data-group internal dg-port-match type string records add \
        { 901 { data pool_901 } \
          902 { data pool_902 } \
          903 { data pool_903 } \
          ... }
    

    In other words, the key is the VS port and the value is the pool. Then, the iRule is:

    when CLIENT_ACCEPTED {
        set p [class lookup [TCP::local_port] dg-port-match]
        
        if { $p ne "" } {
            pool $p
        }
        else {
            log local0.warn "Invalid port connect attempt; port = ([TCP::local_port])"
            reject
        }
    }
    

    Strictly speaking, if no default pool is associated with the VS and it is of Standard or FastL4 type, the reject is implicit, so you can skip that if you don't wish to log (and, of course, it makes more sense to use High-Speed Logging rather than local logging for production).