A customer recently posted about an issue they encountered when migrating an iRule from BIG-IP 4.5.x to LTM v9.x.  When traffic was sent through the iRule, the connections would be reset.  There were no errors when loading the iRule in the iRule editor or at the command line.

It turns out that the syntax for the iRule was correct, but the name of a Data Group it referenced was misspelled. Both iRule editor and command line parser will display an error and fail to load the iRule for a bad pool or profile reference in an iRule, but the iRule Editor didn't mention the missing Data Group and neither did the command line when the iRule was loaded. The customer noted that there didn't seem to be any check done on whether the Data Group existed or not until execution of the iRule.  When the iRule actually ran against traffic and attempted to reference a non-existent Data Group, iRule would exit, and the connection would be reset.

For example, the following class and iRule will load fine, and no error is given indicating that the class is not really there. (Note the reference to "extenelStringClass" instead of "externalStringClass".)

class externalStringClass {
   "bind9"
   "ntp"
   "snmp"
}

rule misconf_rule {
   when HTTP_REQUEST {
      if {[matchclass [HTTP::uri] contains $::extenalStringClass]} {
         pool ServicePool
       } else {
         pool AppPool
       }
   }
}

virtual OmniVS {
   pool AppPool
   destination 192.168.1.14:1234
   ip protocol tcp
   rules misconf_rule
   profiles
      http
      tcp
}

In contrast, a similar version 4.5.x iRule would have generated a syntax error at load time since it references a non-existent class.  The poster goes on to say "There is no mention of this as a problem in any of the 9.x release notes. So keep this in mind as you are creating iRules and triple check to ensure you have the spelling of the Data Group correct."

Excellent advice!  Good coding practice dictates data validation and error catching whenever possible.  You can wrap most commands with "catch" to trap runtime errors and prevent your iRule from aborting on error.  Wrapping matchclass in catch requires saving the matchclass result to a variable, then referencing it later if no error was encountered:

rule catch_rule {
   when HTTP_REQUEST {
      if {[catch {[set match [matchclass [HTTP::uri] contains $::extenalStringClass]]} errmsg]} {
         log local0. "Fail - $errmsg"
      } else {
         if { $match } {
            pool ServicePool
          } else {
            pool AppPool
          }
      }
   }
}


which would log the runtime error to the LTM log and not abort the connection - it would be sent to the default pool. However, the symptoms of a misspelled data group name are fairly obvious even without using catch:  The LTM log is the first place you should be looking if things are going awry with your iRule.  In this case, the logs would have clearly reflected the problem, including the offending iRule line number and the name of the class the iRule was referencing at the time of the error.

But if you are wondering why the bahaviour changed, read on.

It's all in the interpretation...

...which can't happen until there is a conversation.  This is not an LTM issue, per se, rather it's an artifact of working with an interpreted language. Data groups (classes) are simply a special-case global array variable, and references to them are indistinguishable from any other global variable representation.
 
The syntax parser only checks syntax and configuration object references, and is incapable of identifying the non-existence of ANY variable called in an iRule at load time.  Since there is no compiler to pre-process the logic, bad variable references will not be revealed until runtime, when the rule is actually processing data and the interpreter is doing its thing (as the poster experienced.)   The upside of interpreted code is that runtime errors will include the offending line # (in this case the line containing the reference to the non-existent variable) -- much more straightforward than chasing down bad references in compiled code.
 
For iRules, if a runtime error is encountered during connection processing, the rule will exit immediately and stop processing the connection, then TMM will log the error & reset the affected connection.  Runtime errors are reliably logged unless your rule is causing TMOS to restart, so if you're ever working with an iRule and it is just not passing traffic, check the LTM log first for clues.  If substitutions of dynamic data may cause errors, wrap them in catch.  Other more static references, such as the one we've been discussing above, can be validated in runtime testing and save the overhead of unnecessary error checking with catch.

Some iRules enhancements are coming up soon in the areas of Data Groups and error handling in general, and I'll be sure to let you know when that happens.

Get the Flash Player to see this player.