Forum Discussion

Simon_Knox_1115's avatar
Simon_Knox_1115
Icon for Nimbostratus rankNimbostratus
Jul 08, 2005

HELP! hanging iRule

Hi,

I've recently converted from 4.5 to 9.05 and converted my iRules, using OTCU then tweaking so they are correct (at least what I though was correct).

When connecting to a web site, the rule basically connects you to a different pool depending on the port that the client web browser uses.

My old rule (below) worked:

 
 if (server_port == 80) { 
    use pool wwwDEFAULT 
 } 
 else if (server_port == 8001) { 
    use pool node-10.128.32.1 
 } 
 else if (server_port == 8099) { 
    use pool node-10.128.32.2 
 } 
 else if (server_port == 8003) { 
    use pool node-10.128.32.3 
 } 
 else if (server_port == 8004) { 
    use pool node-10.128.32.4 
 } 
 else if (server_port == 8005) { 
    use pool node-10.128.32.5 
 } 
 else if (server_port == 8006) { 
    use pool node-10.128.32.6 
 } 
 else if (server_port == 8007) { 
    use pool node-10.128.32.7 
 } 
 else if (server_port == 8008) { 
    use pool node-10.128.32.8 
 } 
 else if (not (server_port == 80 or not (server_port == 8001 or 
       not (server_port == 8099 or not (server_port == 8003 or 
       not (server_port == 8004 or not (server_port == 8005 or 
       not (server_port == 8006 or not (server_port == 8007 or 
       not (server_port == 8008)))))))))) { 
      redirect to "http://www.vetsite.net" 
 } 
 else { 
    discard 
 } 
 

The converted one doesn't seem to

 
 when HTTP_REQUEST { 
    if { [TCP::client_port] == "80"  } { 
       persist source_addr 1800 
       HTTP::fallback http://support.blackwellpublishing.com 
       pool wwwDEFAULT 
    } 
    elseif { [TCP::client_port] == "8001"  } { 
       pool node-10.128.32.1 
    } 
    elseif { [TCP::client_port] == "8099"  } { 
       pool node-10.128.32.2 
    } 
    elseif { [TCP::client_port] == "8003"  } { 
       pool node-10.128.32.3 
    } 
    elseif { [TCP::client_port] == "8004"  } { 
       pool node-10.128.32.4 
    } 
    elseif { [TCP::client_port] == "8005"  } { 
       pool node-10.128.32.5 
    } 
    elseif { [TCP::client_port] == "8006"  } { 
       pool node-10.128.32.6 
    } 
    elseif { [TCP::client_port] == "8007"  } { 
       pool node-10.128.32.7 
    } 
    elseif { [TCP::client_port] == "8008"  } { 
       pool node-10.128.32.8 
    } 
    elseif { not [TCP::client_port] == "80" or not [TCP::client_port] == "8001" or 
        not [TCP::client_port] == "8099" or not [TCP::client_port] == "8003" or 
        not [TCP::client_port] == "8004" or not [TCP::client_port] == "8005" or 
        not [TCP::client_port] == "8006" or not [TCP::client_port] == "8007" or 
        not [TCP::client_port] == "8008"  } { 
       HTTP::redirect "http://www.vetsite.net" 
    } 
    else { 
       discard 
    } 
 } 
 

When the web browser trys to connect to the web site that it is trying to view (on HTTP port 80) it says 'website found waiting for reply' and seems to spend an eternity waiting before timing out.

If I dump the rule and make the virtual server use pool wwwDEFAULT directly all is fine.

I can't see any problems that would cause this, am I going mad?

Cheers

4 Replies

  • I haven't tested any of this, but I would mention a couple things. You are using tcp::client_port where I think that is going to be the source port. You would want to use tcp::local_port which is the destination port.

    Also, you're doing when HTTP_Request when you should probably be using when CLIENT_ACCEPTED. This happens higher in the stack, so it should be more efficient.

    Something like this:

     
     when CLIENT_ACCEPTED { 
     if { [TCP::local_port] equals 531 } { 
     pool win2003 
     } elseif { [TCP::local_port] equals 25 } { 
     pool win2003 
     } else { 
     pool win2003 
     }} 
     
  • Try this (not tested!)

     
     class server_ports { 
       "8001 10.128.32.1" 
       "8099 10.128.32.2" 
       "8003 10.128.32.3" 
       "8004 10.128.32.4" 
       "8005 10.128.32.5" 
       "8006 10.128.32.6" 
       "8007 10.128.32.7" 
       "8008 10.128.32.8" 
     } 
      
     when CLIENT_ACCEPTED { 
       if { [TCP::local_port] eq "80" } { 
         persist uie [IP::client_addr] 1800 
         HTTP::fallback http://support.blackwellpublishing.com 
         pool wwwDEFAULT 
       } elseif { 
           set match [lindex [findclass [TCP::local_port] $::server_ports] 1] 
           pool node-$match 
       } 
     } 
     
  • unRuleY_95363's avatar
    unRuleY_95363
    Historic F5 Account
    Another thing worth noting is that the "not" operator is of higher precendence that it used to be in 4.x (basically 4.x did a better job of figuring out what you wanted to do, but because we are using Tcl now, we don't have that same flexibility with the precedence of the operators). So, make sure you add parenthesis around the expression that is the target of the not operator, as in:

      
     elseif { not ( [TCP::client_port] == "80" ) or not ( [TCP::client_port] == "8001" ) or 
            not ( [TCP::client_port] == "8099" ) or not ( [TCP::client_port] == "8003" ) or 
            not ( [TCP::client_port] == "8004" ) or not ( [TCP::client_port] == "8005" ) or 
            not ( [TCP::client_port] == "8006" ) or not ( [TCP::client_port] == "8007" ) or 
            not ( [TCP::client_port] == "8008" ) } {   
      

    I would also suggest using a class to help minimize the number of these tests as in:

      
      class server_ports {  
         80,  
         8001,  
         8099,  
         8003,  
         8004,  
         8005,  
         8006,  
         8007,  
         8008  
      }  
      

    and then modify your last elseif to be:

      
         elseif { not [matchclass [TCP::local_port] equals $::server_ports] } {  
      

    You can also use citizen_elah's example above which relies even more on the class (you may want to add a test of $match to make sure a match was found before do the "pool node-$match" though).

    Hope this all helps.

  • Thanks you for all your help, I'm getting there and had eveything working.

    I'm now trying to impliment citizen_elah's suggestion of replacing all of the:

     
     elseif { [TCP::client_port] == "8099" } { 
        pool node-10.128.32.2 
     } 
     

    with:

     
     } elseif { 
        set match [lindex [findclass [TCP::local_port] $::server_ports] 1] 
        pool node-$match 
     } 
     

    Which I couldn't get to work so had a stab at it from scratch like this:

     
     elseif { [lindex [matchclass [TCP::local_port] eq $::Individual_Servers] 1]} { 
        set match [lindex  $::Individual_Servers 1] 
        node $match 
     }   
     

    I'm having a few problems though and as I keep getting the following error:

    01070151:3: Rule [www.vetsite.net] error: line 21: [undefined procedure: elseif] [elseif { [lindex [matchclass [TCP::local_port] eq $::Individual_Servers] 1]} {

    set match [lindex $::Individual_Servers 1]

    node $match

    } ]

    I'm now very confused, can anyone point out where I'm going wrong?

    For reference my complete rule now looks like this:

     
     when CLIENT_ACCEPTED { 
        TCP::collect 5 
     } 
     when CLIENT_DATA { 
        if { [matchclass [TCP::payload] starts_with $::http_methods] } { 
           SSL::disable 
        } 
     } 
     when HTTP_REQUEST { 
        if { [TCP::local_port] eq "80"  } { 
           persist source_addr 1800 
           HTTP::fallback http://support.blackwellpublishing.com 
           pool wwwDEFAULT  
        } 
        elseif { [lindex [matchclass [TCP::local_port] eq $::Individual_Servers] 1]} { 
           set match [lindex  $::Individual_Servers 1] 
           node $match 
        } 
        elseif { not [matchclass [TCP::local_port] eq $::Server_Ports] } { 
           HTTP::redirect "http://www.vetsite.net" 
        } 
        else { 
           discard 
        } 
     } 
      
     class http_methods { 
        "GET" 
        "POST" 
        "HEAD" 
        "PUT" 
     } 
      
     class ServerPorts { 
        "80" 
        "8099" 
        "8003" 
        "8004" 
        "8005" 
        "8006" 
        "8007" 
        "8008" 
     } 
      
     class Individual_Servers { 
        "8001 10.128.32.1" 
        "8099 10.128.32.2" 
        "8003 10.128.32.3" 
        "8004 10.128.32.4" 
        "8005 10.128.32.5" 
        "8006 10.128.32.6" 
        "8007 10.128.32.7" 
        "8008 10.128.32.8" 
     }