As you're beginning to get more comfortable reading and writing iRules, you're going to continue expanding your toolbox as well as the tasks you're going to tackle. If your experience is anything like mine then sooner, rather than later, you'll be looking at ways to read, store, and manipulate different types of content. It's at this point in your "iRuling" career that variables begin coming into play more regularly and an understanding of what they are and how they're handled in iRules would probably be useful. Other articles in the series: 

Setting, Unsetting and Manipulating Variables

iRules makes use of standard TCL variables, for the most part, and as such most of the commands you'd use to set, unset, evaluate and effect variables in TCL still apply. Many of these commands are the same regardless of what type of data structure (variable) you're creating, and are straight-forward in their naming and behavior. For example, to set (or create) a variable, you simply use the command set:

set msg "Hello, World!"

The same command applies even when setting more complex structures and filling them with different types of data, static or dynamic alike. A few more examples could look like:

set r [expr rand()]
set vbl in[expr {rand() >= 0.5}]
set reqArray([IP::client_addr]) [getfield [string tolower [HTTP::uri]] "?" 2]

 

Now that you know how to set a variable, the next thing you should probably learn is how to delete it once you're done with it, even though iRules is pretty good about taking out the trash, but more on that later. To delete a variable that you've already created, you simply use the unset command, which looks like:

unset msg

This particular command can take multiple arguments, as well. To delete all the basic variables we set above, for example, you could simply use:

unset msg r vbl

 

Now that you can set and delete variables, what other kinds of fun things can you do to them? I mean, we all know they're meant to be used in place of static data in commands like pool and log, but what other commands do you have available to effect variables that are already in memory? The real answer is "lots!", but here are a few fun ones.

append
append is used for appending data to an already existing variable (Note: will also create the variable if it doesn't exist):

set var 0
for {set i 1} {$i<=10} {incr i} {
   append var "," $i
}

puts $var
# Prints 0,1,2,3,4,5,6,7,8,9,10

concat
The concat command will join all values provided as arguments together into a list, seperated by white space:

concat " a b {c   " d "  e} f"
will return "a b {c d e} f" as its result.

incr
By using the incr command you can increment the value of a variable either by 1 if no value is supplied, or by a desired value:

Add one to the contents of the variable x:
  incr x

Add 42 to the contents of the variable x:
  incr x 42

 

 

Variable Scopes (local vs. global)

One of the largest differences between standard TCL and iRules, as far as variable contruction and interaction are concerned, is that in iRules there are effectively only two namespaces - local and global. All "normal" variables are under the local scope. This means that they are connection based. You set the variable in the iRule, it remains present for the length of that connection, and is torn down when the connection is reaped. This is typically just a Request/Response pair but could span multiple Requests/Responses depending on the protocol, settings, etc. These variables are the most efficient, safest, and are what we use and recommend 98% of the time.

So what, you ask, makes up that other 2%? Global variables. A global variable in an iRule is set much the same way, can be influenced with the same commands just like the "normal" (local) variables in the demonstrations above, with one key difference; global variables are not tied to a session, but rather to a TMM instance. This means that you can access the data contained inside a gobal variable not just across events, but across connections as well. This can range from unnecessary to absolutely required depending on the task you're trying to accomplish (such as a counter that needs to extend across connections for something like a rate-limiting filter).

We tend to only use global variables when they are absolutely necessary for a couple of reasons. Efficiency, first, and ease of use, second. Since these variables aren't torn down nicely by TMM after every connection, you suddenly have to worry about variable scope and management, rather than just setting and forgetting. This isn't a horrendous undertaking, but something to keep in mind whenever you may end up using a global variable. If you set it, you'd better have a plan for unsetting it, too. This is especially true if you have multiple VIPs and or rules accessing a single variable as whatever value is last set will remain in place until the variable is updated or unset, which can cause unexpected behavior and even errors in some situations.

Lastly, how do you know which variables are which? Luckily this is easy. Global variables are defined and signified by a double colon before the variable name, such as ::myGlobal. You can spot these easily in an iRule because any variable starting with a double colon in this fashion is treated as a global variable, so there shouldnt' be any confusion when you see set ::r [expr rand()] instead of set r [expr rand()]. The only time this becomes even slightly confusing is when setting variables in the RULE_INIT event. All variables set under this event are treated as global, so keep that in mind. The same commands may be used against either local or global variables, though, so keep an eye out.

For more information on the commands I talked about see:
set
unset
append
concat
incr

And for a list of available TCL commands to see what other fun things you can do to/with variables, check out:
TCL Commands list

Get the Flash Player to see this player.