#!/usr/bin/perl -w
# switchcheck.pl
use strict;
use Net::SNMP;
my($error,$session,$seed_oid,$oid_root,$csvname,$community,$hostname,$
+seed_ip,$serial,$option,$logdir);
my(@unique,@hostname);
my($ifMIB) = "1.3.6.1.2.1.31.1.1.1";
my(%option)=(
verbose => 0,
csv => 0,
log => 0,
batch => 0,
help => 0,
hostname => 0,
read => 0
);
die "\nusage: $0 option ip\n Use $0 -h for list of options\n" unless (
+ @ARGV >= 1 );
$logdir="/var/log/sc";
#Begin processing command line arguments
#***************************************************************
while(@ARGV){
$option = $ARGV[0];
if($option eq "-v"){
$option{'verbose'} = 1;
$option{'log'} = 0;
$option{'read'} = 0;
}
elsif($option eq "-l"){
$option{'log'} = 1;
$option{'verbose'} = 0;
$option{'read'} = 0;
}
elsif($option eq "-r"){
$option{'read'} = 1;
$option{'verbose'} = 0;
$option{'log'} = 0;
}
elsif($option eq "-b"){
$option{'batch'} = 1;
$community = $ARGV[1];
shift @ARGV;
}
elsif($option eq "-h"){
$option{'help'} = 1;
die "\n\n usage: $0 options ip ... \n\n
-h This help message
-l Logging
-v Verbose
-c filename Send output to filename.csv
-b community Batch, community is the snmp community name
-r ip ... Display results from log files for specified IPs\
+n\n\n";
}
elsif($option eq "-c"){
$option{'csv'} = 1;
$option{'read'} = 0;
$option{'log'} = 0;
$csvname = ("$ARGV[1]".".csv");
shift @ARGV;
}
else{
die "usage: $0 ip\n" unless ($option =~ m{\d+\.\d+\.\d+\.\d+})
+;
push @hostname , $option;
$option{'hostname'} = 1;
}
shift @ARGV;
}
die "You need to give at least one IP address as an option\n" unless($
+option{'hostname'});
#End argument processing
#*************************************************************
#Prompt for SNMP community string
unless($option{'batch'}){
print "community: ";
chomp($community = <STDIN>);
}
$oid_root = "1.3.6.1.2.1.2.2.1";
$seed_oid = ("$oid_root".".1");
unless($option{'csv'}){
foreach(@hostname){
undef @unique;
$hostname=$_;
#Open SNMP session
($session,$error) = Net::SNMP->session(Hostname => $hostname, Comm
+unity => $community);
die "$error\n" unless($session);
get_oids($seed_oid); #Get the SNMP info for this target
if($option{'verbose'}){
print "Port Speed Errors/Data In
+ Errors/Data Out Uptime \n";
print "---------------------------------------------------
+---------------------------------------------------------------------
+-----\n";
SNMP_Grocery_List();
}
elsif($option{'log'}){
SNMP_Logging();
}
elsif($option{'read'}){
Read_Log();
}
else{
SNMP_Light();
}
$session->close;
}
}
if($option{'csv'}){
open(CSV,">$csvname")|| die "Can't open $csvname\n";
if($option{'verbose'}){
print CSV "Name,Speed,Errors_In,Data_in,Errors_out,Data_ou
+t,Uptime,Switch_IP\n";
foreach(@hostname){
undef @unique;
$hostname=$_;
#Open SNMP session
($session,$error) = Net::SNMP->session(Hostname => $ho
+stname, Community => $community);
die "$error\n" unless($session);
get_oids($seed_oid); #Get the SNMP info for this targe
+t
Make_CSV_Verbose();
}
$session->close;
}
else{
print CSV "Switch_IP,Name,Total_Ports,Up,Down,Admin_Down\n";
foreach(@hostname){
undef @unique;
$hostname=$_;
#Open SNMP session
($session,$error) = Net::SNMP->session(Hostname => $ho
+stname, Community => $community);
die "$error\n" unless($session);
get_oids($seed_oid); #Get the SNMP info for this targe
+t
Make_CSV();
$session->close;
}
}
close(CSV) || die "Can't close $csvname\n";
}
#Subs below here
#*********************************************************************
+******
#This sub is what walks through and enumerates an oid tree
#*********************************************************************
+******
sub get_oids{
my($starting_oid , $new_oid , $unique_oid , $result , $crap);
$starting_oid = $_[0];
$new_oid = $starting_oid ;
while(Net::SNMP::oid_context_match($starting_oid,$new_oid)){
$result = $session->get_next_request(($new_oid));
return unless (defined $result);
($new_oid , $crap) = %$result;
if (Net::SNMP::oid_context_match($starting_oid,$new_oid)){
$unique_oid = $new_oid;
$unique_oid =~ s/$starting_oid//g;
push @unique , $unique_oid ;
get_oids($new_oid);
}
}
#This is the sub for -v option
#*********************************************************************
+******
sub SNMP_Grocery_List{
my($unique , $oper , $admin , $name , $uptime , $speed , $data
+in , $dataout , $errorsin , $errorsout);
my(%tally);
%tally=(
total => 0,
up => 0,
down => 0,
admin => 0
);
foreach(@unique){
$unique = $_ ;
$tally{'total'}++;
$oper = (Get_SNMP_Info("$oid_root".".8"."$unique"));
if($oper == 1){
$tally{'up'}++;
$name = (Get_SNMP_Info("$ifMIB".".1"."$unique"));
$uptime = (Get_SNMP_Info("$oid_root".".9"."$unique"));
$speed = (Get_SNMP_Info("$ifMIB".".15"."$unique"));
$datain = (Get_SNMP_Info("$oid_root".".10"."$unique"))
+;
$dataout = (Get_SNMP_Info("$oid_root".".16"."$unique")
+);
$errorsin = (Get_SNMP_Info("$oid_root".".14"."$unique"
+));
$errorsout = (Get_SNMP_Info("$oid_root".".20"."$unique
+"));
$~="GROCERY";
write;
}
else {
$tally{'down'}++;
$admin = (Get_SNMP_Info("$oid_root".".7"."$unique"));
if($admin == 2){
$tally{'admin'}++;
}
}
}
print "\nSummary: $hostname \n Total Ports: $tally{'total'} \n
+ Ports Up: $tally{'up'} \n Ports Down: $tally{'down'} \n Admin Down $
+tally{'admin'} \n";
format GROCERY =
@<<<<<<<<<< @<<<<<< @>>>>>>>>>>>>>>>>>/@<<<<<<<<<<<<<<<<< @>>>>>>>>>
+>>>>>>>>/@<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+<<<<<<<
$name,$speed,$errorsin,$datain,$errorsout,$dataout,$uptime
.
}
# Sub for -l option
#*********************************************************************
+******
sub SNMP_Logging{
my($unique , $oper , $dbm);
my(%log);
$dbm=("$logdir"."sc"."$hostname");
dbmopen(%log, $dbm, 0644);
foreach(@unique){
$unique = $_ ;
$oper = (Get_SNMP_Info("$oid_root".".8"."$unique"));
if($oper == 1){
$log{$unique}++;
}
}
dbmclose(%log);
}
#Sub for -r option
#*********************************************************************
+******
sub Read_Log{
my($dbm,$name,$uptime,$unique,$counter);
my(%log);
$dbm=("$logdir"."sc"."$hostname");
dbmopen(%log, $dbm, 0644);
print "\n\n Switch Check Log for $hostname\n";
print "---------------------------------------------------\n";
while (($unique, $counter) = each(%log)) {
$name = (Get_SNMP_Info("$ifMIB".".1"."$unique"));
$uptime = (Get_SNMP_Info("$oid_root".".9"."$unique"));
$~="READ_LOG";
write;
}
dbmclose(%log);
format READ_LOG =
@<<<<<<<<<<<<<< @<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+<<<<<<<
$name,$counter,$uptime
.
}
#sub for default operation
#*********************************************************************
+******
sub SNMP_Light{
my($unique , $oper , $admin);
my(%tally);
%tally=(
total => 0,
up => 0,
down => 0,
admin => 0
);
foreach(@unique){
$unique = $_ ;
$tally{'total'}++;
$oper = (Get_SNMP_Info("$oid_root".".8"."$unique"));
if($oper == 1){
$tally{'up'}++;
}
else {
$tally{'down'}++;
$admin = (Get_SNMP_Info("$oid_root".".7"."$unique"));
if($admin == 2){
$tally{'admin'}++;
}
}
}
print "\nSummary: $hostname \n Total Ports: $tally{'total'} \n
+ Ports Up: $tally{'up'} \n Ports Down: $tally{'down'} \n Admin Down $
+tally{'admin'} \n";
}
#Sub that acually gets the value for a oid
#*********************************************************************
+******
sub Get_SNMP_Info{ #This sub gets the value of an oid
my($crap , $value , $result);
my($oid) = $_[0];
$result = $session->get_request("$oid");
return unless (defined $result);
($crap , $value) = %$result;
return $value;
}
#sub for -c and -v
#*********************************************************************
+******
sub Make_CSV_Verbose{
my($unique , $oper , $admin , $name , $uptime , $speed , $data
+in , $dataout , $errorsin , $errorsout);
foreach(@unique){
$unique = $_ ;
$oper = (Get_SNMP_Info("$oid_root".".8"."$unique"));
$name = (Get_SNMP_Info("$ifMIB".".1"."$unique"));
$uptime = (Get_SNMP_Info("$oid_root".".9"."$unique"));
$speed = (Get_SNMP_Info("$ifMIB".".15"."$unique"));
$datain = (Get_SNMP_Info("$oid_root".".10"."$unique"));
$dataout = (Get_SNMP_Info("$oid_root".".16"."$unique"));
$errorsin = (Get_SNMP_Info("$oid_root".".14"."$unique"));
$errorsout = (Get_SNMP_Info("$oid_root".".20"."$unique"));
print CSV "$name,$speed,$errorsin,$datain,$errorsout,$data
+out,$uptime,$hostname\n";
}
}
#sub for -c
#*********************************************************************
+******
sub Make_CSV{
my($unique, $sysname , $oper , $admin);
my(%tally);
%tally=(
total => 0,
up => 0,
down => 0,
admin => 0
);
$sysname = (Get_SNMP_Info("1.3.6.1.2.1.1.5.0"));
foreach(@unique){
$unique = $_ ;
$tally{'total'}++;
$oper = (Get_SNMP_Info("$oid_root".".8"."$unique"));
if($oper == 1){
$tally{'up'}++;
}
else {
$tally{'down'}++;
$admin = (Get_SNMP_Info("$oid_root".".7"."$unique"));
if($admin == 2){
$tally{'admin'}++;
}
}
}
print CSV "$hostname,$sysname,$tally{'total'},$tally{'up'},$ta
+lly{'down'},$tally{'admin'}\n";
}
#*********************************************************************
+******
}
=head1 Name
switchcheck.pl
=head1 Summary
Usage: switchcheck.pl options ip { ip ip ... }
Designed to get an overview or collect statisics on switchports usage
+ using SNMP.
-b option allows you to specify community name on the command line to
+ allow being called in a cron job
-l logs basic port usage stats to a dbm file
-r is used to read files created by -l
-v gives more detailed stats on ports that are up
-c generates a csv file, can be used in conjunction with -v
Some options are mutually exclusive. The later option takes precedenc
+e.
=head1 Tested
with:
Perl 5.6.1
RedHat 7.1
against:
Cisco 6509,2924XL,3508XL,3512XL,3524XL,3548XL switches
=head1 Author
fingers
=head1 Credits
Thanks to ybic for answering dumb perl questions and appreciating poo
+rly written code
=head1 Caveats
When looking at the port counts it is important to keep in mind that
+vlans and other "interfaces" show up in this count.
Look at the output from -v for each type of switch you are using to g
+et an idea how many non-port interfaces each switch has.
=head1 Todos
Add in -i option to add a polling interval, to spread out the bandwi
+dth impacts of running against remote equipment.
Accept multiple RO strings for use in enviroments where switches may
+ have different community names.
Add in VLAN and MAC information to the -v reports. So far I haven't
+been able to identify the oids to use for these.
Add in support to log to a real database instead of dbm.
=head1 Updates
2001-07-19 Post to perlmonks
=cut
|