#!/usr/bin/perl -w

################################################
#
# Checks the net-stat (only for status).
#   - warning/critical state only for to much percent of errs or drop packages
#   - unknown is for unknown device
#
# Thomas Otto <thomas.otto@uni-jena.de> 2010
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#
# Changelog:
# v1.1  2015.05.27 (to) 
#   * change charset for devnames (i.e. 'eth0.32')
# v1.0  2011.05.20 (ts) 
#   * add errors and drops in perfdata
#   * rewrite with Getopt::Long
# v0.9  2010.10.22 (ts)
#
####


use strict;
use warnings;
use Getopt::Long;    # libgetopt-mixed-perl perl-Getopt-Mixed


our %ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);
our %opts = (
  help          => 0,
  warning       => 10,
  critical      => 80,
  with_errors   => 0,
  proc_net_file => "/proc/net/dev",
  alldevs       => 0,
);


sub print_exit($$);
sub start_stuff();
sub stat_net($);


my $devices = start_stuff();
stat_net($devices);



#####################################################

### Start Stuff (Get Options ... )
sub start_stuff()
{

  my %devs = ();
  
  ## get options
  Getopt::Long::Configure("no_ignore_case");
  Getopt::Long::GetOptions( \%opts, 
    'help|h',
    'warning|w=i',
    'critical|c=i',
    'with_errors|with-errors|e',
    ) or $opts{help}=1;


  ## checks:
  #$opts{help} = 1 if ( scalar @ARGV != 1 );
  $opts{help} = 1 if $opts{warning} < 0  or $opts{warning} > 100;
  $opts{help} = 1 if $opts{critical} < 0 or $opts{critical} > 100;
  $opts{help} = 1 if $opts{warning} > $opts{critical};
  
  ## Devices:
  foreach my $k ( @ARGV ) {
    $devs{$k}=0;
  }
  $opts{alldevs} = 1 if (keys %devs == 0 );

  ## Usage:
  if ( $opts{help} )  {
    my $usage = "Get statistic counters for network interfaces

Usage: $0 [Options]* [devices]*
Options:
     -h, --help            print this help message
     -w, --warning=<int>   warning level in percent (Default: '$opts{warning}')
     -c, --critical=<int>  critical level in percent (Default: '$opts{critical}')
     -e, --with-errors     add errors and drops in perfdata
";
    print_exit("$usage\n",$ERRORS{'UNKNOWN'});
  }

  return \%devs;
}


## Check Statistics
sub stat_net($) {
  my %devs = %{ ( shift ) };

  my $return_txt='';
  my $perfdata='';
  my $status = 'OK';

  ## read file
  open FILE,"<$opts{proc_net_file}" or 
    print_exit("Error: Can't open file $opts{proc_net_file}: $!\n",$ERRORS{'UNKNOWN'});
  while(<FILE>) {
    chomp $_;
    if ($_ =~ /^\s*([\w\.]+):(.*)$/){
      my $key = lc $1;
      if(( $opts{alldevs} )or( exists $devs{$key} )) {
        $devs{$key}=$2;
      }
    }
  }
  close FILE;

  ## check devs
  foreach my $k ( sort keys %devs ) {

    if ( $devs{$k} eq "0" ) { 
      $status = 'UNKNOWN'; 
      $return_txt .= "$k=(-/-), ";
      next; 
    }
    
    #Receive:  bytes    packets errs drop fifo frame compressed multicast 
    #Transmit: bytes    packets errs drop fifo colls carrier compressed
    my @val = split " ",$devs{$k};
    my $rx = $val[0];
    my $tx = $val[8];
    my $rx_errs = $val[2];
    my $rx_drop = $val[3];
    my $tx_errs = $val[10];
    my $tx_drop = $val[11];

    $perfdata .= "${k}_in=${rx}c; "; #In Bytes (Counter)
    $perfdata .= "${k}_out=${tx}c; "; #Out Bytes (Counter)

    if ( $opts{with_errors} ) {
      $perfdata .= "${k}_in_err=${rx_errs}c; "; #Out Bytes (Counter)
      $perfdata .= "${k}_in_drop=${rx_drop}c; "; #Out Bytes (Counter)
      $perfdata .= "${k}_out_err=${tx_errs}c; "; #Out Bytes (Counter)
      $perfdata .= "${k}_out_drop=${tx_drop}c; "; #Out Bytes (Counter)
    }

    ## calculate dops and errors to percent
    if ( ( ($val[2]+$val[3]) * 100   > $opts{warning} * $rx ) or 
         ( ($val[10]+$val[11]) * 100 > $opts{warning} * $tx ) ) {
       if ( $ERRORS{$status} < $ERRORS{'WARNING'} ) { $status ='WARNING'; }
    }

    my $rx_unit = "B";
    if ( $rx > 1024 * 4 ) { $rx /= 1024; $rx_unit="kB"; }
    if ( $rx > 1024 * 4 ) { $rx /= 1024; $rx_unit="MB"; }
    if ( $rx > 1024 * 4 ) { $rx /= 1024; $rx_unit="GB"; }
    if ( $rx > 1024 * 4 ) { $rx /= 1024; $rx_unit="TB"; }

    my $tx_unit = "B";
    if ( $tx > 1024 * 4 ) { $tx /= 1024; $tx_unit="kB"; }
    if ( $tx > 1024 * 4 ) { $tx /= 1024; $tx_unit="MB"; }
    if ( $tx > 1024 * 4 ) { $tx /= 1024; $tx_unit="GB"; }
    if ( $tx > 1024 * 4 ) { $tx /= 1024; $tx_unit="TB"; }
    
    $return_txt .= sprintf "$k=(%.1f$rx_unit/%.1f$tx_unit), ",$rx,$tx;
    
  }             
                
  $return_txt =~ s/, $//;
  $return_txt = "NET $status - (Rx/Tx) $return_txt|$perfdata\n";
  print_exit($return_txt,$ERRORS{$status});

}


## Print output and exit with error code
sub print_exit($$) {
  my $msg = shift;
  my $return_code = shift;

  print "$msg";
  exit $return_code;
}




__END__


