Forum Discussion

rjordan's avatar
rjordan
Icon for Nimbostratus rankNimbostratus
May 04, 2011

Stop processing iRule if condition is met?

I have an existing iRule that directs traffic to various pools based on the host name. It was requested that connections from specific source IPs be directed to specific nodes. I added this functionality in the CLIENT_ACCEPTED event in the iRule but the node decision seems to be "overridden" during the HTTP_REQUEST event. Is there a way to stop processing the rule in my IF statement? Or should move the IF statement into the HTTP_REQUEST?

 

 

Below is a simplified version of the iRule. Please excuse minor syntax issues, I just wrote it so you can see the basic functionality and flow.

 

 

when CLIENT_ACCEPTED {

 

if { [IP::client_addr] equals 1.2.3.4 } {

 

node 192.168.10.10 80

 

}

 

}

 

when HTTP_REQUEST {

 

if { [HTTP::host] contains domain1.com {

 

pool domain1.com_pool

 

}

 

elseif { [HTTP::host] contains domain2.com {

 

pool domain2.com_pool

 

}

 

else {

 

pool domain.com_pool

 

}

 

}

 

 

 

9 Replies

  • I also tried the rule below but it behaves the same way. I need any request from 1.2.3.4 to direct to 192.168.10.10 80, regardless of the hostname. Instead, it is directing the request to one of the pools.

    
    when HTTP_REQUEST {  
       if { [IP::remote_addr] equals 1.2.3.4 } {
          node 192.168.10.10 80
       }     
       if { HTTP::host contains "domain1.com" } {
          pool domain1.com_pool
       }           
       elseif {HTTP::host contains "domain2.com" } {
          pool domain2.com_pool
       }
       else {
          pool domain.com_pool
       }
    }
     
  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    Try this:

    
    
    when CLIENT_ACCEPTED {
      set httpfunctions 1
      if { [IP::client_addr] equals 1.2.3.4 } {
        node 192.168.10.10 80
        unset httpfunctions
      }
    }
    
    when HTTP_REQUEST {
      if { [info exists httpfunctions]} {
        if { [HTTP::host] contains domain1.com {
          pool domain1.com_pool
        }
        elseif { [HTTP::host] contains domain2.com {
          pool domain2.com_pool
        }
        else {
          pool domain.com_pool
        }
      }
    }
     

    Basically you want to do an event disable, but only for the context of this iRule, not all the HTTP_REQUEST events in all the iRules. So this should get you there.

    Colin
  • Hey Colin,

    Your example does work but it is a bit more complex than I thought I needed. I saw in the documentation that if multiple conditions are met, the last pool specified will be used. For some odd reason, I thought that node command would be handled differently. In any case, I just moved the new IF statement below my hostname stuff and it works. Below is what I'm using.

     
    when HTTP_REQUEST {  
       if { HTTP::host contains "domain1.com" } {
          pool domain1.com_pool
       }           
       elseif {HTTP::host contains "domain2.com" } {
          pool domain2.com_pool
       }
       elseif { [IP::remote_addr] equals 1.2.3.4 } {
          node 192.168.10.10 80
       }     
       else {
          pool domain.com_pool
       }
    }
    
  • This seems like one of these should work. Will need syntax correction most likely

    The third one is probably the best one, since the return will mean that its only checked during tcp setup, no need to check every GET/POST request, but it won't hurt on an underutilized LTM.

    Return works well for stopping processing of the current irule, and its nice that if there are multiple irules assocated to a VS, the return only exits execution of the current irule, so other irules still execute

    Maybe there is an issue using 'return' after a node call, assumption is not, since clearly the original rule is continuing to apply even after tcp setup for subsequent GET/POST requests?

    Hope this helps

    
    when HTTP_REQUEST {  
       if { [IP::remote_addr] equals 1.2.3.4 } {
          node 192.168.10.10 80
          return
       }     
       if { HTTP::host contains "domain1.com" } {
          pool domain1.com_pool
       }           
       elseif {HTTP::host contains "domain2.com" } {
          pool domain2.com_pool
       }
       else {
          pool domain.com_pool
       }
    }
     

    or this

    
    when HTTP_REQUEST {  
       if { [IP::remote_addr] equals 1.2.3.4 } {
          node 192.168.10.10 80
       } else {     
          if { HTTP::host contains "domain1.com" } {
             pool domain1.com_pool
          } elseif {HTTP::host contains "domain2.com" } {
             pool domain2.com_pool
          } else {
             pool domain.com_pool
          }
       }
    }
      

    this is the closest to the original

    
    when CLIENT_ACCEPTED {
      if { [IP::client_addr] equals 1.2.3.4 } {
        node 192.168.10.10 80
        return
      }
    }
    when HTTP_REQUEST {
      if { [HTTP::host] contains domain1.com {
        pool domain1.com_pool
      }
      elseif { [HTTP::host] contains domain2.com {
        pool domain2.com_pool
      }
      else {
        pool domain.com_pool
      }
    }
     
  • Yeah, I think return should do the trick. I will probably use this in other iRules where I can't simply manipulate the order of the statements. For now, my current iRule is working properly. I would estimate only .01% of the requests actually match the IP, so I don't expect much more load than doing it in CLIENT_ACCEPTED. Thanks Colin and Matt for all the suggestions.
  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    I was just trying to keep the node command up in the CLIENT_ACCEPTED event where you put it originally. If you're okay with moving it to the end of the if/else chain, then that's definitely the simplest solution.

     

     

    Just keep in mind that it doesn't take priority this way. Since it's in an if/else chain, it only gets fired if one of the conditions above it are not met. What I mean is, in my example if you get a request from 1.2.3.4 to domain1.com, it will get directed to the particular node as you desired. In your example, it will get sent to the pool that all other domain1.com requests are sent to.

     

     

    Colin
  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    As far as the return command, that will probably work but I'd want to test it to be sure it kicks you all the way out of the iRule every time, not just out of the CLIENT_ACCEPTED event.

     

     

    Like I said, it should work, I just like to use more explicit statements usually. ;)

     

     

    Colin
  • return will only exit the current event in the current rule. If you want to prevent all subsequent iRule events from any iRule on the virtual server from running, you can use 'event disable all'. Or if you want to do it just for select code in this or another rule on the same virtual server, you could set a variable in CLIENT_ACCEPTED and then check the value in subsequent code before running it.

     

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/return

     

    http://devcentral.f5.com/wiki/default.aspx/iRules/event

     

     

    Aaron
  • Colin_Walker_12's avatar
    Colin_Walker_12
    Historic F5 Account
    See, I knew I was leery for a reason, I just couldn't recall (since I rarely use return) and didn't get to testing it yet (whee conference calls!).

     

     

    Thanks for the info Aaron, now I don't feel dumb for forgetting about return as an option here...since it's not. ;)

     

     

    Colin