The structure of a MIBs internals are a little strange and foreign at first, but it's structured well enough that you can poke through it pretty intelligently without really knowing what your doing. The structure of a MIB comes from the Structure of Management Information (SMI) standard detailed in IETF RFC 1155 and 2578. If you choose to modify or write your own MIBs you'll benefit from understanding SMI before hacking much on MIBs.
Lets look at the header of a MIB to get a better idea of how they work:
-- PowerNet-MIB { iso org(3) dod(6) internet(1) private(4) -- enterprises(1) apc(318) } PowerNet-MIB DEFINITIONS ::= BEGIN IMPORTS enterprises, IpAddress, Gauge, TimeTicks FROM RFC1155-SMI DisplayString FROM RFC1213-MIB OBJECT-TYPE FROM RFC-1212 TRAP-TYPE FROM RFC-1215; apc OBJECT IDENTIFIER ::= { enterprises 318 } products OBJECT IDENTIFIER ::= { apc 1 } apcmgmt OBJECT IDENTIFIER ::= { apc 2 }
Comments can be inserted into a MIB by prepending them with two dashes. In the header the declaration BEGIN starts off the MIB. Imports can be used to pull information from other MIBs, typically those mandated by the MIB-II standard.
The MIB lays out the structure of OID addresses starting from the enterprises value. Here the enterprise value 318 maps to "apc" (relative address .1.318). Typically then several categories are defined. Here we see 2 categories: products (.1.318.1) and apcmgmt (.1.318.2). Notice that in the curly braces two values are specified, its parent address followed by its address. So the products identifier is parented by the apc identifier which is parented by the enterprises identifier, so on and so forth. This type of categorization and subcategorizing will typically continue on in the header of the MIB for awhile segmenting the available keys into tight subgroupings. By segmenting values out in this way it makes the available keys easier to navigate.
The real meat of the MIB is in the description of object types. Here's an example of a integer key:
upsBasicOutputStatus OBJECT-TYPE SYNTAX INTEGER { unknown(1), onLine(2), onBattery(3), onSmartBoost(4), timedSleeping(5), softwareBypass(6), off(7), rebooting(8), switchedBypass(9), hardwareFailureBypass(10), sleepingUntilPowerReturn(11), onSmartTrim(12) } ACCESS read-only STATUS mandatory DESCRIPTION "The current state of the UPS. If the UPS is unable to determine the state of the UPS this variable is set to unknown(1)." ::= { upsBasicOutput 1 }
Here is defined the upsBasicOutputStatus key with a return type of INTEGER. The returned integer maps to one of 12 different return values as listed. Notice that in the MIB a description of the key is provided. These descriptions can be extremely useful in determining which objects can best provide the data you want, especially if you don't have MIB documentation supplied by the vendor.
Notice also that the last line of the object type description includes the numeric value 1 with upsBasicOutput as the parent. If we follow this parenting backwards in the MIB we'd find that upsBasicOutput has the value 1 and is parented by upsOutput which has the value 4 and is parented by ups which has a value of 1, which is parented by hardware which has a value of 1, which is parented by products with a value of 1 which is parented by apc with a value of 318, which is parented by enterprises with a value of 1. So, if we put all that mapping together we get a relative address for the key upsBasicOutputStatus of .1.318.1.1.1.4.1.1.0. Remember that the trailing .0 represents the first instance of the key. Applications called MIB Browsers can easily parse a MIB and make navigation much quicker than flipping through the file in vim, but don't be fooled into thinking it's difficult without such a tool.
So, whats really important to notice here is that the MIB is really just providing us with a road map of the OIDs available on the agent we wish to get values from. A MIB describes both where to find a value and what it returns. We can still interface with a device without the MIB, it's just much easier when you get a return of "Up" instead of "1". By leveraging the options of the Net-SNMP CLI tools you can decide just how you wish to return output which will be different if your just using the tool from the command line (where "Up" is preferable) or if your calling the tool from a script (where "1" is preferable).