#!/usr/bin/perl -w ############################## check_snmp_int ############## my $VERSION = "2.1.0"; # Date : Oct 10 2007 # Author : Patrick Proy ( patrick at proy.org ) # Help : http://nagios.manubulon.com # License : GPL - http://www.fsf.org/licenses/gpl.txt # Contrib : J. Jungmann, S. Probst, R. Leroy, M. Berger # TODO : # Maybe put base directory for performance as an option ################################################################# # # Help : ./check_snmp_int.pl -h # use strict; use Net::SNMP; use Getopt::Long; ############### BASE DIRECTORY FOR TEMP FILE ######## my $o_base_dir = "/tmp/tmp_Icinga_int."; my $file_history = 200; # number of data to keep in files. # Icinga specific my %ERRORS = ('OK' => 0, 'WARNING' => 1, 'CRITICAL' => 2, 'UNKNOWN' => 3, 'DEPENDENT' => 4); # split big SNMP requests to smaller ones my $snmp_splice_size = 50; # SNMP Datas my $inter_table = '.1.3.6.1.2.1.2.2.1'; my $index_table = '1.3.6.1.2.1.2.2.1.1'; my $descr_table = '1.3.6.1.2.1.2.2.1.2'; my $name_table = '1.3.6.1.2.1.31.1.1.1.1'; my $alias_table = '.1.3.6.1.2.1.31.1.1.1.18'; my $oper_table = '1.3.6.1.2.1.2.2.1.8.'; my $admin_table = '1.3.6.1.2.1.2.2.1.7.'; my $speed_table = '1.3.6.1.2.1.2.2.1.5.'; my $speed_table_64 = '1.3.6.1.2.1.31.1.1.1.15.'; my $in_octet_table = '1.3.6.1.2.1.2.2.1.10.'; my $in_octet_table_64 = '1.3.6.1.2.1.31.1.1.1.6.'; my $in_error_table = '1.3.6.1.2.1.2.2.1.14.'; my $in_discard_table = '1.3.6.1.2.1.2.2.1.13.'; my $out_octet_table = '1.3.6.1.2.1.2.2.1.16.'; my $out_octet_table_64 = '1.3.6.1.2.1.31.1.1.1.10.'; my $out_error_table = '1.3.6.1.2.1.2.2.1.20.'; my $out_discard_table = '1.3.6.1.2.1.2.2.1.19.'; my %status = ( 1 => 'UP', 2 => 'DOWN', 3 => 'TESTING', 4 => 'UNKNOWN', 5 => 'DORMANT', 6 => 'NotPresent', 7 => 'lowerLayerDown' ); # Globals # Standard options my $o_host = undef; # hostname my $o_port = 161; # port my $o_descr = undef; # description filter my $o_help = undef; # wan't some help ? my $o_admin = undef; # admin status instead of oper my $o_inverse = undef; # Critical when up my $o_dormant = undef; # Dormant state is OK my $o_down = undef; # Down state is OK my $o_verb = undef; # verbose mode my $o_version = undef; # print version my $o_noreg = undef; # Do not use Regexp for name my $o_short = undef; # set maximum of n chars to be displayed my $o_label = undef; # add label before speed (in, out, etc...). my $o_weather = undef; # output "weathermap" data for NagVis # Performance data options my $o_perf = undef; # Output performance data my $o_perfe = undef; # Output discard/error also in perf data my $o_perfs = undef; # include speed in performance output (-S) my $o_perfp = undef; # output performance data in % of max speed (-y) my $o_perfr = undef; # output performance data in bits/s or Bytes/s (-Y) # Speed/error checks my $o_checkperf = undef; # checks in/out/err/disc values my $o_delta = 300; # delta of time of perfcheck (default 5min) my $o_ext_checkperf = undef; # extended perf checks (+error+discard) my $o_warn_opt = undef; # warning options my $o_crit_opt = undef; # critical options my $o_kbits = undef; # Warn and critical in Kbits instead of KBytes my @o_warn = undef; # warning levels of perfcheck my @o_crit = undef; # critical levels of perfcheck my $o_highperf = undef; # Use 64 bits counters my $o_meg = undef; # output in MBytes or Mbits (-M) my $o_gig = undef; # output in GBytes or Gbits (-G) my $o_prct = undef; # output in % of max speed (-u) my $o_use_ifname = undef; # use IF-MIB::ifName instead of IF-MIB::ifDescr my $o_use_ifalias = undef; # use IF-MIB::ifAlias instead of IF-MIB::ifDescr my $o_timeout = undef; # Timeout (Default 5) # SNMP Message size parameter (Makina Corpus contrib) my $o_octetlength = undef; # Login options specific my $o_community = undef; # community my $o_version2 = undef; #use snmp v2c my $o_login = undef; # Login for snmpv3 my $o_passwd = undef; # Pass for snmpv3 my $v3protocols = undef; # V3 protocol list. my $o_authproto = 'md5'; # Auth protocol my $o_privproto = 'des'; # Priv protocol my $o_privpass = undef; # priv password # Readable names for counters (M. Berger contrib) my @countername = ("in=", "out=", "errors-in=", "errors-out=", "discard-in=", "discard-out="); my $checkperf_out_desc; # functions sub read_file { # Input : File, items_number # Returns : array of value : [line][item] my ($traffic_file, $items_number) = @_; my ($ligne, $n_rows) = (undef, 0); my (@last_values, @file_values, $i); open(FILE, "<" . $traffic_file) || return (1, 0, 0); while ($ligne = ) { chomp($ligne); @file_values = split(":", $ligne); #verb("@file_values"); if ($#file_values >= ($items_number - 1)) { # check if there is enough data, else ignore line for ($i = 0; $i < $items_number; $i++) { $last_values[$n_rows][$i] = $file_values[$i]; } $n_rows++; } } close FILE; if ($n_rows != 0) { return (0, $n_rows, @last_values); } else { return (1, 0, 0); } } sub write_file { # Input : file , rows, items, array of value : [line][item] # Returns : 0 / OK, 1 / error my ($file_out, $rows, $item, @file_values) = @_; my $start_line = ($rows > $file_history) ? $rows - $file_history : 0; if (open(FILE2, ">" . $file_out)) { for (my $i = $start_line; $i < $rows; $i++) { for (my $j = 0; $j < $item; $j++) { print FILE2 $file_values[$i][$j]; if ($j != ($item - 1)) { print FILE2 ":" } } print FILE2 "\n"; } close FILE2; return 0; } else { return 1; } } sub p_version { print "check_snmp_int version : $VERSION\n"; } sub print_usage { print "Usage: $0 [-v] -H -C [-2] | (-l login -x passwd [-X pass -L ,) [-p ] -n [-N -A -i -a -D --down] [-r] [-f[eSyY]] [-k[qBMGu] -g -w -c -d] [-o ] [-t ] [-s] --label [-V]\n"; } sub isnnum { # Return true if arg is not a number my $num = shift; if ($num =~ /^(\d+\.?\d*)|(^\.\d+)$/) { return 0; } return 1; } sub help { print "\nSNMP Network Interface Monitor for Icinga/Nagios/Naemon/Shinken, Version ", $VERSION, "\n"; print "GPL license, (c)2004-2007 Patrick Proy\n\n"; print_usage(); print <, : Authentication protocol (md5|sha : default md5) : Priv protocole (des|aes : default des) -P, --port=PORT SNMP port (Default 161) -n, --name=NAME Name in description OID (eth0, ppp0 ...). This is treated as a regexp : -n eth will match eth0,eth1,... Test it before, because there are known bugs (ex : trailling /) -r, --noregexp Do not use regexp to match NAME in description OID -N, --use-ifname Use IF-MIB::ifName as source for NIC name instead of IF-MIB::ifDescr -A, --use-ifalias Use IF-MIB::ifAlias as source for NIC name instead of IF-MIB::ifDescr -i, --inverse Make critical when up -a, --admin Use administrative status instead of operational -D, --dormant Dormant state is an OK state --down Down state is an OK state -o, --octetlength=INTEGER max-size of the SNMP message, usefull in case of Too Long responses. Be carefull with network filters. Range 484 - 65535, default are usually 1472,1452,1460 or 1440. -f, --perfparse, --perfdata Performance data output (no output when interface is down). -W, --weather Output data for "weathermap" lines in NagVis with performance data -e, --error Add error & discard to Perfparse output -S, --intspeed Include speed in performance output in bits/s -y, --perfprct ; -Y, --perfspeed -y : output performance data in % of max speed -Y : output performance data in bits/s or Bytes/s (depending on -B) -k, --perfcheck ; -q, --extperfcheck -k check the input/ouput bandwidth of the interface -q also check the error and discard input/output --label Add label before speed in output : in=, out=, errors-out=, etc... -g, --64bits Use 64 bits counters instead of the standard counters when checking bandwidth & performance data for interface >= 1Gbps. You must use snmp v2c or v3 to get 64 bits counters. -d, --delta=seconds make an average of seconds (default 300=5min) -B, --kbits Make the warning and critical levels in K|M|G Bits/s instead of K|M|G Bytes/s -G, --giga ; -M, --mega ; -u, --prct -G : Make the warning and critical levels in Gbps (with -B) or GBps -M : Make the warning and critical levels in Mbps (with -B) or MBps -u : Make the warning and critical levels in % of reported interface speed. -w, --warning=input,output[,error in,error out,discard in,discard out] warning level for input / output bandwidth (0 for no warning) unit depends on B,M,G,u options warning for error & discard input / output in error/min (need -q) -c, --critical=input,output[,error in,error out,discard in,discard out] critical level for input / output bandwidth (0 for no critical) unit depends on B,M,G,u options critical for error & discard input / output in error/min (need -q) -s, --short=int Make the output shorter : only the first chars of the interface(s) If the number is negative, then get the LAST caracters. -t, --timeout=INTEGER timeout for SNMP in seconds (Default: 5) -V, --version prints version number Note : when multiple interface are selected with regexp, all be must be up (or down with -i) to get an OK result. EOT } # For verbose output sub verb { my $t = shift; print $t, "\n" if defined($o_verb); } sub check_options { Getopt::Long::Configure("bundling"); GetOptions( 'v' => \$o_verb, 'verbose' => \$o_verb, 'h' => \$o_help, 'help' => \$o_help, 'H:s' => \$o_host, 'hostname:s' => \$o_host, 'p:i' => \$o_port, 'port:i' => \$o_port, 'n:s' => \$o_descr, 'name:s' => \$o_descr, 'N' => \$o_use_ifname, 'use-ifname' => \$o_use_ifname, 'A' => \$o_use_ifalias, 'use-ifalias' => \$o_use_ifalias, 'C:s' => \$o_community, 'community:s' => \$o_community, '2' => \$o_version2, 'v2c' => \$o_version2, 'l:s' => \$o_login, 'login:s' => \$o_login, 'x:s' => \$o_passwd, 'passwd:s' => \$o_passwd, 'X:s' => \$o_privpass, 'privpass:s' => \$o_privpass, 'L:s' => \$v3protocols, 'protocols:s' => \$v3protocols, 't:i' => \$o_timeout, 'timeout:i' => \$o_timeout, 'i' => \$o_inverse, 'inverse' => \$o_inverse, 'a' => \$o_admin, 'admin' => \$o_admin, 'r' => \$o_noreg, 'noregexp' => \$o_noreg, 'V' => \$o_version, 'version' => \$o_version, 'f' => \$o_perf, 'perfparse' => \$o_perf, 'perfdata' => \$o_perf, 'e' => \$o_perfe, 'error' => \$o_perfe, 'k' => \$o_checkperf, 'perfcheck' => \$o_checkperf, 'q' => \$o_ext_checkperf, 'extperfcheck' => \$o_ext_checkperf, 'w:s' => \$o_warn_opt, 'warning:s' => \$o_warn_opt, 'c:s' => \$o_crit_opt, 'critical:s' => \$o_crit_opt, 'B' => \$o_kbits, 'kbits' => \$o_kbits, 's:i' => \$o_short, 'short:i' => \$o_short, 'g' => \$o_highperf, '64bits' => \$o_highperf, 'S' => \$o_perfs, 'intspeed' => \$o_perfs, 'y' => \$o_perfp, 'perfprct' => \$o_perfp, 'Y' => \$o_perfr, 'perfspeed' => \$o_perfr, 'M' => \$o_meg, 'mega' => \$o_meg, 'G' => \$o_gig, 'giga' => \$o_gig, 'u' => \$o_prct, 'prct' => \$o_prct, 'o:i' => \$o_octetlength, 'octetlength:i' => \$o_octetlength, 'label' => \$o_label, 'd:i' => \$o_delta, 'delta:i' => \$o_delta, 'D' => \$o_dormant, 'dormant' => \$o_dormant, 'down' => \$o_down, 'W' => \$o_weather, 'weather' => \$o_weather ); if (defined($o_help)) { help(); exit $ERRORS{"UNKNOWN"} } if (defined($o_version)) { p_version(); exit $ERRORS{"UNKNOWN"} } if (!defined($o_descr) || !defined($o_host)) # check host and filter { print_usage(); exit $ERRORS{"UNKNOWN"}; } # check snmp information if (!defined($o_community) && (!defined($o_login) || !defined($o_passwd))) { print "Put snmp login info!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if ((defined($o_login) || defined($o_passwd)) && (defined($o_community) || defined($o_version2))) { print "Can't mix snmp v1,2c,3 protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (defined($v3protocols)) { if (!defined($o_login)) { print "Put snmp V3 login info with protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } my @v3proto = split(/,/, $v3protocols); if ((defined($v3proto[0])) && ($v3proto[0] ne "")) { $o_authproto = $v3proto[0]; } # Auth protocol if (defined($v3proto[1])) { $o_privproto = $v3proto[1]; } # Priv protocol if ((defined($v3proto[1])) && (!defined($o_privpass))) { print "Put snmp V3 priv login info with priv protocols!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } } if (defined($o_timeout) && (isnnum($o_timeout) || ($o_timeout < 2) || ($o_timeout > 60))) { print "Timeout must be >1 and <60 !\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (!defined($o_timeout)) { $o_timeout = 5; } # Check snmpv2c or v3 with 64 bit counters if (defined($o_highperf) && (!defined($o_version2) && defined($o_community))) { print "Can't get 64 bit counters with snmp version 1\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (defined($o_highperf)) { if (eval "require bigint") { use bigint; } else { print "Need bigint module for 64 bit counters\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } } # check if -e without -f if (defined($o_perfe) && !defined($o_perf)) { print "Cannot output error without -f option!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (defined($o_weather) && !defined($o_perf)) { print "Cannot output weathermap line data without -f option!\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (defined($o_perfr) && defined($o_perfp)) { print "-Y and -y options are exclusives\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if ((defined($o_perfr) || defined($o_perfp)) && !defined($o_checkperf)) { print "Cannot put -Y or -y options without perf check option (-k) \n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (defined($o_short)) { #TODO maybe some basic tests ? caracters return empty string } if (defined($o_checkperf)) { @o_warn = split(/,/, $o_warn_opt); if (defined($o_ext_checkperf) && ($#o_warn != 5)) { print "6 warning levels for extended checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (!defined($o_ext_checkperf) && ($#o_warn != 1)) { print "2 warning levels for bandwidth checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } @o_crit = split(/,/, $o_crit_opt); #verb(" $o_crit_opt :: $#o_crit : @o_crit"); if (defined($o_ext_checkperf) && ($#o_crit != 5)) { print "6 critical levels for extended checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } if (!defined($o_ext_checkperf) && ($#o_crit != 1)) { print "2 critical levels for bandwidth checks \n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } for (my $i = 0; $i <= $#o_warn; $i++) { if (($o_crit[$i] != 0) && ($o_warn[$i] > $o_crit[$i])) { print "Warning must be < Critical level \n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } } if ( (defined($o_meg) && defined($o_gig)) || (defined($o_meg) && defined($o_prct)) || (defined($o_gig) && defined($o_prct))) { print "-M -G and -u options are exclusives\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } } #### octet length checks if (defined($o_octetlength) && (isnnum($o_octetlength) || $o_octetlength > 65535 || $o_octetlength < 484)) { print "octet lenght must be < 65535 and > 484\n"; print_usage(); exit $ERRORS{"UNKNOWN"}; } } ########## MAIN ####### check_options(); # Check timeout if snmp screws up if (defined($o_timeout)) { verb("Alarm in $o_timeout seconds"); alarm($o_timeout); } $SIG{'ALRM'} = sub { print "No answer from host $o_host:$o_port\n"; exit $ERRORS{"UNKNOWN"}; }; # Connect to host my ($session, $error); if (defined($o_login) && defined($o_passwd)) { # SNMPv3 login if (!defined($o_privpass)) { verb("SNMPv3 AuthNoPriv login : $o_login, $o_authproto"); ($session, $error) = Net::SNMP->session( -hostname => $o_host, -version => '3', -port => $o_port, -username => $o_login, -authpassword => $o_passwd, -authprotocol => $o_authproto, -timeout => $o_timeout ); } else { verb("SNMPv3 AuthPriv login : $o_login, $o_authproto, $o_privproto"); ($session, $error) = Net::SNMP->session( -hostname => $o_host, -version => '3', -username => $o_login, -port => $o_port, -authpassword => $o_passwd, -authprotocol => $o_authproto, -privpassword => $o_privpass, -privprotocol => $o_privproto, -timeout => $o_timeout ); } } else { if (defined($o_version2)) { # SNMPv2c Login verb("SNMP v2c login"); ($session, $error) = Net::SNMP->session( -hostname => $o_host, -version => 2, -community => $o_community, -port => $o_port, -timeout => $o_timeout ); } else { # SNMPV1 login verb("SNMP v1 login"); ($session, $error) = Net::SNMP->session( -hostname => $o_host, -community => $o_community, -port => $o_port, -timeout => $o_timeout ); } } if (!defined($session)) { printf("ERROR opening session: %s.\n", $error); exit $ERRORS{"UNKNOWN"}; } if (defined($o_octetlength)) { my $oct_resultat = undef; my $oct_test = $session->max_msg_size(); verb(" actual max octets:: $oct_test"); $oct_resultat = $session->max_msg_size($o_octetlength); if (!defined($oct_resultat)) { printf("ERROR: Session settings : %s.\n", $session->error); $session->close; exit $ERRORS{"UNKNOWN"}; } $oct_test = $session->max_msg_size(); verb(" new max octets:: $oct_test"); } # Get description table my $query_table = $descr_table; if (defined($o_use_ifalias) and defined($o_use_ifname)) { printf("ERROR: Options -N and -A are exclusive. Please select only one.\n"); $session->close; exit $ERRORS{"UNKNOWN"}; } if (defined($o_use_ifname)) { $query_table = $name_table; } if (defined($o_use_ifalias)) { $query_table = $alias_table; } my $resultat = $session->get_table(Baseoid => $query_table); if (!defined($resultat)) { printf("ERROR: Description table : %s.\n", $session->error); $session->close; exit $ERRORS{"UNKNOWN"}; } my @tindex = undef; my @oids = undef; my @descr = undef; my ( @oid_perf, @oid_perf_outoct, @oid_perf_inoct, @oid_perf_inerr, @oid_perf_outerr, @oid_perf_indisc, @oid_perf_outdisc ) = (undef, undef, undef, undef, undef, undef, undef); my @oid_speed = undef; my @oid_speed_high = undef; my $num_int = 0; # Change to 64 bit counters if option is set : if (defined($o_highperf)) { $out_octet_table = $out_octet_table_64; $in_octet_table = $in_octet_table_64; } # Select interface by regexp of exact match # and put the oid to query in an array verb("Filter : $o_descr"); foreach my $key (sort { $$resultat{$a} cmp $$resultat{$b} } keys %$resultat) { verb("OID : $key, Desc : $$resultat{$key}"); # test by regexp or exact match my $test = defined($o_noreg) ? $$resultat{$key} eq $o_descr : $$resultat{$key} =~ /$o_descr/; if ($test) { # get the index number of the interface my @oid_list = split(/\./, $key); $tindex[$num_int] = pop(@oid_list); # get the full description $descr[$num_int] = $$resultat{$key}; # Get rid of special caracters (specially for Windows) $descr[$num_int] =~ s/[[:cntrl:]]//g; # put the admin or oper oid in an array $oids[$num_int] = defined($o_admin) ? $admin_table . $tindex[$num_int] : $oper_table . $tindex[$num_int]; # Put the performance oid if (defined($o_perf) || defined($o_checkperf)) { $oid_perf_inoct[$num_int] = $in_octet_table . $tindex[$num_int]; $oid_perf_outoct[$num_int] = $out_octet_table . $tindex[$num_int]; $oid_speed[$num_int] = $speed_table . $tindex[$num_int]; $oid_speed_high[$num_int] = $speed_table_64 . $tindex[$num_int]; if (defined($o_ext_checkperf) || defined($o_perfe)) { $oid_perf_indisc[$num_int] = $in_discard_table . $tindex[$num_int]; $oid_perf_outdisc[$num_int] = $out_discard_table . $tindex[$num_int]; $oid_perf_inerr[$num_int] = $in_error_table . $tindex[$num_int]; $oid_perf_outerr[$num_int] = $out_error_table . $tindex[$num_int]; } } verb("Name : $descr[$num_int], Index : $tindex[$num_int]"); $num_int++; } } # No interface found -> error if ($num_int == 0) { print "ERROR : Unknown interface $o_descr\n"; exit $ERRORS{"UNKNOWN"}; } my $result = undef; # Add performance oids if requested if (defined($o_perf) || defined($o_checkperf)) { @oids = (@oids, @oid_perf_outoct, @oid_perf_inoct, @oid_speed); if (defined($o_highperf)) { @oids = (@oids, @oid_speed_high); } if (defined($o_ext_checkperf) || defined($o_perfe)) { @oids = (@oids, @oid_perf_inerr, @oid_perf_outerr, @oid_perf_indisc, @oid_perf_outdisc); } } # Get the requested oid values while (my @oids_part = splice(@oids, 0, $snmp_splice_size)) { my $result_part = $session->get_request(Varbindlist => \@oids_part); if (!defined($result_part)) { printf("ERROR: Status/statistics table : %s.\n ", $session->error); $session->close; exit $ERRORS{"UNKNOWN"}; } $result = defined($result) ? { %$result, %$result_part } : $result_part; } $session->close; my $num_ok = 0; my @checkperf_out = undef; my @checkperf_out_raw = undef; ### Bandwidth test variables my $temp_file_name; my ($return, @file_values) = (undef, undef); my $n_rows = 0; my $n_items_check = (defined($o_ext_checkperf)) ? 7 : 3; my $timenow = time; my $trigger = $timenow - ($o_delta - ($o_delta / 10)); my $trigger_low = $timenow - 3 * $o_delta; my ($old_value, $old_time) = undef; my $speed_unit = undef; my $speed_real = undef; # speed of interface using either standard or highperf mib. # define the OK value depending on -i option my $ok_val = defined($o_inverse) ? 2 : 1; my $final_status = 0; my ($print_out, $perf_out) = (undef, undef); # make all checks and output for all interfaces for (my $i = 0; $i < $num_int; $i++) { $print_out .= ", " if (defined($print_out)); $perf_out .= " " if (defined($perf_out)); my $usable_data = 1; # Get the status of the current interface my $int_status = defined($o_admin) ? $$result{ $admin_table . $tindex[$i] } : $$result{ $oper_table . $tindex[$i] }; # Make the bandwith & error checks if necessary if (defined($o_checkperf) && $int_status == 1) { $temp_file_name = $descr[$i]; $temp_file_name =~ s/[ ;\/]/_/g; $temp_file_name = $o_base_dir . $o_host . "." . $o_port . "." . $temp_file_name; # First, read entire file my @ret_array = read_file($temp_file_name, $n_items_check); $return = shift(@ret_array); $n_rows = shift(@ret_array); if ($n_rows != 0) { @file_values = @ret_array } verb("File read returns : $return with $n_rows rows"); # Get the speed in normal or highperf speed counters if ($$result{ $oid_speed[$i] } == 4294967295) { # Too high for this counter (cf IF-MIB) if (!defined($o_highperf) && (defined($o_prct) || defined($o_perfs) || defined($o_perfp))) { print "Cannot get interface speed with standard MIB, use highperf mib (-g) : UNKNOWN\n"; exit $ERRORS{"UNKNOWN"}; } if (defined($$result{ $oid_speed_high[$i] }) && $$result{ $oid_speed_high[$i] } != 0) { $speed_real = $$result{ $oid_speed_high[$i] } * 1000000; } else { print "Cannot get interface speed using highperf mib : UNKNOWN\n"; exit $ERRORS{"UNKNOWN"}; } } else { $speed_real = $$result{ $oid_speed[$i] }; } verb("Interface speed : $speed_real"); #make the checks if the file is OK if ($return == 0) { my $j = $n_rows - 1; @checkperf_out = undef; @checkperf_out_raw = undef; do { if ($file_values[$j][0] < $trigger) { if ($file_values[$j][0] > $trigger_low) { # Define the speed metric ( K | M | G ) (Bits|Bytes) or % my $speed_metric = undef; if (defined($o_prct)) { # in % of speed # Speed is in bits/s, calculated speed is in Bytes/s $speed_metric = $speed_real / 800; $speed_unit = "%"; } else { if (defined($o_kbits)) { # metric in bits if (defined($o_meg)) { # in Mbit/s = 1000000 bit/s $speed_metric = 125000; # (1000/8) * 1000 $speed_unit = "Mbps"; } elsif (defined($o_gig)) { # in Gbit/s = 1000000000 bit/s $speed_metric = 125000000; # (1000/8) * 1000 * 1000 $speed_unit = "Gbps"; } else { # in Kbits $speed_metric = 125; # ( 1000/8 ) $speed_unit = "Kbps"; } } else { # metric in byte if (defined($o_meg)) { # in Mbits $speed_metric = 1048576; # 1024^2 $speed_unit = "MBps"; } elsif (defined($o_gig)) { # in Mbits $speed_metric = 1073741824; # 1024^3 $speed_unit = "GBps"; } else { $speed_metric = 1024; # 1024^3 $speed_unit = "KBps"; } } } # check if the counter is back to 0 after 2^32 / 2^64. # First set the modulus depending on highperf counters or not my $overfl_mod = defined($o_highperf) ? 18446744073709551616 : 4294967296; # Check counter (s) my $overfl = ($$result{ $oid_perf_inoct[$i] } >= $file_values[$j][1]) ? 0 : $overfl_mod; $checkperf_out_raw[0] = (($overfl + $$result{ $oid_perf_inoct[$i] } - $file_values[$j][1]) / ($timenow - $file_values[$j][0])); $checkperf_out[0] = $checkperf_out_raw[0] / $speed_metric; $overfl = ($$result{ $oid_perf_outoct[$i] } >= $file_values[$j][2]) ? 0 : $overfl_mod; $checkperf_out_raw[1] = (($overfl + $$result{ $oid_perf_outoct[$i] } - $file_values[$j][2]) / ($timenow - $file_values[$j][0])); $checkperf_out[1] = $checkperf_out_raw[1] / $speed_metric; if (defined($o_ext_checkperf)) { $checkperf_out[2] = (($$result{ $oid_perf_inerr[$i] } - $file_values[$j][3]) / ($timenow - $file_values[$j][0])) * 60; $checkperf_out[3] = (($$result{ $oid_perf_outerr[$i] } - $file_values[$j][4]) / ($timenow - $file_values[$j][0])) * 60; $checkperf_out[4] = (($$result{ $oid_perf_indisc[$i] } - $file_values[$j][5]) / ($timenow - $file_values[$j][0])) * 60; $checkperf_out[5] = (($$result{ $oid_perf_outdisc[$i] } - $file_values[$j][6]) / ($timenow - $file_values[$j][0])) * 60; } } } $j--; } while (($j >= 0) && (!defined($checkperf_out[0]))); } # Put the new values in the array and write the file $file_values[$n_rows][0] = $timenow; $file_values[$n_rows][1] = $$result{ $oid_perf_inoct[$i] }; $file_values[$n_rows][2] = $$result{ $oid_perf_outoct[$i] }; if (defined($o_ext_checkperf)) { # Add other values (error & disc) $file_values[$n_rows][3] = $$result{ $oid_perf_inerr[$i] }; $file_values[$n_rows][4] = $$result{ $oid_perf_outerr[$i] }; $file_values[$n_rows][5] = $$result{ $oid_perf_indisc[$i] }; $file_values[$n_rows][6] = $$result{ $oid_perf_outdisc[$i] }; } $n_rows++; $return = write_file($temp_file_name, $n_rows, $n_items_check, @file_values); verb("Write file returned : $return"); # Print the basic status if (defined($o_short)) { my $short_desc = undef; if ($o_short < 0) { $short_desc = substr($descr[$i], $o_short); } else { $short_desc = substr($descr[$i], 0, $o_short); } $print_out .= sprintf("%s:%s", $short_desc, $status{$int_status}); } else { $print_out .= sprintf("%s:%s", $descr[$i], $status{$int_status}); } if ($return != 0) { # On error writing, return Unknown status $final_status = 3; $print_out .= " !!Unable to write file " . $temp_file_name . " !! "; } # print the other checks if it was calculated if (defined($checkperf_out[0])) { $print_out .= " ("; # check 2 or 6 values depending on ext_check_perf my $num_checkperf = (defined($o_ext_checkperf)) ? 6 : 2; for (my $l = 0; $l < $num_checkperf; $l++) { # Set labels if needed $checkperf_out_desc = (defined($o_label)) ? $countername[$l] : ""; verb("Interface $i, check $l : $checkperf_out[$l]"); if ($l != 0) { $print_out .= "/"; } if (($o_crit[$l] != 0) && ($checkperf_out[$l] > $o_crit[$l])) { $final_status = 2; $print_out .= sprintf("CRIT %s%.1f", $checkperf_out_desc, $checkperf_out[$l]); } elsif (($o_warn[$l] != 0) && ($checkperf_out[$l] > $o_warn[$l])) { $final_status = ($final_status == 2) ? 2 : 1; $print_out .= sprintf("WARN %s%.1f", $checkperf_out_desc, $checkperf_out[$l]); } else { $print_out .= sprintf("%s%.1f", $checkperf_out_desc, $checkperf_out[$l]); } if ($l == 0 || $l == 1) { $print_out .= $speed_unit; } } $print_out .= ")"; } else { # Return unknown when no data $print_out .= " No usable data on file (" . $n_rows . " rows) "; $final_status = 3; $usable_data = 0; } } else { if (defined($o_short)) { my $short_desc = undef; if ($o_short < 0) { $short_desc = substr($descr[$i], $o_short); } else { $short_desc = substr($descr[$i], 0, $o_short); } $print_out .= sprintf("%s:%s", $short_desc, $status{$int_status}); } else { $print_out .= sprintf("%s:%s", $descr[$i], $status{$int_status}); } } # Get rid of special caracters for performance in description $descr[$i] =~ s/'\/\(\)/_/g; if (($int_status == $ok_val) || (defined($o_down) && $int_status == 2) || (defined($o_dormant) && $int_status == 5)) { $num_ok++; } if (($int_status == 1) && defined($o_perf)) { if (defined($o_perfp)) { # output in % of speed if ($usable_data == 1) { my $warn_factor = 1; if (!defined($o_prct)) { # warn&crit in K|M|G B|bps -> put warn_factor to make % $warn_factor = (defined($o_meg)) ? 1000000 : (defined($o_gig)) ? 1000000000 : 1000; if (!defined($o_kbits)) { $warn_factor *= 8; } $warn_factor /= $speed_real; $warn_factor *= 100; # now turn into displayed % : 0,1 = 10% } $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_in_prct'="; $perf_out .= sprintf("%.0f", $checkperf_out_raw[0] * 800 / $speed_real) . "%;"; $perf_out .= ($o_warn[0] != 0) ? sprintf("%.0f", $o_warn[0] * $warn_factor) . ";" : ";"; $perf_out .= ($o_crit[0] != 0) ? sprintf("%.0f", $o_crit[0] * $warn_factor) . ";" : ";"; $perf_out .= "0;100 "; $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_out_prct'="; $perf_out .= sprintf("%.0f", $checkperf_out_raw[1] * 800 / $speed_real) . "%;"; $perf_out .= ($o_warn[1] != 0) ? sprintf("%.0f", $o_warn[1] * $warn_factor) . ";" : ";"; $perf_out .= ($o_crit[1] != 0) ? sprintf("%.0f", $o_crit[1] * $warn_factor) . ";" : ";"; $perf_out .= "0;100 "; } } elsif (defined($o_perfr)) { # output in bites or Bytes /s if ($usable_data == 1) { if (defined($o_kbits)) { # bps # put warning and critical levels into bps or Bps my $warn_factor; if (defined($o_prct)) { # warn&crit in % -> put warn_factor to 1% of speed in bps $warn_factor = $speed_real / 100; } else { # just convert from K|M|G bps $warn_factor = (defined($o_meg)) ? 1000000 : (defined($o_gig)) ? 1000000000 : 1000; } $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_in_bps'="; $perf_out .= sprintf("%.0f", $checkperf_out_raw[0] * 8) . ";"; $perf_out .= ($o_warn[0] != 0) ? $o_warn[0] * $warn_factor . ";" : ";"; $perf_out .= ($o_crit[0] != 0) ? $o_crit[0] * $warn_factor . ";" : ";"; $perf_out .= "0;" . $speed_real . " "; $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_out_bps'="; $perf_out .= sprintf("%.0f", $checkperf_out_raw[1] * 8) . ";"; $perf_out .= ($o_warn[1] != 0) ? $o_warn[1] * $warn_factor . ";" : ";"; $perf_out .= ($o_crit[1] != 0) ? $o_crit[1] * $warn_factor . ";" : ";"; $perf_out .= "0;" . $speed_real . " "; } else { # Bps my $warn_factor; if (defined($o_prct)) { # warn&crit in % -> put warn_factor to 1% of speed in Bps $warn_factor = $speed_real / 800; } else { # just convert from K|M|G bps $warn_factor = (defined($o_meg)) ? 1048576 : (defined($o_gig)) ? 1073741824 : 1024; } $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_in_Bps'=" . sprintf("%.0f", $checkperf_out_raw[0]) . ";"; $perf_out .= ($o_warn[0] != 0) ? $o_warn[0] * $warn_factor . ";" : ";"; $perf_out .= ($o_crit[0] != 0) ? $o_crit[0] * $warn_factor . ";" : ";"; $perf_out .= "0;" . $speed_real / 8 . " "; $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_out_Bps'=" . sprintf("%.0f", $checkperf_out_raw[1]) . ";"; $perf_out .= ($o_warn[1] != 0) ? $o_warn[1] * $warn_factor . ";" : ";"; $perf_out .= ($o_crit[1] != 0) ? $o_crit[1] * $warn_factor . ";" : ";"; $perf_out .= "0;" . $speed_real / 8 . " "; } } } else { # output in octet counter $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_in_octet'=" . $$result{ $oid_perf_inoct[$i] } . "c "; $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_out_octet'=" . $$result{ $oid_perf_outoct[$i] } . "c "; } if (defined($o_perfe)) { $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_in_error'=" . $$result{ $oid_perf_inerr[$i] } . "c "; $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_in_discard'=" . $$result{ $oid_perf_indisc[$i] } . "c "; $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_out_error'=" . $$result{ $oid_perf_outerr[$i] } . "c "; $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_out_discard'=" . $$result{ $oid_perf_outdisc[$i] } . "c "; } if (defined($o_perfs)) { $perf_out .= "'" . $descr[$i] =~ s/\./_/r . "_speed_bps'=" . $speed_real . " "; } if (defined($o_weather) && $usable_data == 1) { $perf_out .= "in=" . sprintf("%.0f", $checkperf_out_raw[0]) . ";;;0;" . sprintf("%.0f", $speed_real / 8) . " "; $perf_out .= "out=" . sprintf("%.0f", $checkperf_out_raw[1]) . ";;;0;" . sprintf("%.0f", $speed_real / 8) . " "; } } } # Only a few ms left... alarm(0); # Check if all interface are OK if ($num_ok == $num_int) { if ($final_status == 0) { print $print_out, ":", $num_ok, " UP: OK"; if (defined($o_perf)) { print " | ", $perf_out; } print "\n"; exit $ERRORS{"OK"}; } elsif ($final_status == 1) { print $print_out, ":(", $num_ok, " UP): WARNING"; if (defined($o_perf)) { print " | ", $perf_out; } print "\n"; exit $ERRORS{"WARNING"}; } elsif ($final_status == 2) { print $print_out, ":(", $num_ok, " UP): CRITICAL"; if (defined($o_perf)) { print " | ", $perf_out; } print "\n"; exit $ERRORS{"CRITICAL"}; } else { print $print_out, ":(", $num_ok, " UP): UNKNOWN"; if (defined($perf_out)) { print " | ", $perf_out; } print "\n"; exit $ERRORS{"UNKNOWN"}; } } # else print the not OK interface number and exit (return is always critical if at least one int is down). print $print_out, ": ", $num_int - $num_ok, " int NOK : CRITICAL"; if (defined($perf_out)) { print " | ", $perf_out; } print "\n"; exit $ERRORS{"CRITICAL"};