#!/usr/bin/perl use Getopt::Std; use Net::SNMP qw(:snmp); #use Data::Dumper; #------------------------------------------------------------------------------- # Global variable declarations #------------------------------------------------------------------------------- my ( $usage, # Help message $hostname, # Target router $community, # SNMP community (v2c only) $base_oid, # %router_ipsla, # hash of IP SLAs %rttSense, # hash of IP SLA states %rtt_status, # hash of IP SLA statuses @ipsla, # array to temporarily hold the list of IP SLA $message, # the text message to return to Nagios $state # 2=critical, 1=warning, 0=ok, -1=error ); #------------------------------------------------------------------------------- # Global variable initializations #------------------------------------------------------------------------------- $usage = <<"EOF"; usage: $0 [-h] -H -c -i Nagios check for Cisco IP SLAs. Checks for probe status and returns execution time as perf data (multi-line output) [-h] : Print this message [-H] : IP Address or Hostname of the router [-c] : SNMP Community String (default = "public") [-i] : comma-separated list of IP SLA tags (rttMonCtrlAdminTag) as defined by the IOS "ip sla tag" command. (ALL = all IP SLAs configured on the router) [-d] : enable debug output EOF %rttSense = ( "0" => "Other", "1" => "OK", "2" => "Disconnected", "3" => "Over Threshold", "4" => "Time Out", "5" => "Busy", "6" => "Not Connected", "7" => "Dropped", "8" => "Sequence Error", "9" => "Verify Error", "10" => "Application Specific", "11" => "DNS Server Time Out", "12" => "TCP Connect Time Out", "13" => "HTTP Transaction Time Out", "14" => "DNS Query Error", "15" => "HTTP Error", "16" => "Error", ); %rttType = ( "1" => "echo", "2" => "pathEcho", "3" => "fileIO", "4" => "script", "5" => "udpEcho", "6" => "tcpConnect", "7" => "http", "8" => "dns", "9" => "udp-jitter", "10" => "dlsw", "11" => "dhcp", "12" => "ftp", "16" => "icmp-jitter", ); %rttCodec = ( "0" => "", "1" => "g711ulaw ", "2" => "g711alaw ", "3" => "g729a ", ); $state = 0; $base_oid = "0"; $rttMonLatestRttOperSense = "1.3.6.1.4.1.9.9.42.1.2.10.1.2"; $rttMonCtrlAdminTag = "1.3.6.1.4.1.9.9.42.1.2.1.1.3"; $rttMonLatestRttOperCompletionTime = "1.3.6.1.4.1.9.9.42.1.2.10.1.1"; $rttMonCtrlAdminRttType = "1.3.6.1.4.1.9.9.42.1.2.1.1.4"; $rttMonEchoAdminCodecType = "1.3.6.1.4.1.9.9.42.1.2.2.1.27"; #=============================================================================== # Input Phase #=============================================================================== die $usage if (!getopts('hH:c:i:d') || $opt_h); die $usage if (!$opt_H || !$opt_i || $opt_h); $hostname = $opt_H; $community = $opt_c || "public"; #------------------------------------------------------------------------------- # Build a hash of IP SLAs passed as options #------------------------------------------------------------------------------- @ipsla = split(',', $opt_i); foreach my $tag (@ipsla) { my @tmp = split('\%', $tag); push (@{$router_ipsla{$tmp[0]}}, $tmp[1]); } #------------------------------------------------------------------------------- # Open an SNMPv2 session with the router #------------------------------------------------------------------------------- my ($session, $error) = Net::SNMP->session( -version => 'snmpv2c', -nonblocking => 1, -timeout => 2, -hostname => $hostname, -community => $community ); if (!defined($session)) { printf("ERROR: %s.\n", $error); exit (-1); } #------------------------------------------------------------------------------- # Send a bulk request for the rttMonCtrlAdminTag table #------------------------------------------------------------------------------- $base_oid = $rttMonCtrlAdminTag; my $result = $session->get_bulk_request( -callback => [\&table_cb, {}], -maxrepetitions => 20, -varbindlist => [$base_oid] ); if (!defined($result)) { printf("ERROR: %s.\n", $session->error); $session->close; exit (-1); } snmp_dispatcher(); #------------------------------------------------------------------------------- # Send a bulk request for the rttMonLatestRttOperSense table #------------------------------------------------------------------------------- $base_oid = $rttMonLatestRttOperSense; my $result = $session->get_bulk_request( -callback => [\&table_cb, {}], -maxrepetitions => 20, -varbindlist => [$base_oid] ); if (!defined($result)) { printf("ERROR: %s.\n", $session->error); $session->close; exit (-1); } snmp_dispatcher(); #------------------------------------------------------------------------------- # Send a bulk request for the rttMonLatestRttOperCompletionTime table #------------------------------------------------------------------------------- $base_oid = $rttMonLatestRttOperCompletionTime; my $result = $session->get_bulk_request( -callback => [\&table_cb, {}], -maxrepetitions => 20, -varbindlist => [$base_oid] ); if (!defined($result)) { printf("ERROR: %s.\n", $session->error); $session->close; exit (-1); } snmp_dispatcher(); #------------------------------------------------------------------------------- # Send a bulk request for the rttMonCtrlAdminRttType table #------------------------------------------------------------------------------- $base_oid = $rttMonCtrlAdminRttType; my $result = $session->get_bulk_request( -callback => [\&table_cb, {}], -maxrepetitions => 20, -varbindlist => [$base_oid] ); if (!defined($result)) { printf("ERROR: %s.\n", $session->error); $session->close; exit (-1); } snmp_dispatcher(); #------------------------------------------------------------------------------- # Send a bulk request for the rttMonEchoAdminCodecType table #------------------------------------------------------------------------------- $base_oid = $rttMonEchoAdminCodecType; my $result = $session->get_bulk_request( -callback => [\&table_cb, {}], -maxrepetitions => 20, -varbindlist => [$base_oid] ); if (!defined($result)) { printf("ERROR: %s.\n", $session->error); $session->close; exit (-1); } snmp_dispatcher(); #------------------------------------------------------------------------------- # Clean-up and exit. #------------------------------------------------------------------------------- $session->close; #=============================================================================== # Output Phase #=============================================================================== my $state=0; my $long; my $perf; my $short; my $fail; my $total=0; if ($opt_i eq "ALL") { for $index ( sort keys %rtt_status ) { if ( $rtt_status{$index}{status} != 1) { $state=$state + 2; $fail=$fail.$index."#".$rtt_status{$index}{adminTag}." "; }; $long = $long . "\nIP SLA $index # $rtt_status{$index}{adminTag} ( $rtt_status{$index}{rttType} $rtt_status{$index}{codecType}) status: $rtt_status{$index}{statusText}"; $perf = $perf . "$rtt_status{$index}{adminTag}=$rtt_status{$index}{completionTime}\n"; $total = $total + $rtt_status{$index}{completionTime}; } $short = "IP SLA status: OK"; if ( $state > 0 ) { $short = "IP SLA probes $fail have failed: CRITICAL"; $state = 2; } print "$short | Total-Time=$total"; print "$long | $perf"; exit($state); } print "TODO\n"; exit 3; #------------------------------------------------------------------------------- # Subroutine to handle the SNMP responses. #------------------------------------------------------------------------------- sub table_cb { my ($session, $table) = @_; if (!defined($session->var_bind_list)) { printf("ERROR: %s\n", $session->error); } else { #--------------------------------------------------------------- # Loop through each of the OIDs in the response and assign # the key/value pairs to the anonymous hash that is passed # to the callback. Make sure that we are still in the table # before assigning the key/values. #--------------------------------------------------------------- my $next; foreach my $oid (oid_lex_sort(keys(%{$session->var_bind_list}))) { if (!oid_base_match($base_oid, $oid)) { $next = undef; last; } $next = $oid; $table->{$oid} = $session->var_bind_list->{$oid}; } #--------------------------------------------------------------- # If $next is defined we need to send another request # to get more of the table. #--------------------------------------------------------------- if (defined($next)) { $result = $session->get_bulk_request( -callback => [\&table_cb, $table], -maxrepetitions => 10, -varbindlist => [$next] ); if (!defined($result)) { printf("ERROR: %s\n", $session->error); } } else { #------------------------------------------------------- # We are no longer in the table, so print the results. #------------------------------------------------------- my @ipsla; foreach my $oid (oid_lex_sort(keys(%{$table}))) { #----------------------------------------------- # Handle result from rttMonCtrlAdminTag walk #----------------------------------------------- if ($oid =~ /^$rttMonCtrlAdminTag.(\d+)$/) { my $rttIndex = $1; my $myrttMonCtrlAdminTag = $table->{$oid}; if($opt_d) { print "GOT rttIndex $1 for $table->{$oid}\n"; } $rtt_status{$rttIndex}{"adminTag"} = "$table->{$oid}"; next unless defined ($router_ipsla{$myrttMonCtrlAdminTag}); push (@{$router_ipsla{$myrttMonCtrlAdminTag}}, $rttIndex); $rtt_status{$rttIndex}{"status"} = -1; #----------------------------------------------- # Handle result from rttMonLatestRttOperSense walk #----------------------------------------------- } elsif ($oid =~ /^$rttMonLatestRttOperSense.(\d+)$/) { if($opt_d) { print "setting rttMonLatestRttOperSense for $1 to $table->{$oid} ($rttSense{$table->{$oid}})\n"; } my $rttIndex = $1; $rtt_status{$rttIndex}{"status"} = $table->{$oid}; $rtt_status{$rttIndex}{"statusText"} = $rttSense{$table->{$oid}}; #----------------------------------------------- # Handle result from rttMonCtrlAdminRttType walk #----------------------------------------------- } elsif ($oid =~ /^$rttMonCtrlAdminRttType.(\d+)$/) { if($opt_d) { print "setting rttMonCtrlAdminRttType for $1 to $table->{$oid} ($rttType{$table->{$oid}})\n"; } my $rttIndex = $1; $rtt_status{$rttIndex}{"rttType"} = $rttType{$table->{$oid}}; #----------------------------------------------- # Handle result from rttMonEchoAdminCodecType walk #----------------------------------------------- } elsif ($oid =~ /^$rttMonEchoAdminCodecType.(\d+)$/) { if($opt_d) { print "setting rttMonEchoAdminCodecType for $1 to $table->{$oid} ($rttCodec{$table->{$oid}})\n"; } my $rttIndex = $1; $rtt_status{$rttIndex}{"codecType"} = $rttCodec{$table->{$oid}}; #----------------------------------------------- # Handle result from rttMonLatestRttOperCompletionTime walk #----------------------------------------------- } elsif ($oid =~ /^$rttMonLatestRttOperCompletionTime.(\d+)$/) { if($opt_d) { print "setting rttMonLatestRttOperCompletionTime for $1 to $table->{$oid} ($table->{$oid} ms)\n"; } my $rttIndex = $1; $rtt_status{$rttIndex}{"completionTime"} = "$table->{$oid}"; } } } } }