![]() |
  |
|
NC::MIB - Access to NerveCenter MIBSYNOPSIS
The NC::MIB module implements an API that allows access to the MIB being used by the NerveCenter Server. The module and API is available for all Perl usage within NerveCenter (Poll functions, Trap Mask func- tions, and Perl Subroutine Actions).DESCRIPTION
The MIB is a large static cache of data loaded by NerveCenter Server. "MIB" stands for Management Information Base and is the data dictionary used for SNMP operations. The NerveCenter MIB Compiler, 'mibTool', cre- ates the MIB. The NerveCenter Server then loads it upon startup. Within a MIB there are typically hundreds, if not thousands, of name and OID declarations plus enumeration listings. NerveCenter uses this data dictionary for building SNMP requests, parsing responses and decoding SNMP Notifications (Traps and Informs). This data can be accessed through the API that this module implements. Object names, OIDs and types Each entry in the MIB centers on defining an Object. An Object has a name, an object identifier (OID) and a type. Let's consider each of these in turn. Object names Object names are textual labels, meaning they are "human readable." Examples of names are "system.sysName", "ifEntry.ifInOctets", and "ifX- Entry.ifHCInOctets". Notice there are two parts to this: a base object name and an attribute name. NerveCenter makes the distinction between base object and attribute in that attributes are items attached to a base object and may contain a (pollable) value. For example "sysLocation" is an attribute of the base object "system". In SNMP, "sysLocation" can be polled but "sys- tem" cannot. If you try to poll "system" in a tool such as 'ncget', the response from the polled SNMP Agent will be something like "No such name". Here's an attempt using 'snmpget' from NET-SNMP: % /usr/bin/snmpget -v 1 -c public 192.168.1.1 1.3.6.1.2.1.1 Error in packet Reason: (noSuchName) There is no such name variable in this MIB. Failed object: SNMPv2-MIB::system % And here's an attempt using 'ncget' from NerveCenter: % ncget -v1 192.168.1.1 public system Sending to 192.168.1.1 161/udp Error! noSuchName [Check vb#1 (Agent cannot resolve the OID)] #vb1: {system, (null)} % For both tools, the result is the same: the agent at 192.168.1.1 is rejecting the SNMP Get request, saying that the given OID is not for a pollable entity. But if you poll for the "sysLocation" you might get back a value. % ncget -v1 192.168.1.1 public sysLocation.0 Sending to 192.168.1.1 161/udp Normal SNMPv1 reply #vb1: {sysLocation.0, Boston, MA/OCTET STRING[10]} % (So, "What is with that ".0"?" you might be asking. In SNMP you always need to phrase a GET REQUEST by including which 'instance' you want to retrieve. For scalars, such as found in the 'system' group, a ".0" is the required instance. Later, when we look at tables, you'll see instances being used in a more understandable manner - such as that ".33" is the instance naming for row #33. Unfortunately you have to remember that ".0" is the mandatory instance value for scalars.) Object identifiers (OIDS) OIDs are, each, a specific series of sub-identifiers, where each sub- identifier is a numeric value. They are commonly displayed in a deci- mal-dot notation, such as "1.3.6.1.4.1.78". These values are stati- cally assigned. So if "1.3.6.1.2.1.1.1" means "system.sysDescr", then it will always mean that. Also, know that the same is true in reverse: "system.sysDescr" translates to "1.3.6.1.2.1.1.1" and this will always be the this name's OID translation. Sometimes OIDs are preceeded with a leading dot. And sometimes by a trailing dot. Either is optional and therefore often omitted. The API understands this. For example the API sees these three OIDs as identi- cal: ".1.3.6" and "1.3.6" and "1.3.6.". OIDs may not contain non-numeric characters. So "one.2.3." is not an OID. Neither is "1.c.3.2" or "$1.19". As well, OIDs must have at least one sub-identifier. This means "." by itself does not qualify as an OID but "1" is perfectly fine - it is a single element OID. Object types Objects always have a type association. In SNMP the set of possible types is limited to a fairly small range: INTEGER, Integer32, Counter, Counter32, Counter64, Gauge, Gauge32, IpAddress, ObjectID, OctetString, TimeTicks and Unsigned32. Adding it up: Object Names + OID + Type Every object defined in the MIB consists of a name, an OID and a type. This trio of information is known to all devices (SNMP Agents) that support the object. Thus if you ask for "system.sysContact" from some- thing, the local SNMP Stack knows to convert the requested name to its assigned OID; the SNMP Agent answering the query for this object knows the same assignment; the SNMP Agent will respond (if it supports the requested object) with specified data type. In a loose way this is similar to how telephones work: If you want to call somebody, you use their phone number; you only get to talk to your friend if you use the right phone number. Let's try an example. To lookup a device's "system.sysContact" value the following steps are used, assisted by the entries held in SNMP data dictionary (ie: the MIB). 1. An application needs to find out a device's "system.sysContact" value. The requesting application looks up "system.sysContact" in its MIB. The retrieved OID is "1.3.6.1.2.1.1.4". 2. The requesting application issues a SNMP 'Get' request to the device, asking for "1.3.6.1.2.1.1.4". 3. The device being queried does a reverse lookup on the incoming request's "1.3.6.1.2.1.1.4" and knows to respond with the value for its configured "sysContact" information. The data type for this value is "OctetString", which for this object means a displayable string (ex: "Jane Doe"). 4. The device responds back to the requesting application, supply- ing the same OID and the value ("Jane Doe"), identifying the value as an OctetString 5. The requestion application gets the response, finds the "1.3.6.1.2.1.1.4" and associated OctetString containing the value ("Jane Doe"). Using its MIB, the application recoginizes the "1.3.6.1.2.1.1.4" as being the identifier for "system.sysContact" and can verify that the return type (OctetString) is what should be returned and uses this to unpackage the data value ("Jane Doe"). Translating between OIDs and names As seen in the above scenario, bridging back and forth between OIDs and Names is a primary usage of the MIB. NC::MIB provides for this with the functions parse_oid(), get_oid() and get_name(). parse_oid() - translate an object identifier's naming $name = NC::MIB::parse_oid( $oid ); This method translates an OID to a name. The OID argument to parse_oid() is to be given as a Perl string scalar. For example: my $oid = "1.3.6.1.2.1.1.1.0"; my $name = NC::MIB::parse_oid( $oid ); print "Okay, $oid translates to $name!\n"; Okay, 1.3.6.1.2.1.1.1.0 translates to system.sysDescr.0! Names in NerveCenter are provided as a combination of a base object name, an attribute name and a trailing instance identification. You can see that in the example. The OID "1.3.6.1.2.1.1.1.0" didn't return simply a word but rather the longer value "system.sysDescr.0". The three elements of that return line up with NerveCenter's naming: a base object, an attribute and a trailing instance. Let's use Perl's split() function to break up the response so we can look at it again. my $oid = "1.3.6.1.2.1.1.1.0"; my $name = NC::MIB::parse_oid( $oid ); print "Okay, $oid translates to $name!\n"; my ( $baseObject, $attribute, $instance ) = split( '\.', $name, 3 ); print " --- $baseObject + $attribute + $instance\n"; Okay, 1.3.6.1.2.1.1.1.0 translates to system.sysDescr.0! --- system + sysDescr + 0 Now, without repeating all the Perl lines, the following snippets show a replacement for the first line ( "my $oid = ...." ) and then jump forward to show how parse_oid handles a wider set of possible OIDs. The examples cover errors and other oddities. # -------------------------------------------------------------- # Ex1: '1' is the base of the OID tree. 'iso' is the name assigned to '1'. my $oid = '1'; Okay, 1 translates to iso! --- iso + + # -------------------------------------------------------------- # Ex2: '1.3.6'. This translates to 'dod'. my $oid = '1.3.6'; Okay, 1.3.6 translates to dod! --- dod + + # -------------------------------------------------------------- # Ex3: An invalid OID is given. So we get back nothing. my $oid = 'one.2.3'; Okay, one.2.3 translates to ! --- + + # -------------------------------------------------------------- # Ex4: The ifInOctets value for the row #50 of ifTable. # 1.3.6.1.2.1.2.2 = ifTable # 1.3.6.1.2.1.2.2.1 = ifEntry # 1.3.6.1.2.1.2.2.1.10 = ifInOctets # 1.3.6.1.2.1.2.2.1.10.50 = ifInOctets on row #50 my $oid = '1.3.6.1.2.1.2.2.1.10.50'; Okay, 1.3.6.1.2.1.2.2.1.10.50 translates to ifEntry.ifInOctets! --- ifEntry + ifInOctets + 50 get_name() -- translate an object identifier to its closest fitting name my $name = NC::MIB::get_name( "1.3.6.1.2.1.1" ); The function get_name() returns a single name for a given OID. The return represents the closest fitting name for the OID, where the attempt is made to find the single object from the MIB that comes the closest to matching the OID. In the first example, the OID is an exact match for an entry in the MIB. "1.3.6" is "dod". In the second example, the longer OID is best matched by ifInOctets. The trailing ".50" of the argument "1.3.6.1.2.1.2.2.1.10.50" does not lead to a better fit, so it is ignored. # -------------------------------------------------------------- # Ex1: "1.3.6" is 'dod' in the mib. my $oid = "1.3.6" my $name = NC::MIB::get_mib( $oid ); print "$name best fits $oid\n" dod best fits 1.3.6 # -------------------------------------------------------------- # Ex2: The ifInOctets value for the row #50 of ifTable. # 1.3.6.1.2.1.2.2 = ifTable # 1.3.6.1.2.1.2.2.1 = ifEntry # 1.3.6.1.2.1.2.2.1.10 = ifInOctets my $oid = '1.3.6.1.2.1.2.2.1.10.50'; my $name = NC::MIB::get_mib( $oid ); print "$name best fits $oid\n" ifInOctets best fits 1.3.6.1.2.1.2.2.1.10.50 A third example shows the tear-down of an OID by repeated removal of its final sub-element and using get_name() to examine what remains. The code is a loop. # -------------------------------------------------------------- # loop and tear-down "1.3.6.1.2.1.2.2.1.10.50" my $oid = "1.3.6.1.2.1.2.2.1.10.50"; my $indx = rindex( $oid, '.'); while ( $indx != -1 || length($oid) > 0 ) { print "get_name( " . $oid . " ) -=> " . NC::MIB::get_name( $oid ) . "\n"; $oid = substr( $oid, 0, $indx-length($oid) ); # pop off the trailing ".nnn" $indx = rindex( $oid, '.'); } When this is encountered the following is produced. Notice how there are two best fits for "ifInOctets". This because the ".50" is being ignored. Once it and the ".10" are popped off the layers of supporting MIB object names are revealed. get_name( 1.3.6.1.2.1.2.2.1.10.50 ) -=> ifInOctets get_name( 1.3.6.1.2.1.2.2.1.10 ) -=> ifInOctets get_name( 1.3.6.1.2.1.2.2.1 ) -=> ifEntry get_name( 1.3.6.1.2.1.2.2 ) -=> ifTable get_name( 1.3.6.1.2.1.2 ) -=> interfaces get_name( 1.3.6.1.2.1 ) -=> mib-2 get_name( 1.3.6.1.2 ) -=> mgmt get_name( 1.3.6.1 ) -=> internet get_name( 1.3.6 ) -=> dod get_name( 1.3 ) -=> org get_name( 1 ) -=> iso get_oid() -- translate a Base Object and Attribute name to an OID my $name = 'system.sysDescr'; my $oid = NC::MIB::get_oid( $name ); The function get_oid() is roughly the reverse of parse_oid(). The parameter given to get_oid() is a name, such as "system.sysLocation" or "ifXEntry.ifHCInOctets". The return will be the OID assigned to that name. If the input name is not known, then the output is an empty value. Supportive lookup functions get_trapname() -- translate an OID into a SNMP Notification Name $trapname = NC::MIB::get_trapname( $trapoid ); SNMP Notifications are defined as being either a Trap or an Inform. Traps and Informs are defined in the MIB and each is identified by an assigned OID. When a SNMP Notification is received by a management application, the notification's OID - referred to as its Trap OID - is used to identify it. This is rather analogous to phone numbers and Caller ID. For example when your phone rings, it might show you a phone number. You, or perhaps your phone, translates this to a person"s name. This is how a management station identifies notifications: it looks at the incoming event"s Trap OID and converts this to a name. The get_trapname() function does the lookup and conversion of a Trap OID to its defined name. If given Trap OID is found, the function returns the name as a string value. If the Trap OID is not recogniz- able, then the function returns an empty string value. get_mibname() -- retrieve the name of the defininig MIB Module my $mibname = NC::MIB::get_mibname( $name ); The MIB is created from a set of text files wherein each provides a 'MIB Module'. Each such module defines a set of objects, often build- ing their definitions from declarations made in base-level modules. The result, the data dictionary known as the MIB, is the sum of the declarations found across the set of included MIB Modules. In NerveCenter, the 'mibTool' utility creates the MIB. When it assem- bles the data dictionary, it includes with each object the name of the MIB Module where it was defined. This can be retrieved through the function get_mibname(). If the function can find the provided OID or Name in the MIB, it returns the name of the defining MIB Module. If the lookup is not successful, it returns an empty string. get_type() -- retrieve an object's return type Translating between enumerated values and names There are many cases where a MIB object is defined to contain one of a set of possible values. The range of these possible values is given as an enumeration. The definition provides both a value and a label for each possibility. An example is the quickest way to see this. In RFC2863 and its IF-MIB module, the object 'ifEntry.ifAdminStatus' tells whether an interface on a device is administratively allowed to be used or is turned off or is set to be in a test mode. From the MIB Module "IF-MIB" this is the definition: ifAdminStatus OBJECT-TYPE SYNTAX INTEGER { up(1), -- ready to pass packets down(2), testing(3) -- in some test mode } MAX-ACCESS read-write STATUS current DESCRIPTION "The desired state of the interface. The testing(3) state indicates that no operational packets can be passed. When a managed system initializes, all interfaces start with ifAdminStatus in the down(2) state. As a result of either explicit management action or per configuration information retained by the managed system, ifAdminStatus is then changed to either the up(1) or testing(3) states (or remains in the down(2) state)." ::= { ifEntry 7 } When an instance of this object is polled, the response should be one of the three defined values. The response will contain the numeric value. To support working with enumerations, NC::MIB provides the two func- tions get_enum_value() and get_enum_label(). get_enum_label() -- retrieve the text label for a numeric value The function get_enum_label() retrieves from the MIB the text label assigned to a numeric value for a specific MIB object. If the function is called with a MIB Object that does not define a numeric range, or the MIB object is unknown, or the provide value is out of the defined range, then an empty string is returned. Otherwise, the assigned text value is returned. Here is an example using the above ifAdminStatus definition. This bit of Perl code loops over the range defined by the definition and prints the labels.AUTHORfor ( my $value = 0; $value < 6; $value++ ) { my $label = NC::MIB::get_enum_label( "ifEntry\.ifAdminStatus", $value ); print TFILE "For ifAdminStatus of $value, the label is $label\n"; }
When run, the loop produces the following output lines. For ifAdminStatus of 0, the label is For ifAdminStatus of 1, the label is up For ifAdminStatus of 2, the label is down For ifAdminStatus of 3, the label is testing For ifAdminStatus of 4, the label is For ifAdminStatus of 5, the label is As a second example, the following Perl code shows a loop that works across the varbinds attached to a trap. As part of its per-varbind processing, this code uses get_enum_label() to find if there is a label for varbind's value.for ( my $vbn = 0; $vbn < VbNum(); $vbn++ ) { my $attr = VbAttribute( $vbn ); my $object = VbObject( $vbn ); my ( $baseobject, $instance ) = split( '\.', $object, 2 ); my $vboid = NC::MIB::get_oid( "$baseobject.$attr" ) . "\.$instance"; my $value = VbValue( $vbn ); my $type = NC::MIB::get_type( "$baseobject.$attr" ); my $enumlabel = NC::MIB::get_enum_label( "$baseobject.$attr", $value ); my $mibmodule = NC::MIB::get_mibname( "$baseobject.$attr" ); print " #vb$vbn: {$mibmodule\:\:$baseobject.$attr.$instance, "; print "$enumlabel $value\/$type} (oid:$vboid)\n"; }
For a linkDown event, the output from the above code gives the follow- ing output. The 'up' and 'down' are the returns from this get_enum_label(). #vb0: {IF-MIB::ifEntry.ifIndex.100, 100/INTEGER} (oid:1.3.6.1.2.1.2.2.1.1.100) #vb1: {IF-MIB::ifEntry.ifAdminStatus.100, up 1/INTEGER} (oid:1.3.6.1.2.1.2.2.1.7.100) #vb2: {IF-MIB::ifEntry.ifOperStatus.100, down 2/INTEGER} (oid:1.3.6.1.2.1.2.2.1.8.100) get_enum_value() -- retrieve the numeric value for a text label The function get_enum_value() performs the reverse of get_enum_label. The function is called with a text label and a specific MIB object. Similar to get_enum_label, if the named MIB object defines an enumera- tion and then the provided label matches one of the defined entries, then the corresponding value is returned. If no matching value can be found, then a -1 (negative one) is returned; thus this function is always returning a numeric value. In this example the defined labels for ifAdminStatus (up, down, test- ing) are intermixed with several other words. These are fed through get_num_value() and the output shows the result.my @labels = qw/flower up duck down goose testing bread/; foreach my $label ( @labels ) { my $val = NC::MIB::get_enum_value( "ifEntry\.ifAdminStaus", $label ); print TFILE "For ifAdminStatus and the label $label, the value is $val\n"; }
... For ifAdminStatus and the label flower, the value is -1 For ifAdminStatus and the label up, the value is 1 For ifAdminStatus and the label duck, the value is -1 For ifAdminStatus and the label down, the value is 2 For ifAdminStatus and the label goose, the value is -1 For ifAdminStatus and the label testing, the value is 3 For ifAdminStatus and the label bread, the value is -1
Maintained by Customer Service <techsupport@logmatrix.com>COPYRIGHT
Copyright (c) 1994-2016 by OpenService, Inc./LogMatrix, Inc. All rights reserved. This module is provided as a component of the NerveCenter product. It is not meant for availability apart from usage with NerveCenter. Use of this module should remain consistent with that expressed in the licensing of NerveCenter.
###