class

Description

The class command, implemented in v10.0.0, allows you to query data groups and data group properties.
These commands work for both internal (defined in the bigip.conf) and external (custom file) data groups. Internal data groups were not able to make use of the name/value pairing with the := separator until version 10.1. As of 10.1 all classes support the name/value pairing.
The class command deprecates the findclass and matchclass commands as it offers better functionality and performance than the older commands.
Note that you should not use a $:: or :: prefix on the datagroup name when using the class command (or in any datagroup reference on 9.4.4 or later). In v9.4.4 - 10, using $::datagroup_name will work but demote the virtual server from running on all TMMs. For details, see the CMP compatibility page. In v11, using $::datagroup_name will result in a TCL runtime error and a reset being sent to the client!

Note that starting in v11, any data-groups that are configured in a partition other than Common must be referenced by /Partition_Name/Data-Group_Name, even by iRules configured in that partition. Data-groups referenced only by name are implicitly presumed to be /Common/Data-Group_Name.

Syntax

class match [<options>] <item> <operator> <class>
class search [<options>] <class> <operator> <item>
class lookup <item> <class>
class element [<options>] <index> <class>
class type <class>
class exists <class>
class size <class>
class names [-nocase] <class> [<pattern>]
class get [-nocase] <class> [<pattern>]
class startsearch <class>
class nextelement [<options>] <class> <search_id>
class anymore <class> <search_id>
class donesearch <class> <search_id>

class match


class match [<options>] <item> <operator> <class>

  • class match attempts to match the provided <item> to an element in <class> by applying the <operator> to the <item>. The return value depends on the option specified. If no option was specified, the return value is 1 for a match and 0 for a no-match. See discussion below regarding options.

  • This command form is equivalent to the obsolete iRule command:

    • matchclass <item> <operator> <class>
      
  • Example:

    • class match [HTTP::uri] ends_with image_class
      
    • read as, does the URI end with an element from image_class.

  • Example:

    • class match [IP::client_addr] equals client_ip_class
      
    • read as, does the client IP address exist in the client_ip_class.


class match & class search difference:

Notice that there are differences between the two forms:

  • The order in which you specify <item> and <class>.
  • The item on which the operator is applied for operations other than equals.

The table below describes the semantics of the different operators when used in each of the commands. See also the example below for a code snippet depicting the differences:
operator class match class search
equals return a value indicating <class> has an element that is equal to <item> return a value indicating <class> has an element that is equal to <item>
starts_with return a value indicating there is a <class> element that matches the start of <item> return a value indicating <item>’s value matches the start of a <class> element
ends_with return a value indicating there is a <class> element that matches the end of <item> return a value indicating <item>’s value matches the end of a <class> element
contains return a value indicating <item>’s value contains a <class> element return a value indicating there is a <class> element that contains <item>

class match & class search optional arguments:

The for both of the above forms of the class command can be:
-index    Changes the return value to be the index of the matching class element.
-name     Changes the return value to be the name of the matching class element.
-value    Changes the return value to be the value of the matching class element.
-element  Changes the return value to be a list of the name and value of the matching class element.
-all      If used with -index, -name, -value, -element, changes the return value to
               all of the matching class elements.  (added in v11.0)
               NOTE: Beware that the return format when using -element and -all together is inconsistent. If a
               single element is matched, it is returned as a list, whereas if more than one element is matched,
               it is returned as a list of lists. (Behavior observed in 12.1.3.1)
--        Terminates option processing (useful if the <item> or <class> begins with a hyphen).
The for both of the above forms can be:
equals, starts_with, ends_with, contains

class lookup

  • Equivalent to:

    class match -value <item> equals <class>
    


class element []

  • Returns a list containing the name and value of the element found at in .
  • Note: class indexes are not guaranteed to be consistent and may change when a datagroup is modified. This could happen if the event execution becomes suspended or across executions of different events.

The for this command can be:
-name   Changes the return value to be the name of the class element at the index.
-value  Changes the return value to be the value of the class element at the index.
--      Terminates option processing.

class type

  • Returns the type of the , currently only “string”, “IP”, or “value”.

class exists

  • Returns 1 or 0 depending on whether a class named actually exists.

class size

  • Returns the number of elements currently found in .

class names [-nocase] []

  • Returns the names of the class elements

class get [-nocase] []

  • Returns a list containing the names or a list of the name and value currently found in .
  • An optional may be specified to restrict the list to names that match the Tcl glob pattern. Additionally, the switch -nocase may be specified to enable case-insensitive pattern matching.
  • This command provides a way to access the class as a Tcl list similar to previously access the global variable named the same as the list.

Note: Use class get only if you want to manage a class as a list. If you are looking for an element within the class, class search and class match are far more efficient. This is particularly important when using large classes.

class startsearch

  • Returns a to be used with each of the following commands.

class nextelement []

  • Returns a list containing the name and value of the next element in the current search.

The for this command can be:
-index       Changes the return value to be the index of the next class element.
-name        Changes the return value to be the name of the next class element.
-value       Changes the return value to be the value of the next class element.
--           Terminates option processing.

class anymore

  • Returns 1 or 0 depending on whether there are more elements to iterate on in the .

class donesearch

  • Terminates the search. After using this command, executing ‘class anymore’ or ‘class nextelement’ will cause a runtime error. To exit a loop early, use break . Once done with the search and outside any loop referencing the search id, use ‘class donesearch’ to clean up the memory associated with the search.

Note: When using the equals operator on IP classes, or when using the starts_with or ends_with operators, if multiple possible matches are found in the class, then the longest match is always chosen. This is not true when using the contains operator. See the example below for more details.

Examples

External Class Format (v10):
class namevalue {
  "name1" := "value",
  "name2" := "value",
}

Internal Class Format (v10.1):
class namevalue {
   {
      "name1" { "value1" }
      "name2" { "value2" }
   }
}

Internal Class Format (v11.0):
ltm data-group internal name_value_dg {
    records {
        name1 {
            data value1
        }
        name2 {
            data "value2 with spaces"
        }
    }
    type string
}

The example below demonstrates the differences between class match and class search when applied to a data group using different keys and operations (note that no option was specified, so the return value shown in the tables below is the operation result code). The iRule first gets the contents of the data group being queried and then performs the various operations using both forms. When a match occurs, the matching data group key is shown as well.
when RULE_INIT {

    log local0.info "dg_test_class: [class get dg_test_class]"
    foreach val {p://a.b p://a.b/x p://a.b/x/y p://a.b/x/y/z } {

        log local0.info "+[string repeat - 15]|[string repeat - 15]|[string repeat - 15]|[string repeat - 15]+"
        log local0.info "[format |%-15s|%15s|%15s|%15s| value operation {class match} {class search}]"
        foreach oper {equals starts_with ends_with contains} {
            set rc_match "[class match -name $val $oper dg_test_class]:[class match $val $oper dg_test_class]"
            set rc_search "[class search -name dg_test_class $oper $val]:[class search dg_test_class $oper $val]"
            log local0.info "[format |%-15s|%15s|%15s|%15s| $val $oper $rc_match $rc_search ]"
        }
        log local0.info "+[string repeat - 15]|[string repeat - 15]|[string repeat - 15]|[string repeat - 15]+"
    }
}

Below is the resulting log output (note the line prefix was stripped for brevity):
 "/Common/rl_test_dg <RULE_INIT>: dg_test_class: {p://a.b/x/y a_b_x_y} {p://y.y/x y_y_x} {p://u.v/w u_v_w}"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"
"/Common/rl_test_dg <RULE_INIT>: |value          |      operation|    class match|   class search|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b        |         equals|             :0|             :0|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b        |    starts_with|             :0|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b        |      ends_with|             :0|             :0|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b        |       contains|             :0|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"
"/Common/rl_test_dg <RULE_INIT>: |value          |      operation|    class match|   class search|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x      |         equals|             :0|             :0|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x      |    starts_with|             :0|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x      |      ends_with|             :0|             :0|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x      |       contains|             :0|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"
"/Common/rl_test_dg <RULE_INIT>: |value          |      operation|    class match|   class search|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y    |         equals|  p://a.b/x/y:1|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y    |    starts_with|  p://a.b/x/y:1|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y    |      ends_with|  p://a.b/x/y:1|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y    |       contains|  p://a.b/x/y:1|  p://a.b/x/y:1|"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"
"/Common/rl_test_dg <RULE_INIT>: |value          |      operation|    class match|   class search|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y/z  |         equals|             :0|             :0|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y/z  |    starts_with|  p://a.b/x/y:1|             :0|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y/z  |      ends_with|             :0|             :0|"
"/Common/rl_test_dg <RULE_INIT>: |p://a.b/x/y/z  |       contains|  p://a.b/x/y:1|             :0|"
"/Common/rl_test_dg <RULE_INIT>: +---------------|---------------|---------------|---------------+"

This example disables compression based on source IP’s in an address type datagroup named localusers_dg
when HTTP_REQUEST {
    if { [class match [IP::client_addr] equals "localusers_dg" ] } {
        COMPRESS::disable
    }
}

This v10 example chooses a pool based on the URI requested:
/config/app_class.dat:
"/trxdef/" := "trx_pool",
"/aaa/" := "aaa_pool",
"/abscon/" := "abs_pool",

class app_class {
   type string
   filename app_class.dat
}

rule appl_director {
   when HTTP_REQUEST {
      set app_pool [class match -value -- [HTTP::uri] starts_with app_class]
      if {$app_pool ne ""} {
         pool $app_pool
      } else {
         pool default_pool
      }
   }
}

This example chooses a pool based on the time of day:
/config/daily_schedule.dat:
0 := early_morning_pool,
7 := morning_rush,
10 := midday_pool,
15 := afternoon_rush,
18 := evening_pool,

class daily_schedule {
   type value
   filename daily_schedule.dat
}

rule daily_director {

   # Initialize a variable to track the closest hour match
   # as we loop through the datagroup elements.
   # We want to find the lowest hour in the datagroup that is
   # greater or equal to the current hour.
   #
   # Note: The order of datagroup elements is not guaranteed
   # so we must loop through all elements to find the best match.

   when HTTP_REQUEST {

      # Get the hour of day
      set hour_now [clock format [clock seconds] -format {%H}]

      # Save a search ID for the daily_schedule datagroup
      set id [class startsearch daily_schedule]

      # Initialize a variable to track the closest hour match
      # By setting this to higher than the highest hour of the day,
      # any match in the datagroup will override this default value.
      set best_match 24

      # Loop through the datagroup
      while { [class anymore daily_schedule $id] } {

         # Save the current element's key and value to a TCL list
         set x [class nextelement daily_schedule $id]

         # Save the current datagroup element's hour field (the first list element)
         # to a variable so we don't rerun the lindex several times
         set hour_class [lindex $x 0]

         # Check if the current hour is greater than the current element key
         if {$hour_now >= $hour_class && $hour_class < $best_match} {

            # Save the currently matched hour to see if it's the best match
            set best_match $hour_class

            # Save the value as the pool name
            set pool [lindex $x 1]
         }
      }
      # Assign the best match's corresponding pool
      pool $pool
   }
}

This example demostrates how to loop through each element in a datagroup using ‘class startsearch’ and exit the loop once a match is found. Cleanup of internal structures is done using ‘class donesearch’:
when RULE_INIT {

   # Save a class name to search through
   set class_name numbers_class

   # Save a search ID for the datagroup
   set id [class startsearch $class_name]

   # Loop through the class row by row
   while {[class anymore $class_name $id]}{
      set element [class nextelement $class_name $id]
      log local0. "\[class nextelement $class_name $id\]: $element"

      # Perform some operation against the current datagroup key and/or value

      # Check if the element's key is greater than 2
      if {[lindex $element 1] > 2}{

         # Exit the loop if the logic check is true
         log local0. "Found key greater than 2, breaking out of loop"
         break
      }
   }
   # Clean up the search
   class donesearch $class_name $id
}

This example extracts an base64 encoded image from a class to send in an HTTP response when load balancing failed:
/config/img.txt:
"img" := "R0lGODlhEgAeANUAABAREz9CSEBBQz0+QB8hJCIkJ5eZnGJlaXN2egQJDwUKEDo+Q0VJTgE
         DBQULEQUKDwMGCTo+Qk1RVUtPU0pOUk9TV1RYXFZaXlxgZFtfYy0vMRcYGTEzNR8gIW5xdG1
         wc2lsb2hrbklLTXh7fnV4e3R3enN2eXF0d4SHiqCipJeZmwQKDwULEDU6PktQVFtfYjI4PHN
         2eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAAEgAeAEA
         G20CRcEgsDjFIZGa5fDmTSId0Sq2yroqsdsvVnr5fk9gUK8fAX4Z6zW6vu3Duak6v2+mIfH7
         E7/P1eSGsDjFIZGa5fDmTSId0Sq2yroqsdsvVnr5fk9gUK8fAX4Z6zW6vu3Duak6v2+CggMd
         IIWHHYOCsDjFIZGa5fDmTSId0Sq2yroqsdsvVnr5fk9gUK8fAX4Z6zW6vu3Duak6v2+FY2NG
         hsSkJIbjsDjFIZGa5fDmTSId0Sq2yroqsdsvVnr5fk9gUK8fAX4Z6zW6vu3Duak6v2+o0RmJ
         gEAC2bnQsDjFIZGa5fDmTSId0Sq2yroqsdsvVnr5fk9gUK8fAX4Z6zW6vu3Duak6v2+CZmFU
         uEA6kpqUsDjFIZGa5fDmTSId0Sq2yroqsdsvVnr5fk9gUK8fAX4Z6zW6vu3Duak6v2+OVyxc
         ExAKrrCvsDjFIZGa5fDmTSId0Sq2yroqsdsvVnr5fk9gUK8fAX4Z6zW6vu3Duak6v2+W3auK
         7a2dSm7vL2+vCXBwSTExcTCwR/KygYCHs0eKgLLygfW19jZ1xfc3CgcFt/hHN3cFOfo6eroA
         e3tJwU7vL2+L8PIF7u0w+Pn6+/lV/lSruEBooGBgQYJxEio0yBChlgcQI0qcGPGORTsJMmrc
         yFFjEA7vL2+A7",

class img {
   type string
   filename "/config/img.txt"
}

rule LBFailedResponse {
   when LB_FAILED {
      HTTP::respond 200 content [b64decode [class element -value 0 img]] "Content-Type" "image/png"
   }
}

Using the -all flag added in v11.0 to return details on multiple matches (for class match or class search):
Show the full contents of the string_dg datagroup retrieved as a TCL list:
log local0. "[class get string_dg] "
# Log output: {abc value1} {abcd value2} {abcde value3} {123 value4}

Use -all with no other options to return a count of the number of matching names in the datagroup:
log local0. "[class search -all string_dg starts_with "abc"]"
# Log output: 3

Use -all with the -index option to return the index of matching names in the datagroup:
log local0. "[class search -all -index string_dg starts_with "abc"]"
# Log output: 0 1 2

Use -all with the -element option to return the name and value of matching names in the datagroup:
log local0. "[class search -all -element string_dg starts_with "abc"]"
# Log output: {abc value1} {abcd value2} {abcde value3}

Use -all with the -name option to return the name of matching names in the datagroup:
log local0. "[class search -all -name string_dg starts_with "abc"]"
# Log output: abc abcd abcde

Use -all with the -value option to return the value of matching names in the datagroup:
log local0. "[class search -all -value string_dg starts_with "abc"]"
# Log output: value1 value2 value3

Examples showing longest-match selection (v11.x syntax):
ltm data-group internal /Common/addr_list {
    records {
        10.0.0.0/8 {
            data bignet
        }
        10.0.0.0/24 {
            data littlenet
        }
    }
    type ip
}
ltm data-group internal /Common/string_list {
    records {
        left {
            data first
        }
        lefter {
            data second
        }
    }
    type string
}

log local0. "match of 10.0.0.128 is [class match -value 10.0.0.128 equals addr_list]"
log local0. "match of lefterest is [class match -value lefterest starts_with string_list]"

will log:

Rule /Common/classes <RULE_INIT>: match of 10.0.0.128 is littlenet
Rule /Common/classes <RULE_INIT>: match of lefterest is second
In each case, the longest match was used (10.0.0.0/24 had a longer match than 10.0.0.0/8, and “lefter” had a longer match than “left”).