#!@@PERL@@ -w # -*- cperl -*- =head1 NAME snmp__if_ - SNMP wildcard plugin to monitor network interfaces of any networked equipment. =head1 APPLICABLE SYSTEMS Any SNMP capable networked computer equipment. Using a command such as "munin-node-configure --snmp switch.langfeldt.net --snmpversion 2c --snmpcommunity public | sh -x" should auto-detect all applicable interfaces. On a typical switch you will get one plugin pr. ethernet port. On a router you might get one plugin pr. VLAN interface. =head1 CONFIGURATION As a rule SNMP plugins need site specific configuration. The default configuration (shown here) will only work on insecure sites/devices: [snmp_*] env.version 2 env.community public In general SNMP is not very secure at all unless you use SNMP version 3 which supports authentication and privacy (encryption). But in any case the community string for your devices should not be "public". Please see 'perldoc Munin::Plugin::SNMP' for further configuration information. Specific interface names (labels) are determined via the SNMP OID for aliases (1.3.6.1.2.1.31.1.1.1.18.*). These can be overridden via the "alias" environment variable: [snmp_hostname.fqdn_if_2] env.alias WAN The symlink name of the plugin determines the host and the switch port. The switch port may be a number or the interface name (e.g. "ethN.VID@ethN"). This is primarily useful on devices where the interface number is not guaranteed to be consistent, such as is the case with some Linux based systems. =head1 INTERPRETATION The graph shows a stright forward "bits per second" incomming and outgoing thruput. "Incomming" is towards the monitored device. Note: The internal representation of the speeds is in bytes pr. second. The plugin multiplies everyting by 8 to get bits pr. second. =head1 MIB INFORMATION This plugin requires the IF-MIB the standard IETF MIB for network interfaces. It reports the contents of the IF-MIB::ifHCInOctets/IF-MIB::ifHCOutOctets if available, IF-MIB::ifInOctets/IF-MIB::ifOutOctets if not. The former are 64 bit counters only available with SNMP 2 and later. The later are 32 bit counters (see FEATURES below). =head1 MAGIC MARKERS #%# family=snmpauto #%# capabilities=snmpconf =head1 BUGS None known. =head1 FEATURES You may get strange results if you use SNMPv1, or SNMPv2 on switches that do not support 64 bit byte counters. If the interface traffic exceeds about 50Mbps a 32 bit byte counter will wrap around in less than 5 minutes making the graph for the interface show random results. If you have a switch/device that supports 64 bit byte counters this plugin will use them and the graph will be fine. The graph information will inform about this. You must use SNMPv2c or SNMPv3 to be able to use 64 bit counters - if the device supports them. This problem is a feature of the device SNMP implementation or your usage of it, it is nothing the plugin can fix. In the future Munin may be able to run the plugin more often than the counter wraps around. =head1 AUTHOR Copyright (C) 2004-2009 Jimmy Olsen, Daginn Ilmari Mannsåker. Documentation, porting to Munin::Plugin::SNMP and further grooming by Nicolai Langfeldt. Initial SNMPv3 support by "Confusedhacker". =head1 LICENSE GPLv2 =cut use strict; use Munin::Plugin; use Munin::Plugin::SNMP; my $response; my $iface; # This is the snmpwalk: # .1.3.6.1.2.1.2.1.0 = INTEGER: 2 # .1.3.6.1.2.1.2.2.1.1.1 = INTEGER: 1 # .1.3.6.1.2.1.2.2.1.1.65539 = INTEGER: 65539 # .1.3.6.1.2.1.2.2.1.2.1 = STRING: MS TCP Loopback interface # .1.3.6.1.2.1.2.2.1.2.65539 = STRING: Broadcom NetXtreme Gigabit Ethernet # .1.3.6.1.2.1.2.2.1.3.1 = INTEGER: softwareLoopback(24) # .1.3.6.1.2.1.2.2.1.3.65539 = INTEGER: ethernetCsmacd(6) # .1.3.6.1.2.1.2.2.1.4.1 = INTEGER: 1520 # .1.3.6.1.2.1.2.2.1.4.65539 = INTEGER: 1500 # .1.3.6.1.2.1.2.2.1.5.1 = Gauge32: 10000000 # .1.3.6.1.2.1.2.2.1.5.65539 = Gauge32: 1000000000 # .1.3.6.1.2.1.2.2.1.6.1 = STRING: # .1.3.6.1.2.1.2.2.1.6.65539 = STRING: 0:30:48:75:65:5e # .1.3.6.1.2.1.2.2.1.7.1 = INTEGER: up(1) # .1.3.6.1.2.1.2.2.1.7.65539 = INTEGER: up(1) # .1.3.6.1.2.1.2.2.1.8.1 = INTEGER: up(1) # .1.3.6.1.2.1.2.2.1.8.65539 = INTEGER: up(1) # # 64 bit counters: # .1.3.6.1.2.1.31.1.1.1.6. Counter64 ifHCInOctets # .1.3.6.1.2.1.31.1.1.1.10. Counter64 ifHCOutOctets if (defined $ARGV[0] and $ARGV[0] eq "snmpconf") { print "index 1.3.6.1.2.1.2.2.1.1.\n"; print "require 1.3.6.1.2.1.2.2.1.5. [1-9]\n"; # Speed print "require 1.3.6.1.2.1.2.2.1.10. [1-9]\n"; # ifInOctets exit 0; } my ($session, $error); # SNMP needed for both config and fetch. $session = Munin::Plugin::SNMP->session(); $session->translate([-nosuchinstance => 0]); if ($Munin::Plugin::me =~ /_if_(\d+)$/) { # Also accept leading 0 like (snmp_router_if_01 .. snmp_router_if_24) $iface = int $1; } elsif ($Munin::Plugin::me =~ /_if_([\w\@.-]+)$/) { my $ifAliasContainer = "1.3.6.1.2.1.31.1.1.1.18."; my $if_alias = $session->get_by_regex($ifAliasContainer, "^$1\$"); if (keys(%{$if_alias}) != 1) { die "Could not determine interface number from ".$Munin::Plugin::me."\n"; } $iface = (keys %{$if_alias})[0]; } else { die "Could not determine interface number from ".$Munin::Plugin::me."\n"; } my $ifEntryDescr = "1.3.6.1.2.1.2.2.1.2.$iface"; my $ifEntryHiSpeed = "1.3.6.1.2.1.31.1.1.1.15.$iface"; my $ifEntrySpeed = "1.3.6.1.2.1.2.2.1.5.$iface"; my $ifEntryStatus = "1.3.6.1.2.1.2.2.1.8.$iface"; my $ifEntryInOctets = "1.3.6.1.2.1.2.2.1.10.$iface"; my $ifEntryOutOctets = "1.3.6.1.2.1.2.2.1.16.$iface"; # Only available with SNMPv2 and up. my $ifEntryAlias = "1.3.6.1.2.1.31.1.1.1.18.$iface"; my $ifEntryIn64Octets = "1.3.6.1.2.1.31.1.1.1.6.$iface"; my $ifEntryOut64Octets = "1.3.6.1.2.1.31.1.1.1.10.$iface"; if ($ARGV[0] and $ARGV[0] eq "config") { my ($host,undef,$version) = Munin::Plugin::SNMP->config_session(); print "host_name $host\n" unless $host eq 'localhost'; my $alias = $ENV{alias} || $session->get_single($ifEntryAlias) || $session->get_single($ifEntryDescr) || "Interface $iface"; if (! ($alias =~ /\d+/ or defined($ENV{alias})) ) { # If there are no numbers in the $alias add the if index $alias .=" (if $iface)"; } my $extrainfo = ''; if (defined ($response = $session->get_single($ifEntryStatus))) { if ($response == 2) { # Interface is down $extrainfo .= ' The interface is currently down.' } } my $warn = undef; my $speed = undef; if (defined ($speed = $session->get_single($ifEntrySpeed))) { # ifSpeed only supports values up to 4.3Gbps, because it's a # 32-bit value. For faster interfaces, e.g. 10GE or 8Gb/s FC, # use ifHighSpeed instead, which contains the interface speed # in Mbps (e.g. 1000 for GE). # # To detect whether we should use ifHighSpeed, check for an # ifSpeed value of 2^32-1 (4294967295). For some reason # Brocade Fabric OS returns 2^32-2 instead, so check that as # well. if ($speed == 4294967294 || $speed == 4294967295) { $speed = $session->get_single($ifEntryHiSpeed) * 1000 * 1000; } $warn = ($speed/10)*8; # Warn at 1/8th of actuall speed? Or just remove warning? # Tempted to set warning at 80%. 80% over 5 minutes is pretty # busy. my $textspeed = scaleNumber($speed,,'bps','', 'The interface speed is %.1f%s%s.'); $extrainfo .= " ".$textspeed if $textspeed; } if (defined ($session->get_single($ifEntryIn64Octets)) && !($session->get_single($ifEntryIn64Octets) eq '')) { # If we get an answer at the 64 bit OID then this switch # supports the extended MIB $extrainfo .= " This switch supports 64 bit byte counters and these are used by this plugin."; } else { # If not we only have a 32 bit counter and are lost. $extrainfo .= " NOTE! This switch supports only 32 bit byte counters which makes the plugin unreliable and unsuitable for most 100Mb (or faster) interfaces, where bursts are expected to exceed 50Mbps. This means that for interfaces where much traffic is sent this plugin will report false thruputs and cannot be trusted."; # unless perhaps the operator can get us snmp version 2c or 3? $extrainfo .= " I notice that you use SNMP version 1 which does not support 64 bit quantities. You may get better results if you switch to SNMP version 2c or 3. Please refer to the plugin documentation." if $version == 1; } print "graph_title Interface $alias traffic\n"; print "graph_order recv send\n"; print "graph_args --base 1000\n"; print "graph_vlabel bits in (-) / out (+) per \${graph_period}\n"; print "graph_category network\n"; print "graph_info This graph shows traffic for the \"$alias\" network interface.$extrainfo\n"; print "send.info Bits sent/received by this interface.\n"; print "recv.label recv\n"; print "recv.type DERIVE\n"; print "recv.graph no\n"; print "recv.cdef recv,8,*\n"; print "recv.max $speed\n" if $speed; print "recv.min 0\n"; print "recv.warning ", ($warn), "\n" if defined $warn && ($warn != 0); print "send.label bps\n"; print "send.type DERIVE\n"; print "send.negative recv\n"; print "send.cdef send,8,*\n"; print "send.max $speed\n" if $speed; print "send.min 0\n"; print "send.warning $warn\n" if defined $warn && ($warn != 0); exit 0; } if (defined ($response = $session->get_single($ifEntryStatus))) { if ($response == 2) { # Interface is down print "recv.value U\n"; print "send.value U\n"; exit 0; } } if (defined ($response = $session->get_single($ifEntryIn64Octets) || $session->get_single($ifEntryInOctets))) { print "recv.value ", $response, "\n"; } else { # No response... print "recv.value U\n"; } if (defined ($response = $session->get_single($ifEntryOut64Octets) || $session->get_single($ifEntryOutOctets))) { print "send.value ", $response, "\n"; } else { # No response... print "send.value U\n"; }