#!/opt/vdops/bin/perl # This script queries PRI-related parameters from IF-MIB, DS1-MIB, and # ISDN-MIB and produces a report # # V Who When What # --------------------------------------------------------------------------- # 1.2.0 skendric 2011-02-21 Upgrade to Netops 1.4.0 # 1.1.0 skendric 2010-04-15 Upgrade to perl 5.10.1 # 1.0.1 skendric 2009-05-21 Support SNMP.pm # 1.0.0 skendric 2008-02-17 First Version # # # Author: Stuart Kendrick, sbk {put at sign here} skendric {put dot here} com # # Source: http://www.skendric.com/device # # This software is available under the GNU GENERAL PUBLIC LICENSE, see # http://www.fsf.org/licenses/gpl.html # # # This script takes the following approach: # -Parses the hosts table for a list of targets (or accepts a command- # line list) # -Queries a bunch of CISCO specific variables # -Produces a report # # # Requirements: # -The target(s) must be pingable # # -The following MIB modules stashed in /opt/vdops/share/snmp/mibs, # or wherever it is that you store MIB modules: # CISCO-PRODUCTS-MIB.my # # -PERL modules: the WI::Netops collection # # # Assumptions: # # # Tested on: # -perl-5.12.2 # -net-snmp-5.6 # # # Instructions: # -Customize the script for your site: find the 'user-configurable # variables' section and modify as appropriate # -Try it out # # # Caveats: # # # Known Bugs: # # # To do: # -Add support for SNMPv3 # # Begin script # Load modules use strict; use warnings; use feature 'say'; use feature 'switch'; use Carp qw(carp cluck croak confess); use Data::Dumper; use English qw( -no_match_vars ); use Getopt::Std; use List::MoreUtils qw(any); use WI::Netops::CiscoTools 1.4.3; use WI::Netops::HostTools 1.0.4; use WI::Netops::IFTools 1.3.1; use WI::Netops::NetopsTools 2.2.3; use WI::Netops::NetopsData 1.4.0; use WI::Netops::PingTools 1.1.7; use WI::Netops::SNMPTools 1.5.3; use WI::Netops::Utilities 1.4.4; # Declare global variables. All hashes keyed by target my %if_info; # Hash of hash refs, keyed by target name # e.g. # %if_info = ( # target1 => { # 1 => { %ifStuff }, # 2 => { %ifStuff }, # 3 => { %ifStuff }, # } # target2 => { # 15 => { %ifStuff }, # 21 => { %ifStuff }, # 33 => { %ifStuff }, # } # ); # # %ifStuff = ( # 'ifDescr' => 'T1 0/0/0', # 'ifType' => 'ds1', # 'ifSpeed' => 'T1', # 'ifAdminStatus => 'up', # 'ifOperStatus => 'up', # 'dsx1LineType' => 'ESF', # 'dsx1LineCoding' => 'B8ZS', # 'dsx1LineStatus' => 'NoAlarm', # 'dsx1TransmitClockSource' => 'loopTiming', # 'dsx1SignalMode' => 'messageOriented', # 'isdnEndpointStatus' => 'inactive', # 'isdnSignalingProtocol' => 'dms100', # 'isdnSignalingStatus' => 'inactive', # }, # target2 => { # 'ifDescr' => 'T1 0/0/0', # 'ifType' => 'ds1', # 'ifSpeed' => 'T1', # 'ifAdminStatus => 'up', # 'ifOperStatus => 'down', # 'dsx1LineType' => 'D4', # 'dsx1LineCoding' => 'B8ZS', # 'dsx1LineStatus' => 'LossOfFrame', # 'dsx1TransmitClockSource' => 'localTiming', # 'dsx1SignalMode' => 'bitRobbed', # 'isdnEndpointStatus' => 'active', # 'isdnSignalingProtocol' => 'ni2', # 'isdnSignalingStatus' => 'active', # }, # ); # Define global variables $program_name = 'wan-circuit-details'; $usage = 'Usage: wan-circuit-details -s {yes|no} [-d {integer}] [-r] [-a | -e {expr} | -f {filename} | target1 target2 target3 ...]'; $version = '1.2.0'; # Define the IANA ifTypes which designate a WAN circuit @wan_if_types = qw/ds1 e1 basicISDN primaryISDN propPointToPointSerial ds3/; # Grab arguments getopts('ad:e:f:rs:', \%option); @target = @ARGV; # Set mode if ($option{r}) { $mode = 'report' } elsif (-t STDIN) { $mode = 'interactive' } else { $mode = 'batch' } ### Begin Main Program ############################################### { check_args(); # Check arguments read_config(); # Read Netops config file compile_mibs(); # Compile MIB files build_target(); # Populate @target target_check(); # Look for errors in @target basic_info(); # Gather information info_before(); # Gather more information sanity_check(); # Check for error conditions print_report(); # Print report } ##### End Main Program ################################################# ######################################################################## # Gather information ... and perform more error checking ######################################################################## sub info_before { # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Gathering more information...'); # Loop through targets, gathering more information TARGET: for my $target (@target) { my (@channels, $vb); say "Processing $target" if $debug; # Find WAN interfaces by walking ifType $vb = snmpWalk( {host => $target, oid => 'ifType'} ); VARBIND: for my $varbind (@$vb) { my ($if_type, $iid); $iid = $varbind->{iid}; $if_type = $varbind->{val}; # If this looks like a WAN interface if ( any { $_ eq $if_type } @wan_if_types ) { say "$if_type looks like a WAN interface" if $debug > 1; # Skip it if it looks like a channel my $if_descr = snmpGet( {host => $target, oid => "$ifDescr_oid.$iid"} ); unless ($if_descr =~ /Signaling/) { if ($if_descr =~ /:/) { say ' This interface belongs to a channel, skip it' if $debug > 1; next VARBIND; } } # Save what I found $if_info{$target}->{$iid}->{'ifType'} = $if_type; $if_info{$target}->{$iid}->{'ifDescr'} = $if_descr; # Debug info say " Found WAN interface '$if_type' at ifIndex $iid" if $debug > 1; } } # Cycle through ifIndex, adding IF-MIB parameters for my $ifIndex (keys %{$if_info{$target}}) { say "Gathering IF-MIB values for ifIndex $ifIndex" if $debug > 1; # Add ifAlias $if_info{$target}->{$ifIndex}->{'ifAlias'} = snmpGet( {host => $target, oid => "ifAlias.$ifIndex"} ); # Add ifName say "Getting ifName.$ifIndex" if $debug > 3; $if_info{$target}->{$ifIndex}->{'ifName'} = snmpGet( {host => $target, oid => "$ifName_oid.$ifIndex"} ); # Add ifSpeed $if_info{$target}->{$ifIndex}->{'ifSpeed'} = snmpGet( {host => $target, oid => "ifSpeed.$ifIndex"} ); # Add ifAdminStatus $if_info{$target}->{$ifIndex}->{'ifAdminStatus'} = snmpGet( {host => $target, oid => "ifAdminStatus.$ifIndex"} ); # Add ifOperStatus $if_info{$target}->{$ifIndex}->{'ifOperStatus'} = snmpGet( {host => $target, oid => "ifOperStatus.$ifIndex"} ); } # End 'supports IF-MIB' # Cycle through ifIndex, adding DS1-MIB parameters for my $ifIndex (keys %{$if_info{$target}}) { my ($ifName, $val); $ifName = $if_info{$target}->{$ifIndex}->{'ifName'}; say " Processing $ifName at iid $ifIndex for DS1-MIB vars" if $debug > 2; # Check for DS1-MIB support by getting dsx1LineIndex.$ifIndex $val = snmpGet( {host => $target, oid => "dsx1LineIndex.$ifIndex"} ); # If this interface supports DS1-MIB, gather parameters if (defined $val and $val ne $EMPTY_STR) { say " Gathering DS1-MIB values for $ifName" if $debug > 1; # Add dsx1LineType $if_info{$target}->{$ifIndex}->{'dsx1LineType'} = snmpGet( {host => $target, oid => "dsx1LineType.$ifIndex"} ); # Add dsx1LineCoding $if_info{$target}->{$ifIndex}->{'dsx1LineCoding'} = snmpGet( {host => $target, oid => "dsx1LineCoding.$ifIndex"} ); # Add dsx1TransmitClockSource $if_info{$target}->{$ifIndex}->{'dsx1TransmitClockSource'} = snmpGet({host=> $target, oid =>"dsx1TransmitClockSource.$ifIndex"}); # Add dsx1SignalMode $if_info{$target}->{$ifIndex}->{'dsx1SignalMode'} = snmpGet( {host => $target, oid => "dsx1SignalMode.$ifIndex"} ); } # End 'supports DS1-MIB' # Fill with dashes and zeros else { my $ifName = $if_info{$target}->{$ifIndex}->{'ifName'}; say " Zeroing DS1-MIB values for $ifName: $ifIndex" if $debug > 1; $if_info{$target}->{$ifIndex}->{'dsx1LineType'} = $DASH; $if_info{$target}->{$ifIndex}->{'dsx1LineCoding'} = $DASH; $if_info{$target}->{$ifIndex}->{'dsx1TransmitClockSource'} = $DASH; $if_info{$target}->{$ifIndex}->{'dsx1SignalMode'} = $DASH; } # End 'Fill with dashes and zeros' } # End DS1-MIB # Cycle through ifIndex, adding ISDN-MIB parameters say 'Testing for ISDN-MIB support' if $debug; my @ifIndex = keys %{$if_info{$target}}; # Work around SNMP.pm bug for my $ifIndex (@ifIndex) { my ($ifName, $vb); $ifName = $if_info{$target}->{$ifIndex}->{'ifName'}; say " Processing $ifName at iid $ifIndex for ISDN-MIB vars" if $debug>2; # Check for ISDN-MIB support by walking isdnSignalingIfIndex.$ifIndex $vb = snmpWalk( {host => $target, oid => 'isdnSignalingIfIndex'} ); # If this target supports ISDN-MIB, gather parameters if (@$vb > 0) { my $isdn_index; say " Gathering ISDN-MIB values for $ifName: $ifIndex" if $debug > 1; # Find isdnSignalingIfIndex $isdn_index = find_isdn_signaling_if_index($target, $ifIndex); $isdn_index = $DASH unless defined $isdn_index; $if_info{$target}->{$ifIndex}->{'isdnSignalingIfIndex'} = $isdn_index; # Add ISDN parameters if ($isdn_index eq $QUERY) { $if_info{$target}->{$ifIndex}->{'isdnSignalingProtocol'} = $DASH; $if_info{$target}->{$ifIndex}->{'isdnSignalingStatus'} = $DASH; $if_info{$target}->{$ifIndex}->{'isdnEndpointStatus'} = $DASH; } else { $if_info{$target}->{$ifIndex}->{'isdnSignalingStatus'} = snmpGet({host=>$target, oid=>"isdnSignalingStatus.$isdn_index"}); $if_info{$target}->{$ifIndex}->{'isdnEndpointStatus'} = snmpGet({host=>$target, oid=>"isdnEndpointStatus.$isdn_index"}); $if_info{$target}->{$ifIndex}->{'isdnSignalingProtocol'} = snmpGet({host=>$target, oid=>"isdnSignalingProtocol.$isdn_index"}); } } # End 'supports ISDN-MIB' # Fill with dashes else { my $ifName = $if_info{$target}->{$ifIndex}->{'ifName'}; say " Zeroing ISDN-MIB values for $ifName: $ifIndex" if $debug > 1; $if_info{$target}->{$ifIndex}->{'isdnSignalingProtocol'} = $DASH; $if_info{$target}->{$ifIndex}->{'isdnSignalingStatus'} = $DASH; $if_info{$target}->{$ifIndex}->{'isdnEndpointStatus'} = $DASH; } } # End ISDN-MIB # Entertain operator print $BANG if $mode eq 'interactive'; } # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Tell the operator what I discovered ######################################################################## sub print_report { my $handle; my $total = @target; my $now = get_now(); # If we are running in test mode, skip this routine unless ($dome) { print_it("Running in test mode, cannot print a meaningful report\n"); return 1; } # Debug trace trace_location('begin') if $debug; # Direct output to screen or to file if ($mode eq 'interactive') { $handle = *STDOUT; } else { open $handle, '>', $report_file or die "Cannot open $report_file: $!\n"; } print {$handle} <{$index}; $ifAdminStatus = $ifStuff->{'ifAdminStatus'}; next INTERFACE if $ifAdminStatus eq 'down'; $alias = $ifStuff->{'ifAlias'}; $alias = $ifStuff->{'ifName'} if $alias eq $EMPTY_STR; $ifSpeed = $ifStuff->{'ifSpeed'}; $ifType = substr($ifStuff->{'ifType'}, 0, 6); $isdn_protocol = substr($ifStuff->{'isdnSignalingProtocol'}, 0, 9); $dsx1_type = substr($ifStuff->{'dsx1LineType'}, 0, 4); $dsx1_code = substr($ifStuff->{'dsx1LineCoding'}, 0, 4); $dsx1_signal = $ifStuff->{'dsx1SignalMode'}; $dsx1_clock = $ifStuff->{'dsx1TransmitClockSource'}; # Mangle into smaller strings $alias = substr($alias, 0, 13); given ($ifType) { when (/prop/) { $ifType = 'prop' } } given ($dsx1_signal) { when ('robbedBit') { $dsx1_signal = 'robBit' } when ('bitOriented') { $dsx1_signal = 'bitOri' } when ('messageOriented') { $dsx1_signal = 'messOr' } } $ifSpeed /= 1000000; $ifSpeed = sprintf('%-7s', $ifSpeed); $dsx1_clock =~ s/Timing//; # Print first line for this target if ($first == 1) { printf {$handle} "%-13s %-6s %-7s %-9s %-4s %-4s %-6s %-7s\n", $alias, $ifType, $ifSpeed, $isdn_protocol, $dsx1_type, $dsx1_code, $dsx1_signal, $dsx1_clock; $first = 0; } # Print subsequent lines for this target else { printf {$handle} " %-13s %-6s %-7s %-9s %-4s %-4s %-6s %-7s\n", $alias, $ifType, $ifSpeed, $isdn_protocol, $dsx1_type, $dsx1_code, $dsx1_signal, $dsx1_clock; } } # End 'Walk interfaces' } # End 'Walk targets' unless ($handle =~ /STDOUT/) { close $handle or warn "Cannot close $report_file: $!\n"; } # Make things look pretty print_it("\n\nEnding $PROGRAM_NAME"); # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Sanity check ######################################################################## sub sanity_check { my @remove; # Debug trace trace_location('begin') if $debug; # Notify operator print_it('Sanity check...'); # Loop through targets, looking for problems TARGET: for my $target (@target) { # If target contains no WAN interfaces, remove it if (keys %{$if_info{$target}} == 0) { say "$target reports no serial interfaces, ignoring" if $debug; push @remove, $target; next TARGET; } # Entertain operator print $BANG if $mode eq 'interactive'; } # Remove entries which failed checks prune_basic(@remove); # Make things look pretty say "\n" if $mode eq 'interactive'; # Debug trace trace_location('end') if $debug; return 1; } ######################################################################## # Output help ######################################################################## sub HELP_MESSAGE { print <