Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

switchcheck.pl

by fingers (Acolyte)
on Jul 19, 2001 at 22:13 UTC ( #98175=sourcecode: print w/ replies, xml ) Need Help??

Category: Networking Code
Author/Contact Info fingers
Description: 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 precedence.
Tested
with:
Perl 5.6.1
RedHat 7.1
against:
Cisco 6509,2924XL,3508XL,3512XL,3524XL,3548XL switches
I realize it may be a little sloppy and amateur, I definately would appreciate any constructive criticism anyone has about my code.
#!/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

Comment on switchcheck.pl
Download Code
Re: switchcheck.pl (Getopt, $_, nonport interfaces)
by ybiC (Prior) on Jul 24, 2001 at 06:01 UTC
        Hi fingers,
    First off - good job for using Net::Snmp!   I used UCD SNMP for a similar script because of the included additional utilities, but in hindsight wish I'd done like you.

    A couple of trivial suggestions come to mind:

    • Getopt::Long might simplify processing of command-line arguments.
    • If you're going to use $hostname instead of $_ in
      foreach(@hostname){ undef @unique; $hostname=$_;
      it could be a tiny bit cleaner as
      foreach $hostname(@hostname){ undef @unique;
    • I don't know how well the particular syntax would transfer to your code, but "(code) mind your snmPs & Qs" uses a hash to count non-port interfaces, then subtracts them from final port status report.   As you note, it reaaally improves accuracy of generated reports.
    BTW, thanks for the compliment in your pod.   I "appreciate poorly written code" because I'm so well practiced at *writing* it! 8^D
        cheers,
        Don
        striving toward Perl Adept
        (it's pronounced "why-bick")
Re: switchcheck.pl
by Anonymous Monk on Jun 18, 2002 at 19:44 UTC

Back to Code Catacombs

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: sourcecode [id://98175]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (5)
As of 2015-03-29 11:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    When putting a smiley right before a closing parenthesis, do you:









    Results (630 votes), past polls