http://www.perlmonks.org?node_id=81871
Category: Networking Code
Author/Contact Info ybiC
Description: Query one or more SNMP-enabled devices for network interface stats.   Written specifically for multi-interface devices like routers and LAN switches, but trivial to adapt for any table-ish SNMP response.

Accepts target device(s) from command-line, and prompts for SNMP RO community string.   Example run+output, and interesting SNMP OIDs at tail of pod.  

Output is (almost) csv.   Still researching methods for better output format. Probably better to use hash of hashes (or maybe hash references) than to munge existing output.

No external libraries needed.   Uses Net::SNMP, Tie::IxHash and Time::localtime CPAN modules.

fingers++ for recent post "Cisco SNMP CDP Poll" that inspired me to dig into this.

Critique and suggestions are both welcome and appreciated.
    cheers,
    Don
    striving toward Perl Adept
    (it's pronounced "why-bick")

Latest update: 2001-05-20 21:10
Added "Related CPAN modules" to pod.
 

#! /usr/bin/perl -w

# netsnmpT.pl
# pod at tail


use strict;
use Tie::IxHash;
use Time::localtime;
use Net::SNMP(qw(snmp_event_loop oid_lex_sort));


# get snmp query targets from command-line
Usage() unless(defined @ARGV);
my @targets = @ARGV;


# set snmp parameters and OID prefixes
# prompt for snmp community string
my %snmp = (
   timeout => 15,
   mgmt    => '1.3.6.1.2.1',
   cisco   => '1.3.6.1.4.1.9',
   );
print("\n Starting $0\n\n Enter RO community string: ");
chomp($snmp{community} = <STDIN>);
print("\n");


# define snmp names+OIDs
# insertion-order retrieval
tie my %oid, "Tie::IxHash";
%oid = (
   ifIndex            => "$snmp{mgmt}.2.2.1.1",
   ifName             => "$snmp{mgmt}.31.1.1.1.1",
   ifAdminStatus      => "$snmp{mgmt}.2.2.1.7",
   ifOperStatus       => "$snmp{mgmt}.2.2.1.8",
   ifLastChange       => "$snmp{mgmt}.2.2.1.9",
   );


# create csv header bar
print("Localdate,Localtime,target,",);
for my $oidDescr(keys %oid) {
   print($oidDescr, ',');
   }
print("\n");


# establish snmp session with each target
for(@targets) {
   ($snmp{session}, $snmp{error}) = Net::SNMP -> session(
      -hostname  => $_,
      -community => $snmp{community},
      -timeout   => $snmp{timeout},
      );
   unless(defined($snmp{session})) {
      printf("\n Error: %s\n", $snmp{error});
      exit 1;
      }

   # (date|time)stamp and target hostname all-on-one-line
   printf("%d-%d-%d,%d:%d:%d,",
      localtime -> mon()+1,
      localtime -> mday(),
      localtime -> year()+1900,
      localtime -> hour(),
      localtime -> min(),
      localtime -> sec(),
      );
   print($snmp{session} -> hostname(), ",\n");

   # per-port table responses one-per-line
   # assign (HoH value or somesuch) instead of print
   #   to facilitate proper csv output
   for (keys %oid) {
      if (defined($snmp{response} = $snmp{session} -> get_table($oid{$
+_}))) {
         for (oid_lex_sort(keys(%{$snmp{response}}))) {
            print($snmp{response} -> {$_}, ",\n");
            }
         } else {
         print($snmp{session} -> error(), ",\n");
         }
      }
   }

print("\n Finished $0\n\n");
exit 0;


######################################################################
+####
sub Usage{
   print(
      "\n",
      "  D'oh - you didn't provide target name(s) or address(es)!\n\n"
+,
      "  Usage: netsnmpT.pl host1ip host2name\n\n",
      "  Net::SNMP       $Net::SNMP::VERSION\n",
      "  Tie::IxHash     $Tie::IxHash::VERSION\n",
      "  Time::localtime $Time::localtime::VERSION\n",
      "  Perl            $]\n",
      "  OS              $^O\n",
      "  Program         $0\n",
      "  \n",
      );
   exit 1;
   }

######################################################################
+####


=head1 Name

 netsnmpT.pl

=head1 Summary

 Usage: netsnmpT.pl host1ip host2name

 Query one or more SNMP-enabled devices for network interface info.

=head1 Tested

 with:
   Perl 5.00503
   Debian 2.2r3
 against:
   Cisco 2514 router
   Catalyst 2924, 2948g Ethernet switches

=head1 Author

 ybiC

=head1 Credits

 Thanks to fingers for help with OIDs
 Derived from Net::SNMP example 'table.pl'
   david.town++ for great docs

=head1 Updates

 2001-05-20  20:50
   Add 'Related CPAN modules' to pod.
   Post to PerlMonks.
   And more OIDs.
   Corrected exit values (success=0).
   s/foreach/for/g and $_
   for loop to print csv header titles.
   Minimal comments.
 2001-05-19   22:55
   Example run at tail of pod.
   Usage() with module+Perl versions.
   Prompt for community string (chomp<STDIN>).
     (avoid showing in process list).
   Targets list from command-line (@ARGV).
   Efforts to normalize data.
   Replace ifDescr with ifXEntry.ifName.
   Add buckets o'OIDs.
   Date+timestamps (Time::localtime).
   List of targets from array (for loop).
 2001-05-18   21:50
   Initial working code.

=head1 Todos

 Munge outfile to proper csv (HoH, hashrefs ?).
 Support string OIDs - on same line as (date|time)stamp and targetname
   another for(key %oid) loop 
 Command-line switch for output file (GetOpt::Long).
 Command-line switch for input file (GetOpt::Long).
 No-echo of RO community string (Term::ReadKey).
 (Sanity|taint)-check RO community string.
 Convert cdp neighbor IP addr from octal to decimal-dq.
   see fingers' SNMP CDP mapper

=head1 Related CPAN modules

 SNMP::MIB::Compiler
 SNMP::BridgeQuery

 SNMP
 SNMP::Util
 SNMP::Monitor

=head1 Online MIB browsers

 http://www.telecomm.uh.edu/stats/rfc/
 http://www.alvestrand.no/objectid/
 http://www.ibr.cs.tu-bs.de/cgi-bin/sbrowser.cgi

=head1 OIDs of interest

 Use per-port table OIDs with this program:
   tcpConnLocalPort   => "$snmp{mgmt}.6.13.1.3",
   udpLocalPort       => "$snmp{mgmt}.7.5.1.2",
   ifIndex            => "$snmp{mgmt}.2.2.1.1",
   ifDescr            => "$snmp{mgmt}.2.2.1.2",
   ifAdminStatus      => "$snmp{mgmt}.2.2.1.7",
   ifOperStatus       => "$snmp{mgmt}.2.2.1.8",
   ifLastChange       => "$snmp{mgmt}.2.2.1.9",
   ifInOctets         => "$snmp{mgmt}.2.2.1.10",
   ifInUcPkts         => "$snmp{mgmt}.2.2.1.11",
   ifInNuPkts         => "$snmp{mgmt}.2.2.1.12",
   ifInDiscards       => "$snmp{mgmt}.2.2.1.13",
   ifInErrors         => "$snmp{mgmt}.2.2.1.14",
   ifOutOctets        => "$snmp{mgmt}.2.2.1.16",
   ifOutUcPkts        => "$snmp{mgmt}.2.2.1.17",
   ifOutNuPkts        => "$snmp{mgmt}.2.2.1.18",
   ifOutDiscards      => "$snmp{mgmt}.2.2.1.19",
   ifOutErrors        => "$snmp{mgmt}.2.2.1.20",
   ifOutQLen          => "$snmp{mgmt}.2.2.1.21",
   ipAdEntAddr        => "$snmp{mgmt}.4.20.1.1",
   ipAdEntNetMask     => "$snmp{mgmt}.4.20.1.3",
   ifName             => "$snmp{mgmt}.31.1.1.1.1",
   ifInMulticastPkts  => "$snmp{mgmt}.31.1.1.1.2",
   ifInBroadcastPkts  => "$snmp{mgmt}.31.1.1.1.3",
   ifOutMulticastPkts => "$snmp{mgmt}.31.1.1.1.4",
   ifOutBroadcastPkts => "$snmp{mgmt}.31.1.1.1.5",
   ifHighSpeed        => "$snmp{mgmt}.31.1.1.1.15",
   stpPortState       => "$snmp{mgmt}.17.2.15.1.3",
   TpFdbAddress       => "$snmp{mgmt}.17.4.3.1.1",
   TpFdbPort          => "$snmp{mgmt}.17.4.3.1.2",
   TpPortInFrames     => "$snmp{mgmt}.17.4.4.1.3",
   TpPortOutFrames    => "$snmp{mgmt}.17.4.4.1.4",
   TpPortInDiscard    => "$snmp{mgmt}.17.4.4.1.5",
   cdpAddr            => "$snmp{cisco}.9.23.1.2.1.1.4",
   cdpDevId           => "$snmp{cisco}.9.23.1.2.1.1.6",
   cdpPlatform        => "$snmp{cisco}.9.23.1.2.1.1.8",

 Don't use string OIDs with this program:
   sysDescr           => "$snmp{mgmt}.1.1",
   sysContact         => "$snmp{mgmt}.1.4",
   sysName            => "$snmp{mgmt}.1.5",
   sysLocation        => "$snmp{mgmt}.1.6",
   sysUpTime          => "$snmp{mgmt}.1.3",
   snmpBadComName     => "$snmp{mgmt}.11.4",
   snmpBadVers        => "$snmp{mgmt}.11.3",
   snmpBadComUse      => "$snmp{mgmt}.11.5",
   snmpSetReqs        => "$snmp{mgmt}.11.17",
   ifNumber           => "$snmp{mgmt}.2.1",

=head1 Example run

 Targets:
   192.168.5.106  Cisco 2514 low-end LAN router
                  2 ethernet interfaces
                  2 serial interfaces
                  1 null interface

   tux            Debian Linux host
                  1 ethernet interface

 ybiC@tux:~$ snmpT.pl 192.168.5.106 tux

  Starting netsnmpT.pl

  Enter RO community string: public

 Localdate,Localtime,target,ifIndex,ifName,ifAdminStatus(1=up),ifOperS
+tatus(2=dn),ifLastChange,
 5-19-2001,22:41:0,192.168.5.106,
 1,
 2,
 3,
 4,
 5,
 Et0,
 Et1,
 Se0,
 Se1,
 Nu0,
 1,
 1,
 2,
 2,
 1,
 1,
 1,
 2,
 2,
 1,
 26.55 seconds,
 26.55 seconds,
 24.67 seconds,
 25.50 seconds,
 0.00 seconds,
 5-19-2001,22:41:2,tux,
 Requested table is empty or does not exist,
 Requested table is empty or does not exist,
 Requested table is empty or does not exist,
 Requested table is empty or does not exist,
 Requested table is empty or does not exist,

  Finished netsnmpT.pl

 ybiC@tux:~$

=cut