www.logmatrix.com
blog
community
support
contact us
 

docs.nervecenter.com :: NerveCenter :: NC6.1.00

NC::MIB perldoc
April, 2014


NAME
       NC::MIB - Access to NerveCenter MIB
SYNOPSIS
       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
       object".

           % 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)}
           %

       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 is 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 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 get 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 per-
       son’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.

           for ( 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
AUTHOR
       Maintained by Customer Service <techsupport@openservice.com>
COPYRIGHT
       Copyright (c) 1994-2014 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.

###