Forum Discussion

smp_86112's avatar
smp_86112
Icon for Cirrostratus rankCirrostratus
May 04, 2010

v10 - local vs. global vars

Trying to wrap my mind around how this variable scope works. I have a simple iRule I'm testing with:

 

 

when HTTP_REQUEST {

 

global client_local [TCP::local_port clientside]

 

if {$::client_local == 443} {

 

set protocol "https"

 

} elseif {$::client_local == 80} {

 

set protocol "http"

 

}

 

log local0. "$protocol"

 

}

 

 

My intent was to initialize this "client_local" global var by placing on VIP1, then applying a logging statement on VIP2 to output the value of the "client_local" var to ensure I understand how this works. But I've tried different ways of defining and referencing the variable (such as "global client_local" and "set $::client_local" and also different ways of referencing the variable after it's been defined ("$client_local" and "$::client_local"), but I can't seem to find the right combination. Can you help me understand how to define and reference global varables please?

 

 

6 Replies

  • Hi SMP,

     

     

    global my_var, set ::my_var, and any variable set in RULE_INIT will be global and accessible across all connections to the VIP. If you want to set a variable which is only accessible for one TCP connection (from any iRule on the VIP), you can use a local variable.

     

     

    
    when CLIENT_ACCEPTED { 
       switch [TCP::local_port clientside] {
          443 {
             set protocol "https"
          }
          default {
             set protocol "http"
          }
       }
       log local0. "$protocol"
    }
    

     

     

    As the port can't change over the course of the TCP connection, I've moved your code to the CLIENT_ACCEPTED event so it only runs once per connection. You can then reference the $protocol variable in any iRule on the same VIP. If you're referencing the $protocol variable in other rules in the same event it's set in, make sure this iRule is placed before any other iRules on the VIP or explicitly set priority on this iRule so it runs before them.

     

     

    Aaron
  • Thanks for laying out the three different ways to define global variables. Let me narrow this down a bit - I can define a global variable, but how then do I reference it?

     

     

    global client_local [TCP::local_port clientside]

     

    if {$client_local == 443} {

     

    set protocol "https"

     

    }

     

     

     

    Results in:

     

    can't read "client_local": no such variable while executing "if {$client_local == 443} { set protocol "https" }"

     

     

    Is there a different syntax to reference a global variable?
  • I haven't used the TCL 'global' command before. Per the TCL wiki page on the command, I don't think it could be used in current versions of iRules as there is no support for procs in iRules as of now:

     

     

     

    http://www.tcl.tk/man/tcl8.4/TclCmd/global.htm

     

    This command has no effect unless executed in the context of a proc body.

     

     

     

    If you did want to declare a global variable, you could use 'set ::my_global_var' and then reference it using $::my_global_var. However, I don't think you want to use a global variable in the scenario you've described. If you want to set a variable for one client connection and access the variable later in the same iRule or in another iRule on the same VIP, you could use a local variable. Using a global variable means that all client connections will reference the same variable. If one HTTPS connection was established and then another client established an HTTP connection, the HTTP connection would set the global variable to "http" for itself and any prior requests that were still established.

     

     

    See this post for some additional info:

     

     

    http://devcentral.f5.com/Default.aspx?tabid=53&view=topic&postid=85746&ptarget=85747

     

     

    Aaron
  • I think you are getting too hung up on my example. My example was arbitrary - just a simple way designed to help me understand how to and where I can reference global variables, as opposed to local and static ones.

     

     

    What is really bending my mind is this article: http://devcentral.f5.com/wiki/default.aspx/iRules/CMPCompatibility.html

     

    "Note - demoted only if caught by validator--"global" keyword was not caught by validator (:: reference)"

     

     

    1. I read this to mean I could define a global variable using the "global keyword" - hence "global client_local [TCP::local_port clientside]". Maybe that's wrong, and the only way to define a global variable is using the "$::client_local" syntax?

     

     

    2. Is there really only two variable types - local and global, with the global sub-divided into two sub-types: CMP-compatible and non-CMP-compatible? That would make a lot more sense. The doc makes it sound like there are three types, but it only seems to provide examples on how to define two - static and local. I can't figure out where this third type fits.

     

     

  • Ahh, Jason that was a fantastic reference. That video cleared it all up, and I was able to confirm the behavior I was expecting.

     

     

    Having watched that video, I think my statement about the three variables is spot-on. My feeling is that the doc I've read left me with the impression that there are three distinct types of variables - local, global, and static, when there are really just two - local and global. The trick for helping me understand is that global variables are subdivided into two types - CMP-compatible and non-CMP-compatible.

     

     

    There were lots of takeaways from that video, but here are a couple specifically related to the questions I posed in this thread:

     

    1. local variables set var "value" are CMP-compatible, can be defined in any event, and are referenced like $var.

     

    2. Non-static global variables are not CMP-compatible, are defined like set ::var "value", demotes all virtual servers with an irule referencing to a single CPU, and are referenced like $::var

     

    3. Static global variables are CMP-compatible, can only be defined in the RULE_INIT event, are defined like set static::var "value", and can be referenced by any iRule like $static::var.

     

     

    Hopefully this helps others out. Thanks a lot for your thoughts guys.