#!/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 <hostname> -c <community> -i <ip sla tags>

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] <router>     :       IP Address or Hostname of the router
[-c] <community>  :       SNMP Community String  (default = "public")
[-i] <IP SLA Tags>:       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}";
        }
      }
    }
  }
}
