Homebrew NMS: Put It Together with Perl and Net::SNMP

By Charlie Schluting | Aug 29, 2007 | Print this Page
http://www.enterprisenetworkingplanet.com/netos/article.php/10951_3697071_2/Homebrew-NMS-Put-It-Together-with-Perl-and-NetSNMP.htm
Charlie Schluting

This week's look at building a homebrew NMS will focus on using SNMP to gather information about your network. Network Management requires SNMP, and you cannot escape the tangle of OID trees. Certain tools do make it easier, and once you learn a bit about them it becomes clear that this SNMP stuff is quite powerful.

Before we explore the Perl module Net::SNMP, let us have a quick refresher on SNMP.

The Simple Network Management Protocol agent listens on UDP port 161 for incoming requests. SNMP traps are sent, without warning, to UDP port 162 on a central management station that is configured to listen for traps. Traps can take the form of "link down," which is normally sent by a network device, or can be as complex as you'd like.

Most SNMP messages are identified by predefined OIDs, or Object identifiers. An OID is simply a series of numbers that identify an SNMP object. OIDs are hierarchical, and organized in a tree structure. Each node on the tree may have multiple branches, and OIDs typically get quite long. Most SNMP OIDs start in the ISO tree's root, which always begin with .1. In fact, most will be .1.3.6.1, which means iso.org.dod.internet. The Internet tree branches into private and mgmt. For example, 1.3.6.1.2.1.1.6.0 means "sysLocation," which can be discovered by walking down the OID tree to discover that the string of numbers actually mean:
iso.org.dod.internet.mgmt.mib-2.system.systemLocation.

The magical goo that defines what those numbers mean is called the Management Information Base, or a MIB. A MIB defines what types are allowed in each object (integer, string), as well as what they are called. A MIB essentially turns numbers into meaningful information, as well as defines allowed values.

Taking SNMP for a Walk

On to the useful stuff. Let's try out an SNMP query, using out old friend snmpwalk, which comes with the net-snmp software on most *nix hosts. The snmpget command is useful to get a single object, but if you want all information available down a certain branch of the tree, snmpwalk will do just that.

% snmpwalk -v2c -c public nermal 1.3.6.1.2.1.1.6
 SNMPv2-MIB::sysLocation.0 = STRING: "System administrators office"

Running snmpwalk on a specific OID, where nothing follows in the tree, is akin to using snmpget. However, if we bump it up a notch, we can get the entire system MIB:

% snmpwalk -v2c -c public nermal 1.3.6.1.2.1.1
 SNMPv2-MIB::sysDescr.0 = STRING: SunOS nermal.domain.com 5.10 Generic_118833-24 sun4u
 SNMPv2-MIB::sysObjectID.0 = OID: NET-SNMP-MIB::netSnmpAgentOIDs.3
 DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (338266757) 39 days, 3:37:47.57
 SNMPv2-MIB::sysContact.0 = STRING: "System administrator"
 …

Experiment with your network gear, and the private, instead of mgmt branch, under Internet to see what's available. In the Cisco MIB, we can get everything we'd ever want to know, including the ARP table, the Bridge table, and MAC address with port locations. Those are all standards-based OIDs, and the interesting Cisco-specific goodies are in the private tree, under 1.3.6.1.4.1.9.

Port numbers are difficult, since Cisco uses an interface identifier and a few layers of indirection to identify a specific port, but it is possible. Let's start off easier. We'll fetch the port descriptions (string assigned to a port) from our Cisco switch, so that we can ensure they are accurate based on our formatting standards and MAC address discovery information.

Put It All Together With Perl

Hopefully we know Perl already. We'll start by finding the OID we want. This is done by examining the MIBs from your switch's vendor, and painstakingly figuring out which object provides the information. Luckily I already know that IF-MIB::ifAlias.22 will give me the description for port alias number 22. Also, this isn't a vendor-specific item.This isn't the normal "Gi2/37" form we're used to, but it can be converted to the friendly string using other objects to dereference the ifAlias number 22.

% snmpwalk -v2c -c public switch_hostname 1.3.6.1.2.1.31.1.1.1.18.22
 IF-MIB::ifAlias.22 = STRING: nermal.domain.com [F324 60-18]

My computer's name is nermal, and ourport descriptions at work include two other pieces of information: the wall jack number, and room number. Now that we know what OID is required, it's time to pull all port descriptions from the entire switch, just: 'snmpwalk 1.3.6.1.2.1.31.1.1.1.18'.

In Perl, we simply need to define our OIDs, and connect to the agent on our Cisco to grab the information. Using the Net::SNMP module is the best way:

#!/usr/bin/perl
use Net::SNMP;
my $desc = '1.3.6.1.2.1.31.1.1.1.18;
($session, $error) = Net::SNMP->session(
                   -hostname => "switch",
                   -community => "public",
                   -timeout  => "30",
                   -port => "161");

if (!defined($session)) {
      printf("ERROR: %s.\n",  $error);
      exit 1;
}
my $response = $session->get_request($desc);
my %pdesc = %{$response};

my $err = $session->error;
if ($err){
   return 1;
}
print %pdesc;
exit 0;

That's all there is to it. Net::SNMP->session() creates an object, which can be used to call the get_table() method. If you want multiple OIDs in the same session, just define them as comma-seperated values, like so: get_request($desc,$uptime,$etc). The get_table() method returns a reference to a hash, by the way.

If you run that snippet of code, you should get a huge jumbled list, which will contain the key-value pairs of the interface alias and the string. It's a hash, so to print it prettily you must reference each entry individually. Most likely you'll be using this data in combination with other data, possibly from a database. You can compare values on-the-fly, in this example, to ensure that the string is correct.

Likely the most common use of Net::SNMP by sysadmins is to poll equipment for temperature, CPU, memory and other data. This functionality is built-in to most monitoring applications, but often times it needs to be told about MIBs for new devices that do not follow standards.

I hope that it's clear how easy it is to fetch this information, once you know the correct OID. It is amazing how useful Net::SNMP becomes once you start using it. You'll want to pull all kinds of tiny nuggets of information from all sorts of SNMP-enabled devices. By all means, gather as much data as you can!

Having the ability to verify a device's configuration, or perhaps configuring the device in real-time, is an admirable goal. Next time we'll talk about using DBD::Pg to store this information or retrieve other information, which, when combined with Net::SNMP, is quite useful for real-time querying of network information.

Previously: Your NMS: Time to Go Homebrew?