Forum Discussion

Al_Carandang_11's avatar
Al_Carandang_11
Icon for Nimbostratus rankNimbostratus
Sep 20, 2008

problem with findclass

I have an iRule which uses the following statement

set myData [findclass [virtual] myClass]

where the class entries are as follows

class myClass {  
  "icmrdc2_80 field1 field2 field3"    
  "icmrdc2_8081 field1 field2 field3"  
  }

when the virtual name is icmrdc2_80, findclass always returns

"icmrdc2_8081 field1 field2 field3"However, if the class entries are as follows

class myClass {   
  "icmrdc_80 field1 field2 field3"    
  "icmrdc_8081 field1 field2 field3"  
  }

when the virtual name is icmrdc_80, findclass always returns the entry "icmrdc_80 field1 field2 field3"

How do I make the findclass always search for an exact match?

thanks,

Al

8 Replies

  • Hello Al,

    finclass does a hardcoded wildcard match of the string against each line of the datagroup. I don't think there is a way around this. Perhaps you could make a feature request through F5 Support to provide an option for glob or specific matching against just the first "field" of the datagroup. In the meantime, you could use a for loop and getfield to perform an exact match against the class:

     
     when RULE_INIT { 
      
         Create a test class (actually a list in this case).  This could also be defined as a class/datagroup. 
        set ::test_class [list {field1 value1} {field1* value1} {field2 value2} {field11 value11}] 
      
         Loop through the datagroup line by line. 
        foreach element $::test_class { 
      
            Log the current line. 
           log local0. "Current \$element: $element" 
      
            Compare the element against the string. 
            If the datagroup entry has a wildcard, it should be listed first in the string compare statement. 
           if {[string match -nocase [getfield $element " " 1] "field11"]}{ 
      
               Found a match, so log it and break out of the foreach loop. 
              log local0. "Matched \$element: $element.  Value: [getfield $element " " 2]. Exiting loop." 
              break 
           } 
        } 
     } 
     

    Log output:

    Rule : Current $element: field1 value1

    Rule : Current $element: field1* value1

    Rule : Matched $element: field1* value1. Value: value1. Exiting loop.

    If you don't want wildcard matching, you can test with this version which doesn't have a wildcard in the datagroup:

     
     when RULE_INIT { 
      
         Create a test class (actually a list in this case).  This could also be defined as a class/datagroup. 
        set ::test_class [list {field1 value1} {field2 value2} {field11 value11}] 
      
         Loop through the datagroup line by line. 
        foreach element $::test_class { 
      
            Log the current line. 
           log local0. "Current \$element: $element" 
      
            Compare the element against the string. 
            If the datagroup entry has a wildcard, it should be listed first in the string compare statement. 
           if {[string match -nocase [getfield $element " " 1] "field11"]}{ 
      
               Found a match, so log it and break out of the foreach loop. 
              log local0. "Matched \$element: $element.  Value: [getfield $element " " 2]. Exiting loop." 
              break 
           } 
        } 
     } 
     

    Rule : Current $element: field1 value1

    Rule : Current $element: field2 value2

    Rule : Current $element: field11 value11

    Rule : Matched $element: field11 value11. Value: value11. Exiting loop.

    Aaron
  • Got an answer from F5. The value returned when there are multiple matches is arbitrary and depends on how the class gets loaded in memory.

     

     

    To solve the problem, the code should be written as
    set myData [findclass "[virtual] " myClass]

     

     

    -Al

     

     

     

  • Ran into some strange behaviour again. If the statement is
    set Base [virtual]  
      set myData [findclass "$Base " myClass " "]  
      
    myData is always empty

    -Al

  • found the answer... I was specifying the " " separator in the last case wherease I wasn't specifying one in the first.
  • Don't you need to refer to the class as ::class (or $::class in pre-9.4.2)?

     

     

    Aaron
  • It's been tossed around for a while... all of the forms (class, ::class, $class, $::class) seem to work as far as matching goes. I don't have a CMP enabled box to test on so I can't check which forms allow you to use CMP.

     
        log local0. "\[findclass 10.0.0.1 private_net\]: [findclass 10.0.0.1 private_net]" 
        log local0. "\[findclass 10.0.0.1 \$private_net\]: [findclass 10.0.0.1 $private_net]" 
        log local0. "\[findclass 10.0.0.1 ::private_net\]: [findclass 10.0.0.1 ::private_net]" 
        log local0. "\[findclass 10.0.0.1 \$::private_net\]: [findclass 10.0.0.1 $::private_net]" 
      
        log local0. "\[matchclass 10.0.0.1 equals private_net\]: [matchclass 10.0.0.1 equals private_net]" 
        log local0. "\[matchclass 10.0.0.1 equals \$private_net\]: [matchclass 10.0.0.1 equals $private_net]" 
        log local0. "\[matchclass 10.0.0.1 equals ::private_net\]: [matchclass 10.0.0.1 equals ::private_net]" 
        log local0. "\[matchclass 10.0.0.1 equals \$::private_net\]: [matchclass 10.0.0.1 equals $::private_net]" 
      
        log local0. "\[findclass 205.0.0.1 private_net\]: [findclass 205.0.0.1 private_net]" 
        log local0. "\[findclass 205.0.0.1 \$private_net\]: [findclass 205.0.0.1 $private_net]" 
        log local0. "\[findclass 205.0.0.1 ::private_net\]: [findclass 205.0.0.1 ::private_net]" 
        log local0. "\[findclass 205.0.0.1 \$::private_net\]: [findclass 205.0.0.1 $::private_net]" 
      
        log local0. "\[matchclass 205.0.0.1 equals private_net\]: [matchclass 205.0.0.1 equals private_net]" 
        log local0. "\[matchclass 205.0.0.1 equals \$private_net\]: [matchclass 205.0.0.1 equals $private_net]" 
        log local0. "\[matchclass 205.0.0.1 equals ::private_net\]: [matchclass 205.0.0.1 equals ::private_net]" 
        log local0. "\[matchclass 205.0.0.1 equals \$::private_net\]: [matchclass 205.0.0.1 equals $::private_net]" 
     

    Log output:

    Rule : [findclass 10.0.0.1 private_net]: 10.0.0.0/8

    Rule : [findclass 10.0.0.1 $private_net]: 10.0.0.0/8

    Rule : [findclass 10.0.0.1 ::private_net]: 10.0.0.0/8

    Rule : [findclass 10.0.0.1 $::private_net]: 10.0.0.0/8

    Rule : [matchclass 10.0.0.1 equals private_net]: 1

    Rule : [matchclass 10.0.0.1 equals $private_net]: 1

    Rule : [matchclass 10.0.0.1 equals ::private_net]: 1

    Rule : [matchclass 10.0.0.1 equals $::private_net]: 1

    Rule : [findclass 205.0.0.1 private_net]:

    Rule : [findclass 205.0.0.1 $private_net]:

    Rule : [findclass 205.0.0.1 ::private_net]:

    Rule : [findclass 205.0.0.1 $::private_net]:

    Rule : [matchclass 205.0.0.1 equals private_net]: 0

    Rule : [matchclass 205.0.0.1 equals $private_net]: 0

    Rule : [matchclass 205.0.0.1 equals ::private_net]: 0

    Rule : [matchclass 205.0.0.1 equals $::private_net]: 0

    Aaron
  • ::class and $::class work to make reference to a class (starting v9.4.2)

     

     

    But if you use matchclass or findclass then you should use ::class since it will maintain CMP. Click here

     

     

  • Thanks for the confirmation, nmenant. So should using class, $class and ::class all work to leave CMP enabled?

     

     

    Aaron