Previous 7.2 Measurement definitions Next

7.2.2 SNMP expression syntax

 

Two types of formulas can be measured with the help of the system:

In the first case an SNMP OID may be given, which consists only of numbers or it can contain a variable from some of the uploaded MIBs as a prefix. In this case the program measures the given OID.port (if it is not a table measurement, then the port value is 0). The remaining part of this sections deals with the complex expression based measurement calculations.

 

The measurement expression is a text which is evaluated by PVSR to determine the result of the measurement. The expression is basically follows the Perl programming language, with the exception that special PVSR elements can be used. Some of these elements influence and help the expression evaluation, while others tell PVSR how it should query the SNMP variables. The previous ones are discussed in section 7.2.2.1, while the others in section 7.2.2.2.

 

It also important to mention that PVSR uses the measurement expression during the discovery process as well, and not just during the data collection process. However if the first line in the measurement expression is

#no_discovery#

then PVSR will not make a sample measurement during the discovery process, so the discovery is entierly based on the Description OID variable. If its value is empty then this measurement type cannot be discovered. In this case an [add new] link is displayed in the Other measurement header, similar to the non-SNMP measurement configuration and the new measurements for this type have to be created using that link.

 

7.2.2.1 Generic expression elements

The following special variables can be used in the measurement expression. It is important to notice that unlike Perl programing language variables, these have to be used without the $ character

·       OUT: The measured value becomes the value of the OUT variable. During evaluation, the program automatically adds a “return OUT;” line to the expression, but naturally it is also possible to use this in the evaluation

·       NO_LINEAR_OUT: It has the same role as OUT. The difference lies in the processing of the returned value: when using OUT, the application also performs a linear stretch on the received value like in the case of the interface measurement. Therefore, if the received value is X and the previous value was Y, then the stored value becomes (X-Y)*INTERVAL/(INTERVAL+DIFFTIME)+Y. If NO_LINEAR_OUT occurs in the expression, then no such processing is done.

·       FLOAT_OUT: It is similar to the NO_LINEAR_OUT, except that by using this the measurement can have a float value not just an integer value

·       NEGATIVE_OUT: The same as the OUT, except it can also have negative values. It can only be used if the value of the Counter parameter is No

·       NEGATIVE_NO_LINEAR_OUT: The same as the NO_LINEAR_OUT, except it can also have negative values. It can only be used if the value of the Counter parameter is No

·       NEGATIVE_FLOAT_OUT: The same as the FLOAT_OUT, except it can also have negative values. It can only be used if the value of the Counter parameter is No

·       UPTIME: The sysUptime of the equipment in Unix time format

·       TIME: The actual measurement time in Unix time format

·       DIFFTIME: The difference between the actual measurement time and the reference time in seconds. The measured values are stored for whole measurement intervals, so if the actual measurement was made at 7 minute and the interval is 5 minutes, then the value of DIFFTIME is 120

·       PREVDIFFTIME: the value of DIFFTIME in the previous cycle

·       INTERVAL: Value of the measurement interval in seconds

·       PREVINVAL: The value of the first measurement formula in the previous data collection cycle. If that measurement was not successful then if the measurement cannot have negative values then its value will be -1, otherwise undef

·       PREVOUTVAL: Similar to the PREVINVAL, except for the second measurement formula

·       PREVVAL: If used in the first formula then it is the same as PREVINVAL, otherwise PREVOUTVAL

 

7.2.2.2 SNMP OID queries

The SNMP OID queries can be configured in two ways: simple query, when the application queries a given SNMP OID and complex queries, when the application queries several OIDs at once and then calculates a value using analytic functions (for example average) and gives back the result of this function to the measurement expression evaluation.

 

There are common elements in both cases. The query definition has to be placed between two # characters. At the end of the query definition, so just before the second # character, the .PRE string can be used: if it is used then PVSR replaces the #query# part with the value calculated in the previous data collection cycle and not with the value calculated in the current data collection cycle. The last common feature are the PORT and PORT(i[,j[,k…]]) functions, where i, j, k … are numbers. Both of these functions have to do with the Index parameter of the measurement. In case of an SNMP measurement this consits of numbers separated by "." character. The application replaces the PORT part with the value of the Index parameter, the PORT(i) is replaced with the ith number element in the value of the Index parameter, the elements are counted from 1. PORT(i,j) is replaced with the ith number element and jth number element, … For example if the value of an Index is 123.25.1.5 then PORT will be replaced with 123.25.1.5, PORT(2) with 25 and PORT(4,2,3,1) with 5.25.1.123

 

7.2.2.2.1 Simple OID queries

If we only want to query one specific OID then either the number representation of the OID or the MIB::variable format can be written between the # characters. The later one assumes that the MIB has been previously uploaded. For example:

·       #1.3.6.1.2.1.2.2.1.10.PORT#

·       #RFC1213-MIB::ifInOctets.PORT(1)#

 

7.2.2.2.2 Complex OID queries

PVSR also has a complex OID query system. Bulk query functions can be used to get the raw data from the devices and analytic functions can be used to process the result set and to give back one calculated valule based on the result set to the PVSR measurement framework. The complex OID queries can result quite long expressions. This is why it is important to mention once again that the expression must not contain line breaks, i.e. there must not be line break characters between the # characters.

 

Important: If a measurement expression contains a complex query then PVSR cannot use it for discovery purposes, so the first line of such a measurement expression should always be this:

#no_discovery#

 

7.2.2.2.2.1 Query functions

We can choose between three query functions. Each function has several parameters, some of them are mandatory, some of them are optional. The parameters can be specified in two ways. We can specify the value for each parameter in the same order as they appear in the documentation. If we do not specify a value for one of the parameter then it will take its default value. We can ommit the empty values at the end of the parameter list. For the other format the parameter must be specified in a NAME => VALUE format and the order is arbitrary. The parameters must be separated with semi-colon in both cases. Examples:

·       VALUE(CISCO-STACK-MIB::portIfIndex.PORT(1,2))

·       LAST(OID=>1.3.6.1.4.1.9.9.42.1.3.1.1.7.PORT;MAX_VALUE=>2147483647;OID_ELEMENT=>1)

 

The query functions are as follows

·       VALUE(OID;CONDITION;QUERY): it queries the given OID using SNMPWALK and/or SNMPGET. It then filters the results using the optional CONDITION condition (see its format later). The application tries by default both SNMP operations (WALK and GET). This is the same as setting the QUERY parameter to BOTH. If we only want to use SNMPWALK then its value must be WALK, while for the SNMPGET operation its value must be GET. Examples:

o   These two functions mean the same:

VALUE(CISCO-STACK-MIB::portIfIndex.PORT)

VALUE(QUERY=>BOTH;OID=>CISCO-STACK-MIB::portIfIndex.PORT)

o   The OID CISCO-STACK-MIB::portIfIndex has two indexes: portModuleIndex and portIndex. If the measurement expression is created in a way that the PORT parameter will be replaced only with the portModuleIndex value (so this is a per Cisco module measurement) then the CISCO-STACK-MIB::portIfIndex.PORT OID will not mean a leaf OID so the SNMPGET operation will be unsuccessful and the SNMPWALK must be used. Knowing that we might instruct PVSR so that it will only try the SNMPWALK

VALUE(CISCO-STACK-MIB::portIfIndex.PORT;;WALK)

o   Return those interface indexes which begins with 1

VALUE(1.3.6.1.2.1.2.2.1.1;=~/^1/;WALK)

·       VALUE(VALUE(…)…) and VALUE(oid.VALUE(…)…): the VALUE functions can be recursively embedded into each other, i.e. the value of the OID parameter can be an OID, another VALUE expression or the concatenation of these two. The default valule of the QUERY parameter is GET except for the innermost VALUE function. Examples:

o   The CISCO-STACK-MIB::portIfIndex variable stores the index of the interface belonging to the port, so if we want to query the interface speed for a specific Cisco port then the following expression can be used:

VALUE(RFC1213-MIB:: ifSpeed.VALUE(CISCO-STACK-MIB::portIfIndex.PORT))

·       INDEX(OID;CONDITION;ONLY_HEX): it queries the OID using SNMPWALK, then it takes those indexes for which the received value matches the optional CONDITION condition (see its format later). One or more OIDs can be specified for the OID parameter, separated by comma characters. If more than one OID were used then the application concatenates the results using space as the separator character. If the ONLY_HEX parameter is set to 1 and the queried value is a string then PVSR uses the 0x… hexadecimal presentation (for example 0xfa92bc) even if the string only contains printable characters. Examples:

o   It gives back the indexes of those interfaces which have an ifDescr value beginning with Gigab and their ifAdminStatus is 1 (up). An example result could be a list with items 10101, 10102 and 10103

INDEX(1.3.6.1.2.1.2.2.1.2,1.3.6.1.2.1.2.2.1.7;=~/^Gigab.+ 1$/)

o   It gives back the indexes of those interfaces which are of ethernetCsmacd type (value 6)

INDEX(OID=>1.3.6.1.2.1.2.2.1.3;CONDITION => == 6)

·       LAST(OID;CONDITION;ORDER_BY;ORDER_TYPE;OID_ELEMENT;MAX_VALUE;TOP_N;RESULTS;ONLY_HEX): the function searches the last rows for the OID and returns these last indexes or only a part of them. It first queries the OID using SNMPWALK then it takes those indexes for which the received value matches the optional CONDITION condition (see its format later). Similar to the INDEX function, several OIDs can be used separated with comma characters. If the ONLY_HEX parameter is set to 1 and the queried value is a string then PVSR uses the 0x… hexadecimal presentation (for example 0xfa92bc) even if the string only contains printable characters. After the filtering it orders the result set according to the ORDER_BY, ORDER_TYPE and MAX_VALUE parameters:

o   ORDER_BY: if it is not specified then it orders the indexes using the standard OID ordering (for example 1.1, 1.2, 1.10, 2.1 and 10.2). The ORDER_TYPE must not be specified in this case. If the ORDER_BY is not empty then PVSR uses the OID specified in it to order by indexes: it queries the ORDER_BY OID as well using SNMPWALK and sorts the indexes using the ORDER_BY OID results and the ordering specified with the ORDER_TYPE parameter. If the ORDER_BY query does not contain value for an index seen in the OID result set then that indexes is deleted from the result set, i.e. it will be automatically filtered out

o   ORDER_TYPE: how should PVSR order the set, i.e. compare the values for the indexes. The possible parameter values are int (this is the default), string or oid (the same as with the default ORDER_BY)

o   MAX_VALUE: if ORDER_TYPE is int then a maximum value can also be specified. For example we need the last value from an SNMP table which has new rows appearing all the time and these rows are indexed using the sysUptime variable (a 4 byte integer). In this case we have to set MAX_VALUE to 4294967295 (2^32-1), since the row index will "overflow" after a while, i.e. after the index 4294967295 the next one will be 0, 1, … If we do not set the parameter then as long as the row 4294967295 is in the table, PVSR would assume that that row is the last ("oldest"). However if we set the MAX_VALUE to 4294967295 and the PVSR sees both small and large values compared to the MAX_VALUE then it will detect the index overflow situation. The MAX_VALUE can also be set if the ORDER_BY is not set: in this case the MAX_VALUE is interpreted only for the first number element of the index value, so if the index is 32132.1.1 then it used only for the 32132 part

The function searches for the required result set after the sort operation. The result set contains the index values by default, although this can be configured with the OID_ELEMENT parameter. Its value can be either all (this is the default) or numbers separated by colons. In the later case the application splits the index and concatenates the numbers in the index using only the specified elements and in the specified order. For example if the index is 4.78.5.3 and OID_ELEMENT is 3,1 then it will return the 5.4 value. The function returns the last RESULTS unique elements from the result set, beginning with the TOP_N element. The uniqueness is important because although the indexes are already unique, the OID_ELEMENT parameter can modify the result set in a way that two or more indexes will be represented with the same value. The default value is 1 both for the RESULTS and the TOP_N parameter, so by default the function returns the very last element. If TOP_N is 2 and RESULTS is 3 then it will return the next to last index, the index before that and the index before that

 

As presented above, the LAST function has many parameters and features. For the sake of the examples we will assume that an equipment answered the following values for the 1.2.3.4.5 OID WALK (actually this OID does not exists)

1.2.3.4.5.2.5.1:    30

1.2.3.4.5.2.6.1:    12

1.2.3.4.5.2.92.1:   5

1.2.3.4.5.2.101.1:  51

1.2.3.4.5.2.101.2:  52

1.2.3.4.5.3.5.1:    33

1.2.3.4.5.3.6.1:    1

1.2.3.4.5.3.92.1:   4

1.2.3.4.5.3.101.1:  12

1.2.3.4.5.4.5.1:    aaa

1.2.3.4.5.4.6.1:    ccc

1.2.3.4.5.4.92.1:   bbb

The LAST function examples:

·       The last among the 1.2.3.4.5.2 OIDs

LAST(OID=>1.2.3.4.5.2): 101.2

·       The last among the 1.2.3.4.5.2 OIDs, but now we specify that the index overflows after the 103. Since small and large values also exist (relative to the max value), PVSR will assume that the latest entry is not 101.2 but 6.1

LAST(OID=>1.2.3.4.5.2;MAX_VALUE=>103): 6.1

·       The next to last among the 1.2.3.4.5.2 OIDs

LAST(OID=>1.2.3.4.5.2;TOP_N=>2): 101.1

·       The last and next to last among the 1.2.3.4.5.2 OIDs

LAST(OID=>1.2.3.4.5.2;TOP_N=>1;RESULTS=>2): 101.2 and 101.1

·       The last and next to last among the 1.2.3.4.5.2 OIDs, but this time we only want the first element of the indexes. The last three indexes are 101.2, 101.1 and 92.1. This will be modified to 101, 101 and 92 and PVSR treats the two 101 as the same, so the result will be 101 and 92

LAST(OID=>1.2.3.4.5.2;OID_ELEMENT=>1;RESULTS=>2): 101 and 92

·       The last two items, but using the 1.2.3.4.5.3 OID values and the number ordering

LAST(OID=>1.2.3.4.5.2;ORDER_BY=>1.2.3.4.5.3;RESULTS=>2): 5.1 and 101.1

·       The last item, but using the 1.2.3.4.5.4 OID values and the string ordering

LAST(OID=>1.2.3.4.5.2;ORDER_BY=>1.2.3.4.5.4;ORDER_TYPE=>string): 6.1

·       The fifth element, but using the 1.2.3.4.5.2 values for ordering instead of the indexes

LAST(OID=>1.2.3.4.5.2;ORDER_BY=>1.2.3.4.5.2;TOP_N=>5): 92.1

·       The fourth element, using 1.2.3.4.5.4 for ordering. The result will be an empty list: the OID 1.2.3.4.5.2 has five indexes but the 1.2.3.4.5.4 used for ordering only three

LAST(OID=>1.2.3.4.5.2;ORDER_BY=>1.2.3.4.5.4;TOP_N=>4): empty list

 

The optional CONDITION parameter can be used to filter the result set. The possible values and the format is the same for every function:

·       Mathematical operator and operand. The available operators: ==, !=, >=, <=, > and <. Examples:

== 123

>= 23

!= 12

·       String operator and operand. The operator is either eq for checking that the operand is equal to the compared value or ne for checking that it is not equal to the compared value. The compared value must be placed between " characters. Examples:

eq "sample1"

ne "ccc"

·       Regular expression. The i modifier can be used at the end of the expression to indicate case-insensitive matching. The first three sample matches the string Apple, the fourh does not

=~/Apple/

=~/a.+e/i

!~/a.+e/

!~/a.+e/i

 

7.2.2.2.2.2 The ALL function

 

The ALL(i) function does not do any processing. It is only a notation meaning "any i number of index elements". For example RFC1213-MIB::ifInOctets.ALL(1) means that PVSR should get every OID below RFC1213-MIB::ifInOctets and takes only those which have an additional number element after the RFC1213-MIB::ifInOctets OID (the ifIndex). Examples for this function can be found in the next section, which explains the analytic functions in detail.

 

7.2.2.2.2.3 Analytic functions

 

The query functions return lists with zero, one or more elements in them. The lists must be processed with one of the analytic functions. These functions have only one parameter, the expression which returns the list needed to be processed. The result of the analytic function gets send back to the PVSR measurement framework, so in the examples we will also show the beginning and ending # characters.

 

We will use the same OID WALK used for the LAST function examples

1.2.3.4.5.2.5.1:    30

1.2.3.4.5.2.6.1:    12

1.2.3.4.5.2.92.1:   5

1.2.3.4.5.2.101.1:  51

1.2.3.4.5.2.101.2:  52

1.2.3.4.5.3.5.1:    33

1.2.3.4.5.3.6.1:    1

1.2.3.4.5.3.92.1:   4

1.2.3.4.5.3.101.1:  12

1.2.3.4.5.4.5.1:    aaa

1.2.3.4.5.4.6.1:    ccc

1.2.3.4.5.4.92.1:   bbb

 

·       COUNT: it counts the number of elements in the list, i.e. it returns the size of the list. This is the only analytic function which is successful for an empty list. The 1.2.3.4.5 table has 12 elements. The 1.2.3.4.5.2.101 table has two elements and the LAST function will return a list with only one element: 101

#COUNT(1.2.3.4.5.ALL(3))#: 12

#COUNT(1.2.3.4.5.2.LAST(OID=>1.2.3.4.5.2;OID_ELEMENT=>1).ALL(1))#: 2

·       FIRST: it takes the first value. If we do not specify an analytic fucntion then PVSR automatically uses the FIRST function. The first element in the table has the value 30, and the first value in the 1.2.3.4.5.2.101 table is 51

#FIRST(VALUE(1.2.3.4.5;;WALK))#: 30

#1.2.3.4.5.2.LAST(OID=>1.2.3.4.5.2;OID_ELEMENT=>1).ALL(1)#: 51

·       SUM: sum of the values

#SUM(1.2.3.4.5.2.LAST(OID=>1.2.3.4.5.2;OID_ELEMENT=>1).ALL(1))#: 103

·       AVG: average of the values

#SUM(1.2.3.4.5.2.LAST(OID=>1.2.3.4.5.2;OID_ELEMENT=>1).ALL(1))#: 51.5

·       MIN: minimum value

#SUM(1.2.3.4.5.2.LAST(OID=>1.2.3.4.5.2;OID_ELEMENT=>1).ALL(1))#: 51

·       MAX: maximum value

#SUM(1.2.3.4.5.2.LAST(OID=>1.2.3.4.5.2;OID_ELEMENT=>1).ALL(1))#: 52

 

7.2.2.2.2.4 Index set functions

 

The index result set can be furthered processed before applying the analytic functions. The set function looks at the indexes seen in the previous data collection cycle and the current indexes and does additionally filtering based on this. The analytic function to be used after the set function is a parameter of the set function, so the result of the set function gets send back to the PVSR measurement framework.

 

There are two set functions: the DIFF and the NEW.

 

The DIFF function leaves only those indexes in the set which were seen both in the previous and in the current collection cycle. It also modifies the values for these indexes: it takes calculates the difference between the current value and the previous value. The function has one mandatory and two optional parameters, but unlike the query functions, the NAME => VALUE format cannot be used here. The three parameters are the following, in the same order as they can be specified:

·       The expression itself, similar to the analytic fucntions

·       Since the function calculates difference, it is prepared to handle the counter overflow situation. The second parameter is the max value used for this purpose, similar to the max value measurement type parameter. The special value 0 can be also used

·       The analytic function to be used after the set operation. The parameter is only optional, the application uses the default value FIRST if not specified

Example: we saw previously that the VALUE(CISCO-STACK-MIB::portIfIndex.PORT) expression can be used to get the ifIndex values for every interface bound to ports on the same module (if PORT only identifies the module and). If we want to summarize the interface traffic for a module then first we need to calculate the difference between the current value and the previous value for each interface and then summarize the differences. The interface counter choosen for the example is a 4 byte integer, so its max value is 4294967295- (2^32-1). The following will return the sum traffic in bytes for a module

#DIFF(RFC1213-MIB::ifOutOctets.VALUE(CISCO-STACK-MIB::portIfIndex.PORT);4294967295;SUM)#

 

The NEW function is the opposite of the DIFF function: it leaves only those indexes which were not seen during the previous data collection cycle. The function is usefull if there new rows created in an SNMP table and we only want to process those which are new to PVSR. The function has a mandatory and an optional parameter:

·       The expression itself, similar to the analytic fucntions

·       The analytic function to be used after the set operation. The parameter is only optional, the application uses the default value FIRST if not specified

 

7.2.2.3 Unsuccessful measurements

An OID variable has a -1 value during the evaluation if the query for it was unsuccessful and expression contains OUT, NO_LINEAR_OUT or FLOAT_OUT. In this case the output variable should have a value of -1 if the measurement should be considered as unsuccessful.

Contrarily an OID variable has an undefined (undef) value during the evaluation if the query for it was unsuccessful and expression contains NEGATIVE_OUT, NEGATIVE_NO_LINEAR_OUT or NEGATIVE_FLOAT_OUT. In this case the output variable should also have an undefined (undef) value if the measurement should be considered as unsuccessful.

 


 

7.2.2.4 Samples:

 

The expressions between the # characters must not contain line breaks, the samples contain line breaks between the # characters only because the expressions do not fit onto one line.

 

Wanted measurements

Expression

Cisco CPU measurement 1st case

1.3.6.1.4.1.9.2.1.58

Cisco CPU measurement 2nd case

OID=#1.3.6.1.4.1.9.2.1.58.0#;

Sample interface traffic measurement in bit/sec (The value of the counter should be set to Yes)

return -1 if (UPTIME < INTERVAL * 1.5);

OUT=#1.3.6.1.2.1.2.2.1.10.PORT# * 8;

 The same as above, but with a MIB variable

return -1 if (UPTIME < INTERVAL * 1.5);

OUT=#RFC1213-MIB::ifInOctets.PORT# * 8;

The difference between two OIDs if the result can be either non-negative or negative

if (defined #1.2.3.4.5.6.7.8# and defined #1.2.3.4.5.6.7.9#) {

    NEGATIVE_OUT=#1.2.3.4.5.6.7.8# - #1.2.3.4.5.6.7.9#;

} else {

    NEGATIVE_OUT=undef();

}

Cisco module traffic summary in bps (the Description OID should be 1.3.6.1.4.1.9.5.1.3.1.1.1)

#no_discovery#

my $now=#DIFF(RFC1213-MIB::ifOutOctets.VALUE(CISCO-STACK-MIB::portIfIndex.PORT);4294967295;SUM)#;

if ($now>-1) {

    NO_LINEAR_OUT=$now*8/INTERVAL;

}