From 71eaedc34a17679940bf2a2dba370cdf7b951d60 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Wed, 22 Jul 2015 17:42:18 +0200 Subject: [PATCH] + WIP on interface mode (Ref #77) --- os/linux/snmp/plugin.pm | 1 + snmp_standard/mode/interfaces.pm | 872 +++++++++++++++++++++++++++++++ 2 files changed, 873 insertions(+) create mode 100644 snmp_standard/mode/interfaces.pm diff --git a/os/linux/snmp/plugin.pm b/os/linux/snmp/plugin.pm index 28a46d173..dbe3b8fb0 100644 --- a/os/linux/snmp/plugin.pm +++ b/os/linux/snmp/plugin.pm @@ -37,6 +37,7 @@ sub new { 'diskio' => 'snmp_standard::mode::diskio', 'disk-usage' => 'snmp_standard::mode::diskusage', 'inodes' => 'snmp_standard::mode::inodes', + 'interfaces' => 'snmp_standard::mode::interfaces', 'load' => 'snmp_standard::mode::loadaverage', 'list-diskspath' => 'snmp_standard::mode::listdiskspath', 'list-interfaces' => 'snmp_standard::mode::listinterfaces', diff --git a/snmp_standard/mode/interfaces.pm b/snmp_standard/mode/interfaces.pm new file mode 100644 index 000000000..7dba4f243 --- /dev/null +++ b/snmp_standard/mode/interfaces.pm @@ -0,0 +1,872 @@ +# +# Copyright 2015 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package snmp_standard::mode::interfaces; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use centreon::plugins::values; +use centreon::plugins::statefile; +use Digest::MD5 qw(md5_hex); + +my $instance_mode; + +my $maps_counters = { + int => { + '000_status' => { filter => 'add_status', + set => { + key_values => [ { name => 'opstatus' }, { name => 'admstatus' } ], + closure_custom_calc => \&custom_status_calc, + closure_custom_output => \&custom_status_output, + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&custom_threshold_output, + } + }, + '010_in-traffic' => { filter => 'add_traffic', + set => { + key_values => [ { name => 'in', diff => 1 }, { name => 'speed_in'}, { name => 'display' }, { name => 'mode_traffic' } ], + per_second => 1, + closure_custom_calc => \&custom_traffic_calc, closure_custom_calc_extra_options => { label_ref => 'in' }, + closure_custom_output => \&custom_traffic_output, + closure_custom_perfdata => \&custom_traffic_perfdata, + closure_custom_threshold_check => \&custom_traffic_threshold, + } + }, + '011_out-traffic' => { filter => 'add_traffic', + set => { + key_values => [ { name => 'out', diff => 1 }, { name => 'speed_out'}, { name => 'display' }, { name => 'mode_traffic' } ], + per_second => 1, + closure_custom_calc => \&custom_traffic_calc, closure_custom_calc_extra_options => { label_ref => 'out' }, + closure_custom_output => \&custom_traffic_output, + closure_custom_perfdata => \&custom_traffic_perfdata, + closure_custom_threshold_check => \&custom_traffic_threshold, + } + }, + '020_in-ucast' => { filter => 'add_cast', + set => { + key_values => [ { name => 'iucast', diff => 1 }, { name => 'imcast', diff => 1 }, { name => 'ibcast', diff => 1 }, { name => 'display' }, { name => 'mode_cast' } ], + closure_custom_calc => \&custom_cast_calc, closure_custom_calc_extra_options => { label_ref => 'iucast', total_ref1 => 'ibcast', total_ref2 => 'imcast' }, + output_template => 'In Ucast : %.2f %%', output_error_template => 'In Ucast : %s', + output_use => 'iucast_prct', threshold_use => 'iucast_prct', + perfdatas => [ + { value => 'iucast_prct', template => '%.2f', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + '021_in-bcast' => { filter => 'add_cast', + set => { + key_values => [ { name => 'iucast', diff => 1 }, { name => 'imcast', diff => 1 }, { name => 'ibcast', diff => 1 }, { name => 'display' }, { name => 'mode_cast' } ], + closure_custom_calc => \&custom_cast_calc, closure_custom_calc_extra_options => { label_ref => 'ibcast', total_ref1 => 'iucast', total_ref2 => 'imcast' }, + output_template => 'In Bcast : %.2f %%', output_error_template => 'In Bcast : %s', + output_use => 'ibcast_prct', threshold_use => 'ibcast_prct', + perfdatas => [ + { value => 'ibcast_prct', template => '%.2f', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + '022_in-mcast' => { filter => 'add_cast', + set => { + key_values => [ { name => 'iucast', diff => 1 }, { name => 'imcast', diff => 1 }, { name => 'ibcast', diff => 1 }, { name => 'display' }, { name => 'mode_cast' } ], + closure_custom_calc => \&custom_cast_calc, closure_custom_calc_extra_options => { label_ref => 'imcast', total_ref1 => 'iucast', total_ref2 => 'ibcast' }, + output_template => 'In Mcast : %.2f %%', output_error_template => 'In Mcast : %s', + output_use => 'imcast_prct', threshold_use => 'imcast_prct', + perfdatas => [ + { value => 'imcast_prct', template => '%.2f', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + '023_out-ucast' => { filter => 'add_cast', + set => { + key_values => [ { name => 'oucast', diff => 1 }, { name => 'omcast', diff => 1 }, { name => 'obcast', diff => 1 }, { name => 'display' }, { name => 'mode_cast' } ], + closure_custom_calc => \&custom_cast_calc, closure_custom_calc_extra_options => { label_ref => 'oucast', total_ref1 => 'omcast', total_ref2 => 'obcast' }, + output_template => 'Out Ucast : %.2f %%', output_error_template => 'Out Ucast : %s', + output_use => 'oucast_prct', threshold_use => 'oucast_prct', + perfdatas => [ + { value => 'oucast_prct', template => '%.2f', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + '024_out-bcast' => { filter => 'add_cast', + set => { + key_values => [ { name => 'oucast', diff => 1 }, { name => 'omcast', diff => 1 }, { name => 'obcast', diff => 1 }, { name => 'display' }, { name => 'mode_cast' } ], + closure_custom_calc => \&custom_cast_calc, closure_custom_calc_extra_options => { label_ref => 'obcast', total_ref1 => 'omcast', total_ref2 => 'oucast' }, + output_template => 'Out Bcast : %.2f %%', output_error_template => 'Out Bcast : %s', + output_use => 'obcast_prct', threshold_use => 'obcast_prct', + perfdatas => [ + { value => 'obcast_prct', template => '%.2f', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + '025_out-mcast' => { filter => 'add_cast', + set => { + key_values => [ { name => 'iucast', diff => 1 }, { name => 'imcast', diff => 1 }, { name => 'ibcast', diff => 1 }, { name => 'display' }, { name => 'mode_cast' } ], + closure_custom_calc => \&custom_cast_calc, closure_custom_calc_extra_options => { label_ref => 'ibcast', total_ref1 => 'iucast', total_ref2 => 'imcast' }, + output_template => 'In Bcast : %.2f %%', output_error_template => 'In Bcast : %s', + output_use => 'ibcast_prct', threshold_use => 'ibcast_prct', + perfdatas => [ + { value => 'ibcast_prct', template => '%.2f', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + }, +}; + +######################### +# Calc functions +######################### +sub custom_threshold_output { + my ($self, %options) = @_; + + my $status = $instance_mode->get_severity(section => 'admin', value => $self->{result_values}->{admstatus}); + if ($self->{output}->is_status(value => $status, compare => 'ok', litteral => 1)) { + return $status; + } + $status = $instance_mode->get_severity(section => 'oper', value => $self->{result_values}->{opstatus}); + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + my $msg = 'Status : ' . $self->{result_values}->{opstatus} . ' (admin status: ' . $self->{result_values}->{admstatus} . ')'; + + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{opstatus} = $options{new_datas}->{$self->{instance} . '_opstatus'}; + $self->{result_values}->{admstatus} = $options{new_datas}->{$self->{instance} . '_admstatus'}; + return 0; +} + +sub custom_cast_calc { + my ($self, %options) = @_; + + my $diff_cast = ($options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}} - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}}); + my $total = $diff_cast + + ($options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{total_ref1}} - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}->{total_ref1}}) + + ($options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{total_ref2}} - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}->{total_ref2}}); + if ($options{new_datas}->{$self->{instance} . '_mode_cast'} ne $options{old_datas}->{$self->{instance} . '_mode_cast'}) { + $self->{error_msg} = "buffer creation"; + return -2; + } + if ($total == 0) { + $self->{error_msg} = "skipped"; + return -2; + } + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{$options{extra_options}->{label_ref} . '_prct'} = $diff_cast * 100 / $total; + return 0; +} + +############## +# Traffic +sub custom_traffic_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + if (!defined($options{extra_instance}) || $options{extra_instance} != 0) { + $extra_label .= '_' . $self->{result_values}->{display}; + } + my ($warning, $critical); + if ($instance_mode->{option_results}->{units_traffic} eq '%' && defined($self->{result_values}->{speed})) { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{speed}, cast_int => 1); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{speed}, cast_int => 1); + } elsif ($instance_mode->{option_results}->{units_traffic} eq 'b/s') { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}); + } + $self->{output}->perfdata_add(label => 'traffic_' . $self->{result_values}->{label} . $extra_label, unit => 'b/s', + value => $self->{result_values}->{traffic_per_seconds}, + warning => $warning, + critical => $critical, + min => 0, max => $self->{result_values}->{speed}); +} + +sub custom_traffic_threshold { + my ($self, %options) = @_; + + my $exit = 'ok'; + if ($instance_mode->{option_results}->{units_traffic} eq '%' && defined($self->{result_values}->{speed})) { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{traffic_prct}, threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]); + } elsif ($instance_mode->{option_results}->{units_traffic} eq 'b/s') { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{traffic_per_seconds}, threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]); + } + return $exit; +} + +sub custom_traffic_output { + my ($self, %options) = @_; + + my ($traffic_value, $traffic_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{traffic_per_seconds}, network => 1); + my $msg = sprintf("Traffic %s %s/s (%s)", + ucfirst($self->{result_values}->{label}), $traffic_value . $traffic_unit, + defined($self->{result_values}->{traffic_prct}) ? sprintf("%.2f%%", $self->{result_values}->{traffic_prct}) : '-'); + return $msg; +} + +sub custom_traffic_calc { + my ($self, %options) = @_; + + if ($options{new_datas}->{$self->{instance} . '_mode_traffic'} ne $options{old_datas}->{$self->{instance} . '_mode_traffic'}) { + $self->{error_msg} = "buffer creation"; + return -2; + } + + my $diff_traffic = ($options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}} - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}}); + $self->{result_values}->{traffic_per_seconds} = $diff_traffic / $options{delta_time}; + if (defined($options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}) && + $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}} > 0) { + $self->{result_values}->{traffic_prct} = $self->{result_values}->{traffic_per_seconds} * 100 / $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; + $self->{result_values}->{speed} = $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; + } + + $self->{result_values}->{label} = $options{extra_options}->{label_ref}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +######################### +# OIDs mapping functions +######################### +sub set_instance { + my ($self, %options) = @_; + + $instance_mode = $self; +} + +sub set_oids_label { + my ($self, %options) = @_; + + $self->{oids_label} = { + 'ifdesc' => '.1.3.6.1.2.1.2.2.1.2', + 'ifalias' => '.1.3.6.1.2.1.31.1.1.1.18', + 'ifname' => '.1.3.6.1.2.1.31.1.1.1.1', + }; +} + +sub set_oids_status { + my ($self, %options) = @_; + + $self->{oid_adminstatus} = '.1.3.6.1.2.1.2.2.1.7'; + $self->{oid_adminstatus_mapping} = { + 1 => 'up', 2 => 'down', 3 => 'testing', 4 => 'unknown', 5 => 'dormant', 6 => 'notPresent', 7 => 'lowerLayerDown', + }; + $self->{oid_opstatus} = '.1.3.6.1.2.1.2.2.1.8'; + $self->{oid_opstatus_mapping} = { + 1 => 'up', 2 => 'down', 3 => 'testing', 4 => 'unknown', 5 => 'dormant', 6 => 'notPresent', 7 => 'lowerLayerDown', + }; + + $self->{thresholds_status} = { + oper => [ + ['up', 'OK'], + ['.*', 'CRITICAL'], + ], + admin => [ + ['down', 'OK'], + ], + }; +} + +sub set_oids_traffic { + my ($self, %options) = @_; + + $self->{oid_speed32} = '.1.3.6.1.2.1.2.2.1.5'; # in b/s + $self->{oid_in32} = '.1.3.6.1.2.1.2.2.1.10'; # in B + $self->{oid_out32} = '.1.3.6.1.2.1.2.2.1.16'; # in B + $self->{oid_speed64} = '.1.3.6.1.2.1.31.1.1.1.15'; # need multiple by '1000000' + $self->{oid_in64} = '.1.3.6.1.2.1.31.1.1.1.6'; # in B + $self->{oid_out64} = '.1.3.6.1.2.1.31.1.1.1.10'; # in B +} + +sub set_oids_cast { + my ($self, %options) = @_; + + # 32bits + $self->{oid_ifInUcastPkts} = '.1.3.6.1.2.1.2.2.1.11'; + $self->{oid_ifInBroadcastPkts} = '.1.3.6.1.2.1.31.1.1.1.3'; + $self->{oid_ifInMulticastPkts} = '.1.3.6.1.2.1.31.1.1.1.2'; + $self->{oid_ifOutUcastPkts} = '.1.3.6.1.2.1.2.2.1.17'; + $self->{oid_ifOutMulticastPkts} = '.1.3.6.1.2.1.31.1.1.1.4'; + $self->{oid_ifOutBroadcastPkts} = '.1.3.6.1.2.1.31.1.1.1.5'; + + # 64 bits + $self->{oid_ifHCInUcastPkts} = '.1.3.6.1.2.1.31.1.1.1.7'; + $self->{oid_ifHCInMulticastPkts} = '.1.3.6.1.2.1.31.1.1.1.8'; + $self->{oid_ifHCInBroadcastPkts} = '.1.3.6.1.2.1.31.1.1.1.9'; + $self->{oid_ifHCOutUcastPkts} = '.1.3.6.1.2.1.31.1.1.1.11'; + $self->{oid_ifHCOutMulticastPkts} = '.1.3.6.1.2.1.31.1.1.1.12'; + $self->{oid_ifHCOutBroadcastPkts} = '.1.3.6.1.2.1.31.1.1.1.13'; +} + +sub check_oids_label { + my ($self, %options) = @_; + + $self->{option_results}->{oid_filter} = lc($self->{option_results}->{oid_filter}); + foreach (('oid_filter', 'oid_display')) { + if (!defined($self->{oids_label}->{lc($self->{option_results}->{$_})})) { + my $label = $_; + $label =~ s/_/-/g; + $self->{output}->add_option_msg(short_msg => "Unsupported --" . $label . " option."); + $self->{output}->option_exit(); + } + } +} + +sub default_oid_filter_name { + my ($self, %options) = @_; + + return 'ifname'; +} + +sub default_oid_display_name { + my ($self, %options) = @_; + + return 'ifname'; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "add-status" => { name => 'add_status' }, + "add-traffic" => { name => 'add_traffic' }, + "add-errors" => { name => 'add_errors' }, + "add-cast" => { name => 'add_cast' }, + "oid-filter:s" => { name => 'oid_filter', default => $self->default_oid_filter_name() }, + "oid-display:s" => { name => 'oid_display', default => $self->default_oid_display_name() }, + "interface:s" => { name => 'interface' }, + "name" => { name => 'use_name' }, + "units-traffic:s" => { name => 'units_traffic', default => '%' }, + "speed:s" => { name => 'speed' }, + "speed-in:s" => { name => 'speed_in' }, + "speed-out:s" => { name => 'speed_out' }, + "display-transform-src:s" => { name => 'display_transform_src' }, + "display-transform-dst:s" => { name => 'display_transform_dst' }, + "show-cache" => { name => 'show_cache' }, + "reload-cache-time:s" => { name => 'reload_cache_time', default => 180 }, + "threshold-overload:s@" => { name => 'threshold_overload' }, + }); + $self->{statefile_value} = centreon::plugins::statefile->new(%options); + $self->{statefile_cache} = centreon::plugins::statefile->new(%options); + + foreach my $key (('int')) { + foreach (keys %{$maps_counters->{$key}}) { + my ($id, $name) = split /_/; + if (!defined($maps_counters->{$key}->{$_}->{threshold}) || $maps_counters->{$key}->{$_}->{threshold} != 0) { + $options{options}->add_options(arguments => { + 'warning-' . $name . ':s' => { name => 'warning-' . $name }, + 'critical-' . $name . ':s' => { name => 'critical-' . $name }, + }); + } + $maps_counters->{$key}->{$_}->{obj} = centreon::plugins::values->new(statefile => $self->{statefile_value}, + output => $self->{output}, perfdata => $self->{perfdata}, + label => $name); + $maps_counters->{$key}->{$_}->{obj}->set(%{$maps_counters->{$key}->{$_}->{set}}); + } + } + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + + foreach my $key (('int')) { + foreach (keys %{$maps_counters->{$key}}) { + $maps_counters->{$key}->{$_}->{obj}->init(option_results => $self->{option_results}); + } + } + + $self->set_oids_label(); + $self->check_oids_label(); + + $self->set_instance(); + $self->{statefile_cache}->check_options(%options); + $self->{statefile_value}->check_options(%options); + + if (defined($self->{option_results}->{add_traffic}) && + (!defined($self->{option_results}->{units_traffic}) || $self->{option_results}->{units_traffic} !~ /^(%|b\/s)$/)) { + $self->{output}->add_option_msg(short_msg => "Wrong option --units-traffic."); + $self->{output}->option_exit(); + } + + if ((!defined($self->{option_results}->{speed}) || $self->{option_results}->{speed} eq '') && + ((!defined($self->{option_results}->{speed_in}) || $self->{option_results}->{speed_in} eq '') || + (!defined($self->{option_results}->{speed_out}) || $self->{option_results}->{speed_out} eq ''))) { + $self->{get_speed} = 1; + } + + # If no options, we set status + if (!defined($self->{option_results}->{add_status}) && !defined($self->{option_results}->{add_traffic}) && + !defined($self->{option_results}->{add_errors}) && !defined($self->{option_results}->{add_cast})) { + $self->{option_results}->{add_status} = 1; + } + $self->{checking} = ''; + foreach (('add_status', 'add_errors', 'add_traffic', 'add_cast')) { + if (defined($self->{options_results}->{$_})) { + $self->{checking} .= $_; + } + } + + $self->{overload_th} = {}; + foreach my $val (@{$self->{option_results}->{threshold_overload}}) { + if ($val !~ /^(.*?),(.*?),(.*)$/) { + $self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'."); + $self->{output}->option_exit(); + } + my ($section, $status, $filter) = ($1, $2, $3); + if ($self->{output}->is_litteral_status(status => $status) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'."); + $self->{output}->option_exit(); + } + $self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section})); + push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status}; + } +} + +sub run { + my ($self, %options) = @_; + # $options{snmp} = snmp object + $self->{snmp} = $options{snmp}; + $self->{hostname} = $self->{snmp}->get_hostname(); + $self->{snmp_port} = $self->{snmp}->get_port(); + + $self->get_informations(); + + my $multiple = 1; + if (scalar(keys %{$self->{int}}) == 1) { + $multiple = 0; + } + + if ($multiple == 1) { + $self->{output}->output_add(severity => 'OK', + short_msg => 'All interfaces are ok'); + } + + $self->{new_datas} = {}; + $self->{statefile_value}->read(statefile => "snmpstandard_" . $self->{hostname} . '_' . $self->{snmp_port} . '_' . $self->{mode} . '_' . + (defined($self->{option_results}->{interface}) ? md5_hex($self->{option_results}->{interface}) : md5_hex('all')) . '_' . + md5_hex($self->{checking})); + $self->{new_datas}->{last_timestamp} = time(); + + foreach my $id (sort keys %{$self->{interface_selected}}) { + my ($short_msg, $short_msg_append, $long_msg, $long_msg_append) = ('', '', '', ''); + my @exits = (); + foreach (sort keys %{$maps_counters->{int}}) { + my $obj = $maps_counters->{int}->{$_}->{obj}; + next if (!defined($self->{option_results}->{$maps_counters->{int}->{$_}->{filter}})); + $obj->set(instance => $id); + + my ($value_check) = $obj->execute(values => $self->{interface_selected}->{$id}, + new_datas => $self->{new_datas}); + + if ($value_check != 0) { + $long_msg .= $long_msg_append . $obj->output_error(); + $long_msg_append = ', '; + next; + } + my $exit2 = $obj->threshold_check(); + push @exits, $exit2; + + my $output = $obj->output(); + $long_msg .= $long_msg_append . $output; + $long_msg_append = ', '; + + if (!$self->{output}->is_status(litteral => 1, value => $exit2, compare => 'ok')) { + $short_msg .= $short_msg_append . $output; + $short_msg_append = ', '; + } + + $maps_counters->{int}->{$_}->{obj}->perfdata(extra_instance => $multiple); + } + + $self->{output}->output_add(long_msg => "Interface '" . $self->{interface_selected}->{$id}->{display} . "' $long_msg"); + my $exit = $self->{output}->get_most_critical(status => [ @exits ]); + if (!$self->{output}->is_status(litteral => 1, value => $exit, compare => 'ok')) { + $self->{output}->output_add(severity => $exit, + short_msg => "Inteface '" . $self->{interface_selected}->{$id}->{display} . "' $short_msg" + ); + } + + if ($multiple == 0) { + $self->{output}->output_add(short_msg => "Interface '" . $self->{interface_selected}->{$id}->{display} . "' $long_msg"); + } + } + + $self->{statefile_value}->write(data => $self->{new_datas}); + $self->{output}->display(); + $self->{output}->exit(); +} + +sub get_severity { + my ($self, %options) = @_; + my $status = 'UNKNOWN'; # default + + if (defined($self->{overload_th}->{$options{section}})) { + foreach (@{$self->{overload_th}->{$options{section}}}) { + if ($options{value} =~ /$_->{filter}/i) { + $status = $_->{status}; + return $status; + } + } + } + foreach (@{$self->{thresholds_status}->{$options{section}}}) { + if ($options{value} =~ /$$_[0]/i) { + $status = $$_[1]; + return $status; + } + } + + return $status; +} + +sub get_display_value { + my ($self, %options) = @_; + my $value = $self->{statefile_cache}->get(name => $self->{option_results}->{oid_display} . "_" . $options{id}); + + if (defined($self->{option_results}->{display_transform_src})) { + $self->{option_results}->{display_transform_dst} = '' if (!defined($self->{option_results}->{display_transform_dst})); + eval "\$value =~ s{$self->{option_results}->{display_transform_src}}{$self->{option_results}->{display_transform_dst}}"; + } + return $value; +} +sub reload_cache { + my ($self) = @_; + my $datas = {}; + + $datas->{oid_filter} = $self->{option_results}->{oid_filter}; + $datas->{oid_display} = $self->{option_results}->{oid_display}; + $datas->{last_timestamp} = time(); + $datas->{all_ids} = []; + + my $snmp_get = [ + { oid => $self->{oids_label}->{$self->{option_results}->{oid_filter}} }, + ]; + if ($self->{option_results}->{oid_filter} ne $self->{option_results}->{oid_display}) { + push @{$snmp_get}, { oid => $self->{oids_label}->{$self->{option_results}->{oid_display}} }; + } + + my $result = $self->{snmp}->get_multiple_table(oids => $snmp_get); + foreach ($self->{snmp}->oid_lex_sort(keys %{$result->{$self->{oids_label}->{$self->{option_results}->{oid_filter}}}})) { + /\.([0-9]+)$/; + push @{$datas->{all_ids}}, $1; + $datas->{$self->{option_results}->{oid_filter} . "_" . $1} = $self->{output}->to_utf8($result->{$self->{oids_label}->{$self->{option_results}->{oid_filter}}}->{$_}); + } + + if (scalar(@{$datas->{all_ids}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "Can't construct cache..."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{oid_filter} ne $self->{option_results}->{oid_display}) { + foreach ($self->{snmp}->oid_lex_sort(keys %{$result->{$self->{oids_label}->{$self->{option_results}->{oid_display}}}})) { + /\.([0-9]+)$/; + $datas->{$self->{option_results}->{oid_display} . "_" . $1} = $self->{output}->to_utf8($result->{$self->{oids_label}->{$self->{option_results}->{oid_display}}}->{$_}); + } + } + + $self->{statefile_cache}->write(data => $datas); +} + +sub get_selection { + my ($self, %options) = @_; + + # init cache file + my $has_cache_file = $self->{statefile_cache}->read(statefile => 'cache_snmpstandard_' . $self->{hostname} . '_' . $self->{snmp_port} . '_' . $self->{mode}); + if (defined($self->{option_results}->{show_cache})) { + $self->{output}->add_option_msg(long_msg => $self->{statefile_cache}->get_string_content()); + $self->{output}->option_exit(); + } + + $self->{interface_selected} = {}; + my $timestamp_cache = $self->{statefile_cache}->get(name => 'last_timestamp'); + my $oid_display = $self->{statefile_cache}->get(name => 'oid_display'); + my $oid_filter = $self->{statefile_cache}->get(name => 'oid_filter'); + if ($has_cache_file == 0 || + ($self->{option_results}->{oid_display} !~ /^($oid_display|$oid_filter)$/i || $self->{option_results}->{oid_filter} !~ /^($oid_display|$oid_filter)$/i) || + !defined($timestamp_cache) || ((time() - $timestamp_cache) > (($self->{option_results}->{reload_cache_time}) * 60))) { + $self->reload_cache(); + $self->{statefile_cache}->read(); + } + + my $all_ids = $self->{statefile_cache}->get(name => 'all_ids'); + if (!defined($self->{option_results}->{use_name}) && defined($self->{option_results}->{interface})) { + foreach (@{$all_ids}) { + if ($self->{option_results}->{interface} =~ /(^|\s|,)$_(\s*,|$)/) { + $self->{interface_selected}->{$_} = { display => $self->get_display_value(id => $_) }; + } + } + } else { + foreach (@{$all_ids}) { + my $filter_name = $self->{statefile_cache}->get(name => $self->{option_results}->{oid_filter} . "_" . $_); + next if (!defined($filter_name)); + if (!defined($self->{option_results}->{interface})) { + $self->{interface_selected}->{$_} = { display => $self->get_display_value(id => $_) }; + next; + } + if ($filter_name =~ /$self->{option_results}->{interface}/) { + $self->{interface_selected}->{$_} = { display => $self->get_display_value(id => $_) }; + } + } + } + + if (scalar(keys %{$self->{interface_selected}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No entry found (maybe you should reload cache file)"); + $self->{output}->option_exit(); + } +} + +sub load_status { + my ($self, %options) = @_; + + $self->set_oids_status(); + $self->{snmp}->load(oids => [$self->{oid_adminstatus}, $self->{oid_opstatus}], instances => $self->{array_interface_selected}); +} + +sub load_traffic { + my ($self, %options) = @_; + + $self->set_oids_traffic(); + $self->{snmp}->load(oids => [$self->{oid_in32}, $self->{oid_out32}], instances => $self->{array_interface_selected}); + if ($self->{get_speed} == 1) { + $self->{snmp}->load(oids => [$self->{oid_speed32}], instances => $self->{array_interface_selected}); + } + if (!$self->{snmp}->is_snmpv1()) { + $self->{snmp}->load(oids => [$self->{oid_in64}, $self->{oid_out64}], instances => $self->{array_interface_selected}); + if ($self->{get_speed} == 1) { + $self->{snmp}->load(oids => [$self->{oid_speed64}], instances => $self->{array_interface_selected}); + } + } +} + +sub load_cast { + my ($self, %options) = @_; + + $self->set_oids_cast(); + $self->{snmp}->load(oids => [$self->{oid_ifInUcastPkts}, $self->{oid_ifInBroadcastPkts}, $self->{oid_ifInMulticastPkts}, + $self->{oid_ifOutUcastPkts}, $self->{oid_ifOutMulticastPkts}, $self->{oid_ifOutBroadcastPkts}], + instances => $self->{array_interface_selected}); + if (!$self->{snmp}->is_snmpv1()) { + $self->{snmp}->load(oids => [$self->{oid_ifHCInUcastPkts}, $self->{oid_ifHCInMulticastPkts}, $self->{oid_ifHCInBroadcastPkts}, + $self->{oid_ifHCOutUcastPkts}, $self->{oid_ifHCOutMulticastPkts}, $self->{oid_ifHCOutBroadcastPkts}], + instances => $self->{array_interface_selected}); + } +} + +sub get_informations { + my ($self, %options) = @_; + + $self->get_selection(); + $self->{array_interface_selected} = [keys %{$self->{interface_selected}}]; + $self->load_status() if (defined($self->{option_results}->{add_status})); + $self->load_traffic() if (defined($self->{option_results}->{add_traffic})); + $self->load_cast() if (defined($self->{option_results}->{add_cast})); + + $self->{results} = $self->{snmp}->get_leef(); + + foreach (@{$self->{array_interface_selected}}) { + $self->add_result_status(instance => $_) if (defined($self->{option_results}->{add_status})); + $self->add_result_traffic(instance => $_) if (defined($self->{option_results}->{add_traffic})); + $self->add_result_cast(instance => $_) if (defined($self->{option_results}->{add_cast})); + } +} + +sub add_result_status { + my ($self, %options) = @_; + + $self->{interface_selected}->{$options{instance}}->{opstatus} = $self->{oid_opstatus_mapping}->{$self->{results}->{$self->{oid_opstatus} . '.' . $options{instance}}}; + $self->{interface_selected}->{$options{instance}}->{admstatus} = $self->{oid_adminstatus_mapping}->{$self->{results}->{$self->{oid_adminstatus} . '.' . $options{instance}}}; +} + +sub add_result_traffic { + my ($self, %options) = @_; + + $self->{interface_selected}->{$options{instance}}->{mode_traffic} = 32; + $self->{interface_selected}->{$options{instance}}->{in} = $self->{results}->{$self->{oid_in32} . '.' . $options{instance}}; + $self->{interface_selected}->{$options{instance}}->{out} = $self->{results}->{$self->{oid_out32} . '.' . $options{instance}}; + if (!$self->{snmp}->is_snmpv1()) { + if (defined($self->{results}->{$self->{oid_in64} . '.' . $options{instance}}) && $self->{results}->{$self->{oid_in64} . '.' . $options{instance}} ne '' && + $self->{results}->{$self->{oid_in64} . '.' . $options{instance}} != 0) { + $self->{interface_selected}->{$options{instance}}->{mode_traffic} = 64; + $self->{interface_selected}->{$options{instance}}->{in} = $self->{results}->{$self->{oid_in64} . '.' . $options{instance}}; + $self->{interface_selected}->{$options{instance}}->{out} = $self->{results}->{$self->{oid_out64} . '.' . $options{instance}}; + } + } + $self->{interface_selected}->{$options{instance}}->{in} *= 8; + $self->{interface_selected}->{$options{instance}}->{out} *= 8; + + $self->{interface_selected}->{$options{instance}}->{speed_in} = 0; + $self->{interface_selected}->{$options{instance}}->{speed_out} = 0; + if ($self->{get_speed} == 0) { + if (defined($self->{option_results}->{speed}) && $self->{option_results}->{speed} ne '') { + $self->{interface_selected}->{$options{instance}}->{speed_in} = $self->{option_results}->{speed} * 1000000; + $self->{interface_selected}->{$options{instance}}->{speed_out} = $self->{option_results}->{speed} * 1000000; + } + $self->{interface_selected}->{$options{instance}}->{speed_in} = $self->{option_results}->{speed_in} * 1000000 if (defined($self->{option_results}->{speed_in}) && $self->{option_results}->{speed_in} ne ''); + $self->{interface_selected}->{$options{instance}}->{speed_out} = $self->{option_results}->{speed_out} * 1000000 if (defined($self->{option_results}->{speed_out}) && $self->{option_results}->{speed_out} ne ''); + } else { + my $interface_speed = 0; + if (defined($self->{results}->{$self->{oid_speed64} . "." . $options{instance}}) && $self->{results}->{$self->{oid_speed64} . "." . $options{instance}} ne '') { + $interface_speed = $self->{results}->{$self->{oid_speed64} . "." . $options{instance}} * 1000000; + # If 0, we put the 32 bits + if ($interface_speed == 0) { + $interface_speed = $self->{results}->{$self->{oid_speed32} . "." . $options{instance}}; + } + } else { + $interface_speed = $self->{results}->{$self->{oid_speed32} . "." . $options{instance}}; + } + + $self->{interface_selected}->{$options{instance}}->{speed_in} = $interface_speed; + $self->{interface_selected}->{$options{instance}}->{speed_out} = $interface_speed; + $self->{interface_selected}->{$options{instance}}->{speed_in} = $self->{option_results}->{speed_in} * 1000000 if (defined($self->{option_results}->{speed_in}) && $self->{option_results}->{speed_in} ne ''); + $self->{interface_selected}->{$options{instance}}->{speed_out} = $self->{option_results}->{speed_out} * 1000000 if (defined($self->{option_results}->{speed_out}) && $self->{option_results}->{speed_out} ne ''); + } +} + +sub add_result_cast { + my ($self, %options) = @_; + + $self->{interface_selected}->{$options{instance}}->{mode_cast} = 32; + $self->{interface_selected}->{$options{instance}}->{iucast} = $self->{results}->{$self->{oid_ifInUcastPkts} . '.' . $options{instance}}; + $self->{interface_selected}->{$options{instance}}->{ibcast} = defined($self->{results}->{$self->{oid_ifInBroadcastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifInBroadcastPkts} . '.' . $options{instance}} : 0; + $self->{interface_selected}->{$options{instance}}->{imcast} = defined($self->{results}->{$self->{oid_ifInMulticastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifInMulticastPkts} . '.' . $options{instance}} : 0; + $self->{interface_selected}->{$options{instance}}->{oucast} = $self->{results}->{$self->{oid_ifOutUcastPkts} . '.' . $options{instance}}; + $self->{interface_selected}->{$options{instance}}->{omcast} = defined($self->{results}->{$self->{oid_ifOutMulticastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifOutMulticastPkts} . '.' . $options{instance}} : 0; + $self->{interface_selected}->{$options{instance}}->{obcast} = defined($self->{results}->{$self->{oid_ifOutBroadcastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifOutBroadcastPkts} . '.' . $options{instance}} : 0; + if (!$self->{snmp}->is_snmpv1()) { + my $iucast = $self->{results}->{$self->{oid_ifHCInUcastPkts} . '.' . $options{instance}}; + if (defined($iucast) && $iucast =~ /[1-9]/) { + $self->{interface_selected}->{$options{instance}}->{iucast} = $iucast; + $self->{interface_selected}->{$options{instance}}->{imcast} = defined($self->{results}->{$self->{oid_ifHCInMulticastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifHCInMulticastPkts} . '.' . $options{instance}} : 0; + $self->{interface_selected}->{$options{instance}}->{ibcast} = defined($self->{results}->{$self->{oid_ifHCInBroadcastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifHCInBroadcastPkts} . '.' . $options{instance}} : 0; + $self->{interface_selected}->{$options{instance}}->{oucast} = $self->{results}->{$self->{oid_ifHCOutUcastPkts} . '.' . $options{instance}}; + $self->{interface_selected}->{$options{instance}}->{omcast} = defined($self->{results}->{$self->{oid_ifHCOutMulticastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifHCOutMulticastPkts} . '.' . $options{instance}} : 0; + $self->{interface_selected}->{$options{instance}}->{obcast} = defined($self->{results}->{$self->{oid_ifHCOutBroadcastPkts} . '.' . $options{instance}}) ? $self->{results}->{$self->{oid_ifHCOutBroadcastPkts} . '.' . $options{instance}} : 0; + $self->{interface_selected}->{$options{instance}}->{mode_cast} = 64; + } + } +} + + +1; + +__END__ + +=head1 MODE + +Check interfaces. + +=over 8 + +=item B<--add-status> + +Check interface status (By default if no --add-* option is set). + +=item B<--add-traffic> + +Check interface traffic. + +=item B<--add-cast> + +Check interface cast. + +=item B<--warning-*> + +Threshold warning. +Can be: 'in-ucast' (%), 'in-bcast' (%), 'in-mcast' (%), 'out-ucast' (%), 'out-bcast' (%), 'out-mcast' (%). + +=item B<--critical-*> + +Threshold critical. +Can be: 'in-ucast' (%), 'in-bcast' (%), 'in-mcast' (%), 'out-ucast' (%), 'out-bcast' (%), 'out-mcast' (%). + +=item B<--units-traffic> + +Units of thresholds for the traffic (Default: '%') ('%', 'b/s'). + +=item B<--threshold-overload> + +Set to overload default threshold values (syntax: section,status,regexp) +It used before default thresholds (order stays). +How to avoid errors on interface status: --threshold-overload='oper,OK,.*' + +=item B<--interface> + +Set the interface (number expected) ex: 1,2,... (empty means 'check all interface'). + +=item B<--name> + +Allows to use interface name with option --interface instead of interface oid index (Can be a regexp) + +=item B<--speed> + +Set interface speed for incoming/outgoing traffic (in Mb). + +=item B<--speed-in> + +Set interface speed for incoming traffic (in Mb). + +=item B<--speed-out> + +Set interface speed for outgoing traffic (in Mb). + +=item B<--reload-cache-time> + +Time in seconds before reloading cache file (default: 180). + +=item B<--oid-filter> + +Choose OID used to filter interface (default: ifName) (values: ifDesc, ifAlias, ifName). + +=item B<--oid-display> + +Choose OID used to display interface (default: ifName) (values: ifDesc, ifAlias, ifName). + +=item B<--display-transform-src> + +Regexp src to transform display value. (security risk!!!) + +=item B<--display-transform-dst> + +Regexp dst to transform display value. (security risk!!!) + +=item B<--show-cache> + +Display cache interface datas. + +=back + +=cut