Oct. 14, 2008, 6:29 a.m.
posted by vendetta
Using Vendor MIBs
Most network device vendors utilize the enterprise MIB object (1.3.6.1.4.1) to add their own device configurations and statistics to augment the standard MIB-II statistics. The IAB assigns child node values to vendors under this object. When writing real-world SNMP network applications, you often have to use enterprise database objects to control network devices and extract useful information.
This section describes how to interpret vendor MIB data and how to create an SNMP program to query information from a network device based on objects from the vendor MIB. This is done using an SNMP application, CiscoRouter, that has come in handy for me as a network administrator. With several Cisco brand routers on the network, it is nice to see how each one is working throughout the day without having to manually Telnet to each router and watch statistics. One useful statistic to monitor on Cisco routers is the CPU utilization. By watching the CPU utilization of a router you can often tell when network segments are being overloaded, or when strange things are happening on the network.
The CiscoRouter program presented in this section sends an SNMP packet to a Cisco router using a Cisco vendor MIB to query the 5-minute CPU utilization average on the router.
The Cisco CPU MIB
The first step to writing the SNMP application is to obtain the vendor’s MIB data for the device you want to monitor.
Fortunately, Cisco offers a large variety of MIB files for all its network devices, freely available to download from ftp://ftp.cisco.com/pub/mibs/v1/. Various MIB categories and devices are defined in specific MIB files. Usually a quick search on the Cisco web page (http:///www.cisco.com) produces the MIB filename that contains the data you are looking for. The MIB information for router CPU utilization is contained in the OLD-CISCO-CPU-MIB.my file, which defines the MIBs used for monitoring CPU statistics on Cisco devices.
| Note |
There is a newer MIB file available to obtain CPU statistics, but this MIB is not guaranteed to be compatible with all of the Cisco router models. The OLD-CISCO-CPU-MIB.my file is usable with all models of Cisco routers. |
The MIB file uses ASN.1 syntax to define each of the separate MIB objects and object identifiers. The top of the MIB file lists each of the high-level objects on which these MIBs are based. Depending on how often you want to monitor CPU utilization on your router, you can use one of three MIB objects, shown in Figure.
| Note |
Some vendor MIBs (such as Cisco) employ a Unix text format rather than a DOS text format. So each line ends in only a linefeed character instead of both a carriage control and a linefeed. This will make the text look odd if you’re viewing it with Notepad. You can correct it by using an advanced editor such as Microsoft Word to view the MIB. |
|
MIB Object |
Description |
|---|---|
|
busyPer |
The 5-second CPU utilization average |
|
avgbusy1 |
The 1-minute CPU utilization average |
|
avgbusy5 |
The 5-minute CPU utilization average |
Each MIB object has its own unique object identifier to use to obtain the values stored in the device database. The ASN.1 definitions of the objects show the node value for the object, but not the whole object identifier to use. Listing 12.4 shows the three MIB values that can be used.
busyPer OBJECT-TYPE
SYNTAX INTEGER
ACCESS read-only
STATUS mandatory
DESCRIPTION
"CPU busy percentage in the last 5 second
period. Not the last 5 realtime seconds but
the last 5 second period in the scheduler."
::= { lcpu 56 }
avgBusy1 OBJECT-TYPE
SYNTAX INTEGER
ACCESS read-only
STATUS mandatory
DESCRIPTION
"1 minute exponentially-decayed moving
average of the CPU busy percentage."
::= { lcpu 57 }
avgBusy5 OBJECT-TYPE
SYNTAX INTEGER
ACCESS read-only
STATUS mandatory
DESCRIPTION
"5 minute exponentially-decayed moving
average of the CPU busy percentage."
::= { lcpu 58 }
The ASN.1 notation defines five separate values:
-
The datatype (called SYNTAX)
-
The access mode
-
Whether the object is optional or mandatory in each device
-
A text description of the object
-
The ASN.1 definition of the object identifier
The MIB indicates that the avgBusy5 object has a node value of 58 and is a child node of the lcpu object. This in itself does not give you enough information to define the object identifier for the object. You must do some legwork to determine the complete object identifier.
To find the complete object identifier for the object, you must backtrack through the MIBs to find each object’s identifier in the chain. The lcpu object is defined in the same MIB file. It is defined as follows:
lcpu OBJECT IDENTIFIER ::= { local 1 }
The lcpu object is defined as node 1 under the local object. So now you at least know that the avgBusy5 object identifier ends with 1.58.
Unfortunately, the local object is not defined in this MIB file. However, in the comments of the MIB file you see that the local object is referenced as coming from the CISCO-SMI MIB file. To find the rest of the MIB object identifier, you must also download the CISCO-SMI-V1SMI.my MIB file from the Cisco ftp site. In that MIB file, the local object is defined as follows:
local OBJECT IDENTIFIER ::= { cisco 2 }
The local object is child node 2 under the cisco object.
The cisco object is also defined in the same MIB file as follows:
cisco OBJECT IDENTIFIER ::= { enterprises 9 }
OK, now you’re getting somewhere. The cisco object is child node 9 under the enterprises object. The enterprises object is one of the standard MIB objects, with an object identifier of 1.3.6.1.4.1.
Putting all of the pieces together, the whole object identifier for the avgBusy5 object instance is 1.3.6.1.4.1.9.2.1.58.0. Now that you know what MIB object to query, you can write an SNMP program to query the router for the avgBusy5 MIB object at 5-minute intervals.
The CiscoRouter Program
The CiscoRouter.cs program shown in Listing 12.5 uses the avgBusy5 MIB object to get the 5-minute CPU utilization average for a router. The value is retrieved every five minutes, allowing you to see the router CPU utilization over a period of time. The program displays the information in a window and also logs the information in a log file for future reference.
using System;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Windows.Forms;
class CiscoRouter Form
{
private TextBox host;
private TextBox community;
private ListBox results;
private Thread monitor;
private FileStream fs;
private StreamWriter sw;
public CiscoRouter()
{
Text = "Cisco Router Utilization";
Size = new Size(400, 380);
Label label1 = new Label();
label1.Parent = this;
label1.Text = "Host:";
label1.AutoSize = true;
label1.Location = new Point(10, 30);
host = new TextBox();
host.Parent = this;
host.Size = new Size(170, 2 * Font.Height);
host.Location = new Point(40, 27);
Label label2 = new Label();
label2.Parent = this;
label2.Text = "Community:";
label2.AutoSize = true;
label2.Location = new Point(10, 60);
community = new TextBox();
community.Parent = this;
community.Size = new Size(170, 2 * Font.Height);
community.Location = new Point(75, 57);
results = new ListBox();
results.Parent = this;
results.Location = new Point(10, 85);
results.Size = new Size(360, 18 * Font.Height);
Button start = new Button();
start.Parent = this;
start.Text = "Start";
start.Location = new Point(250, 52);
start.Size = new Size(5 * Font.Height, 2 * Font.Height);
start.Click += new EventHandler(ButtonStartOnClick);
Button stop = new Button();
stop.Parent = this;
stop.Text = "Stop";
stop.Location = new Point(320, 52);
stop.Size = new Size(5 * Font.Height, 2 * Font.Height);
stop.Click += new EventHandler(ButtonStopOnClick);
}
void ButtonStartOnClick(Object obj, EventArgs ea)
{
monitor = new Thread(new ThreadStart(checkRouter));
monitor.IsBackground = true;
monitor.Start();
}
void ButtonStopOnClick(Object obj, EventArgs ea)
{
monitor.Abort();
sw.Close();
fs.Close();
}
void checkRouter()
{
int commlength, miblength, datastart, cpuUtil;
SNMP conn = new SNMP();
byte[] response = new byte[1024];
DateTime time;
string logFile = "routerlog.txt";
fs = new FileStream(logFile, FileMode.OpenOrCreate,
FileAccess.ReadWrite);
sw = new StreamWriter(fs);
while (true)
{
response = conn.get("get", host.Text,
community.Text, "1.3.6.1.4.1.9.2.1.58.0");
if (response[0] == 0xff)
{
results.Items.Add("No reponse from host");
sw.WriteLine("No response from host");
sw.Flush();
break;
}
commlength = Convert.ToInt16(response[6]);
miblength = Convert.ToInt16(response[23 + commlength]);
datastart = 26 + commlength + miblength;
cpuUtil = Convert.ToInt16(response[datastart]);
time = DateTime.Now;
results.Items.Add(time + " CPU Utilization: " + cpuUtil + "%");
sw.WriteLine("{0} CPU Utilization: {1}%", time, cpuUtil);
sw.Flush();
Thread.Sleep(5 * 60000);
}
}
public static void Main()
{
Application.Run(new CiscoRouter());
}
}
The CiscoRouter program uses two TextBox objects to allow the customer to enter the hostname (or address) of the remote device and an appropriate community name for read-only access. After the information is entered, the Start button is pressed. Next, a new Thread object is created, which creates the SNMP object and creates the SNMP packet with the avgBusy5 object identifier. The returned packet contains the CPU utilization value. Because this value will never be above 100, you know that it will be contained in a single byte in the SNMP packet and can be converted to an integer value. The current date and time, along with the CPU utilization value, are then displayed in the ListBox and written to the log file. Figure shows a sample running of the CiscoRouter application.
