For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

Forum Discussion

Chris_R_123579's avatar
Chris_R_123579
Icon for Nimbostratus rankNimbostratus
Apr 04, 2013

variable getting reset during irule execution

'll try to be as descriptive as I can since I'm not well trained in our F5 load balancers ways. Basically I have an iRule that looks something like this(pseudocode):

when HTTP_REQUEST { 
set host_num 0
if uri contains /serv prefix
       set host_num=(digit after /serv) 

}

when LB_SELECTED {
    if { $host_num != 0 } {
            reselect the appropriate pool member that corresponds to the host_num
    }
}

My problem is that my host_num variable is lost between when I set it in HTTP_REQUEST and when I actually need it in the LB_SELECTED event.

This system worked flawlessly for years. Until a few days ago when I tried to add another irule that forced all http traffic to be http 1.0 instead of 1.1. I've removed this irule, but this problem still remains. Is there a setting in the HTTP profile that I'm missing? I've checked my other irules and none of them have a host_num variable that could be overwriting this, so what could be happening?

10 Replies

  • nathe's avatar
    nathe
    Icon for Cirrocumulus rankCirrocumulus
    Chris,

     

     

    I'm far from an expert at variables in iRules so my only suggestion would be creating a global variable, rather than a local variable.

     

     

    See this article about global variables: https://devcentral.f5.com/tech-tips/articles/irules-101-03-variables.UV2gXzd5g08

     

     

    So, in your example it would be something like: "set ::host_num=(digit after /serv)" and then referenced thus: "if { $::host_num != 0 }"

     

     

    Hope this helps,

     

    N
  • A global variable would be global to the whole box (ie. everyone), so that wouldn't work. Are you saying that the check for $host_num in the LB_SELECTED event fails? Does it crash the iRule?

    Try this to test and please report the results:

    
    when HTTP_REQUEST {
    log local0. "here"
    set host_num 0
    }
    when LB_SELECTED {
    log local0. "here"
    if { [info exists host_num] } {
    log local0. "host_num exists"
    } else {
    log local0. "host_num does not exist"
    }
    }
    
  • I used your test code and host_num does exist. I don't ever see a host_num does not exist in my logs.

     

     

    But my problem occurs in my irule like so:

     

     when HTTP_REQUEST { 
    log local0. "here" 
    set host_num 0 
    if { [string tolower $uri] starts_with "/serv" } { 
          log local0. "prefix redirect initiated" 
          if { [string tolower $uri] matches_regex {serv[\d]+} } { 
                   scan $uri /serv%d host_num 
                   set path "/" 
                   log local0. "uri match found $host_num" 
          } else { 
                   scan $uri /serv%d%s host_num path 
                   log local0. "uri match not found assert $host_num" 
          } 
          HTTP::uri $path 
    } 
    
    when LB_SELECTED { 
    log local0. "LB here" 
    if { $host_num != 0 } {
        redirect the request to the appropriate member 
               switch $host_num { 
                        1 {
                              LB::reselect pool SERV member 10.10.10.2 
                              log local0. "prefix redirect selecting /serv1" 
                            }
     } } 

     

     

     

    My problem occurs when LB_SELECTED executes. For some reason $host_num is always being reset to 0.

     

     

    It's almost like any user who tries to use the prefix redirect to select a specific server, will get the host_num variable set, but before the LB_SELECT function executes the session/connection is cleared and they get host_num = 0 or something.

     

     

    Any ideas?

     

     

  • I'm a little curious about your if conditional:

    if { [string tolower $uri] matches_regex {serv[\d]+} } {

    You're saying that if there's a number after the /serv URI, set the host_name and the path. But then in the else condition, you have this: scan $uri /serv%d%s host_num path. This assumes there's a number after the /serv URI, followed by a path. I would think that host_num wouldn't be set in this condition, considering the /serv URI doesn't have a number after it.

    Can you try this minor variation:

    
    when HTTP_REQUEST {
    log local0. "here"
    set host_num 0
    set path "/"
    if { [string tolower [HTTP::uri]] starts_with "/serv" } {
    log local0. "prefix redirect initiated"
    if { [string tolower [HTTP::uri]] matches_regex {serv[\d]+} } {
    scan [string tolower [HTTP::uri]] /serv%d%s host_num path
    log local0. "uri match found: $host_num"
    } else {
    scan [string tolower [HTTP::uri]] /serv%s path
    }
    log local0. "path = $path"
    HTTP::uri $path
    }
    }
    when LB_SELECTED {
    log local0. "here"
    if { [info exists host_num] } {
    log local0. "host_num exists: $host_num"
    if { $host_num != 0 } {
    switch $host_num {
    1 {
    LB::reselect pool local-pool member 10.70.0.2
    log local0. "prefix redirect selecting /serv1"
    }
    }
    }
    } else {
    log local0. "host_num does not exist"
    }
    }
    
  • Thanks for the response. I made the changes and every time it checks for host_num existance in the LB_SELECTED event, hust_num is 0.

     

     

    I get the following in my logs on one request to example.com/serv1

     

    Thu Apr 4 16:15:42 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0

     

    Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0

     

    Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0

     

    Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0

     

    Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0

     

    Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : host_num exists: 0

     

    Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : path = /

     

    Thu Apr 4 16:15:41 EDT 2013 Rule clewdev-new-prefix-redirect : uri match found: 2

     

     

    Like I said, this irule worked flawlessly for 4 or 5 years and then one day I threw in a new iRule that had some chunking/http1.0 changes(which has been removed for over a week) and its been messed up since then.

     

     

    Thanks again

     

  • Can you share your entire iRule?

     

     

    Have you or can you reboot the BIG-IP (or do a bigstart restart)?
  • Here is the entire rule with IP's changed etc. But this is the meat of it.

    
    when HTTP_REQUEST { 
    set uri [HTTP::uri]
    set host_num 0
    set req_cookie [HTTP::cookie "DEVPERSIST"]
    
    if { [string tolower $uri] starts_with "/serv" } {
    
    
    if { [string tolower $uri] matches_regex {serv[\d]+} } {
    scan $uri /serv%d host_num
    set path "/"
    } else {
    scan $uri /serv%d%s host_num path
    }
    
    snip the host prefix from the URI
    HTTP::uri $path
                    
    
    
    remove the cookie if it's there
    if { [HTTP::cookie exists DEVPERSIST] } {
    HTTP::cookie remove DEVPERSIST
    }
                    
                  
    
    }
    }
    
    when LB_SELECTED {
    if { $host_num != 0 } {
                    log local0. "hostnum here $host_num"
    redirect the request to the appropriate member
    switch $host_num {
    1 {
    LB::reselect pool DEV member 10.10.10.2:7085
    }
    
    2 {
    LB::reselect pool DEV member 10.10.10.3:8080
    }
    
    }
    }
    }
    
    when HTTP_RESPONSE {
    if { $host_num != 0 } {
    HTTP::header insert Set-Cookie "DEVPERSIST=[HTTP::cookie DEVPERSIST]; Path=/"
                log local0. "hostnum here $host_num"
    }
    }
    
    

    I haven't rebooted the F5 yet since it serves about 30 different high usage web applications. But I can talk to our sys admins about doing so at some point.
  • Fundamentally I don't see anything wrong with the logic. I'm still curious about your else condition though, given that there won't be a number after /serv if this condition is met. I would recommend a bigstart restart on the assumption that NOTHING else has changed other than applying and then removing some iRule logic.

    Can you also try this variation of your rule:

    
    when HTTP_REQUEST { 
    set host_num 0
    set req_cookie [HTTP::cookie "DEVPERSIST"]
    set path "/"
    if { [string tolower [HTTP::uri]] starts_with "/serv" } {
    log local0. "starts with /serv"
    if { [string tolower [HTTP::uri]] matches_regex {/serv[\d]+} } {
    log local0. "match_regex"
    scan [string tolower [HTTP::uri]] /serv%d%s host_num path
    log local0. "host_num = $host_num"
    log local0. "path = $path"
    } else {
    log local0. "not match_regex"
    scan [string tolower [HTTP::uri]] /serv%s path
    log local0. "path = $path"
    }
    snip the host prefix from the URI
    HTTP::uri $path
    remove the cookie if it's there
    if { [HTTP::cookie exists DEVPERSIST] } {
    HTTP::cookie remove DEVPERSIST
    }
    }
    }
    when LB_SELECTED {
    if { $host_num != 0 } {
    log local0. "hostnum here $host_num"
    redirect the request to the appropriate member
    switch $host_num {
    1 {
    log local0. "selecting member 1"
    LB::reselect pool DEV member 10.10.10.2:7085
    }
    2 {
    log local0. "selecting member 2"
    LB::reselect pool DEV member 10.10.10.3:8080
    }
    }
    } else {
    log local0. "hostnum = 0"
    }
    }
    when HTTP_RESPONSE {
    if { $host_num != 0 } {
    HTTP::header insert Set-Cookie "DEVPERSIST=[HTTP::cookie DEVPERSIST]; Path=/"
    log local0. "hostnum here $host_num"
    } else {
    log local0. "hostnum = 0"
    }
    
    
  • Thanks Kevin. I've scheduled a restart for Monday, so hopefully that solves it.

     

     

    I'm not sure what that else logic is for either. The irule was written by my predecessor.
  • nathe's avatar
    nathe
    Icon for Cirrocumulus rankCirrocumulus
    Kevin "A global variable would be global to the whole box (ie. everyone), so that wouldn't work." - doh! I missed that key point about global variables. Back to the Variables 101 guide me thinks. Thanks

     

     

    N