#!/usr/bin/perl -w # nagios: -epn use strict; use Net::SNMP; use Getopt::Long; use Pod::Usage; my $rmon_oid = '.1.3.6.1.2.1.2.2.1.2'; my $name_oid = '.1.3.6.1.2.1.31.1.1.1.1'; my $in_oct_oid = '.1.3.6.1.2.1.2.2.1.10'; my $out_oct_oid = '.1.3.6.1.2.1.2.2.1.16'; my $in_uni_pkt_oid = '.1.3.6.1.2.1.2.2.1.11'; my $out_uni_pkt_oid = '.1.3.6.1.2.1.2.2.1.17'; my $in_non_uni_pkt_oid = '.1.3.6.1.2.1.2.2.1.12'; my $out_non_uni_pkt_oid = '.1.3.6.1.2.1.2.2.1.18'; sub snmp_walk($$$) { my $session = shift; my $start = shift; my $callback = shift; my $oid = $start; while (1) { my $results = $session->get_next_request( -varbindlist => [ $oid ] ); nagios_die($session->error()) unless $results; foreach my $result (keys %{ $results }) { return unless index($result, "${start}.") eq 0; $oid = $result; $callback->($start, $result, $results->{$result}); } } } sub get_ifaces($) { my $session = shift; my $IFACES; snmp_walk($session, $rmon_oid, sub ($$) { my $root = shift; my $oid = shift; my $value = shift; if ($value =~ m/Ethernet|Port/) { my $id = substr($oid, length($root) + 1); $value =~ s/RMON://; $IFACES->{$id}{'name'} = $value; $IFACES->{$id}{'in'} = 0; $IFACES->{$id}{'out'} = 0; } }); return $IFACES; } sub generate_oids ($@) { my $root = shift; my @results = (); foreach my $val (@_) { push(@results, "${root}.${val}"); } return @results; } sub get_info ($$$$) { my $session = shift; my $in_oid = shift; my $out_oid = shift; my $IFACES = shift; foreach my $root ($name_oid, $in_oid, $out_oid) { my $info = $session->get_request( -varbindlist => [ generate_oids($root, keys %{ $IFACES }) ] ); if (defined $info) { foreach my $oid (keys %{ $info }) { if (index($oid, $name_oid) eq 0) { if ($info->{$oid}) { my $id = substr($oid, length($name_oid) + 1); $IFACES->{$id}{'name'} = $info->{$oid}; } } elsif (index($oid, $in_oid) eq 0) { my $id = substr($oid, length($in_oid) + 1); $IFACES->{$id}{'in'} = $info->{$oid}; } elsif (index($oid, $out_oid) eq 0) { my $id = substr($oid, length($out_oid) + 1); $IFACES->{$id}{'out'} = $info->{$oid}; } } } else { nagios_die($session->error()); } } return $IFACES; } sub nagios_die ($) { my $err = shift; $err = "Unknown error" unless defined $err; print "SNMP UNKNOWN - $err\n"; exit 3; } my $host; my $port = 161; my $community = 'public'; my $timeout = 10; my $packets = 0; my $non_unicast_packets = 0; my $help = 0; Getopt::Long::Configure ("bundling"); GetOptions('host|H=s' => \$host, 'port|p=i' => \$port, 'community|C=s' => \$community, 'timeout|t=i' => \$timeout, 'packets' => \$packets, 'non-unicast-packets' => \$non_unicast_packets, 'help|?' => \$help) or pod2usage(2); pod2usage(0) if $help; pod2usage(2) unless (defined $host); $SIG{'ALRM'} = sub { nagios_die('Check timed out'); }; alarm($timeout); my ($session, $err) = Net::SNMP->session( -hostname => $host, -port => $port, -community => $community ); nagios_die($err) unless defined $session; my $in_oid; my $out_oid; if ($non_unicast_packets) { $in_oid = $in_non_uni_pkt_oid; $out_oid = $out_non_uni_pkt_oid; } elsif ($packets) { $in_oid = $in_uni_pkt_oid; $out_oid = $out_uni_pkt_oid; } else { $in_oid = $in_oct_oid; $out_oid = $out_oct_oid; } my $IFACES = get_ifaces($session); get_info($session, $in_oid, $out_oid, $IFACES); $session->close(); my $channel = grep { $IFACES->{$_}{'name'} =~ /^ch/} keys %{ $IFACES }; my $if = grep { $IFACES->{$_}{'name'} !~ /^ch/} keys %{ $IFACES }; print "SNMP OK - $if interfaces, $channel port channel |"; foreach my $key (sort {$a <=> $b} keys %{ $IFACES }) { printf " %s(in)=%sc; %s(out)=%sc;", $IFACES->{$key}{'name'}, $IFACES->{$key}{'in'}, $IFACES->{$key}{'name'}, $IFACES->{$key}{'out'}; } print "\n"; exit 0; __END__ =head1 check_snmp_switch_traffic check_snmp_switch_traffic - Monitor switch ports via SNMP =head1 SYNOPSIS check_snmp_swtich_traffic --host|-H HOSTNAME [options] =item B --port|-p PORT --community|-C COMMUNITY --timeout|-t TIMEOUT --packets --non-unicast-packets --help|-? =head1 OPTIONS =over 8 =item B<--host|-H> Specify the host to connect to via SNMP. This option is required. =item B<--port|-p> Port to connect to. If not specified it defaults to 161. =item B<--community|-C> SNMPv1 Community string. If not specified it defaults to "public". =item B<--timeout|-t> Maximum runtime in seconds of this script before returning UNKNOWN. If not specified it defaults to 10. =item B<--packets> Get the counter for the send and received unicast packets. =item B<--non-unicast-packets> Get the counter for the send and received non unicast packets. If B<--packets> and B<--non-unicast-packets> are given, the B<--packets> switch is ignored. =item B<--help|-?> Display a help message about the available options. =back =head1 DESCRIPTION B fetches the available ports of a switch and queries the in and out octet counters via SNMP. It is also possible to get the counter for unicast and non-unicast packets. =cut