2012-01-27 17:57:58 +01:00
|
|
|
#!/usr/bin/perl
|
|
|
|
# -*- perl -*-
|
2011-09-16 20:11:52 +02:00
|
|
|
|
2012-01-27 17:57:58 +01:00
|
|
|
=head1 NAME
|
2011-09-16 20:11:52 +02:00
|
|
|
|
|
|
|
bandwidth_ - Wildcard-plugin to monitor total network traffic and
|
2012-01-27 17:57:58 +01:00
|
|
|
predict 30 day bandwidth usage
|
2011-09-16 20:11:52 +02:00
|
|
|
|
|
|
|
=head1 CONFIGURATION
|
|
|
|
|
|
|
|
This is a wildcard plugin. To monitor an interface, link
|
|
|
|
bandwidth_<interface> to this file. E.g.
|
|
|
|
|
|
|
|
ln -s /usr/share/munin/node/plugins-auto/bandwidth_ \
|
|
|
|
/etc/munin/node.d/bandwidth_eth0
|
|
|
|
|
|
|
|
...will monitor eth0
|
|
|
|
|
|
|
|
Most likely usage is to monitor an interface connected to your ISP.
|
|
|
|
|
2012-01-27 17:57:58 +01:00
|
|
|
The suggest option will try and determine if you have any interfaces with a
|
|
|
|
public IP and if so it will suggest monitoring those interfaces. If all
|
|
|
|
IP addresses are private the setup will have to be done manually. Suggest
|
|
|
|
does not handle IPv6 addresses.
|
|
|
|
|
2013-04-23 16:59:32 +02:00
|
|
|
Environment Variables:
|
|
|
|
|
|
|
|
* monthlycap => monthly cap to draw warnings at in bytes
|
|
|
|
* uploadonly => if set display (and count against warnings) only upload bytes
|
|
|
|
|
2011-09-16 20:11:52 +02:00
|
|
|
=head1 USAGE
|
|
|
|
|
|
|
|
Any device found in /proc/net/dev can be monitored. Examples include ipsec*,
|
|
|
|
eth*, irda* and lo.
|
|
|
|
|
2012-01-27 17:57:58 +01:00
|
|
|
Please note that aliases cannot be monitored with this plugin.
|
2011-09-16 20:11:52 +02:00
|
|
|
|
|
|
|
=head1 VERSION
|
|
|
|
|
2013-04-23 16:50:58 +02:00
|
|
|
$Id: bandwidth_,v 1.37 2012/01/23 20:04:33 root Exp $
|
2011-09-16 20:11:52 +02:00
|
|
|
|
|
|
|
=head1 AUTHOR
|
|
|
|
|
|
|
|
Sean Whitney
|
|
|
|
|
|
|
|
=head1 LICENSE
|
|
|
|
|
|
|
|
GPLv2
|
|
|
|
|
|
|
|
=head1 MAGIC MARKERS
|
|
|
|
|
|
|
|
#%# family=contrib
|
|
|
|
#%# capabilities=autoconf suggest
|
|
|
|
|
|
|
|
=head1 BUGS
|
|
|
|
|
|
|
|
I know that bandwidth is bits and base10 as opposed to bytes and base2.
|
|
|
|
However the purpose of this plugin it to monitor your monthly bandwidth
|
|
|
|
consumption to make sure you don't go over your ISP's peak. ISP's seem
|
|
|
|
to be interested in expressing peaks in bytes....
|
|
|
|
|
|
|
|
=cut
|
2010-07-27 19:12:52 +02:00
|
|
|
|
2012-01-27 17:57:58 +01:00
|
|
|
use strict;
|
|
|
|
use Storable qw(store retrieve);
|
|
|
|
use Switch;
|
|
|
|
|
|
|
|
my $interface;
|
|
|
|
my $history;
|
|
|
|
my $counter_input;
|
|
|
|
my $counter_output;
|
|
|
|
my $input;
|
|
|
|
my $output;
|
|
|
|
my $uptime;
|
|
|
|
my $oldest_ts;
|
|
|
|
my $input_30days;
|
|
|
|
my $output_30days;
|
|
|
|
my $perf_ref = {};
|
|
|
|
my $count30 = 2592000; # The number of seconds in 30 days
|
|
|
|
my $unix_ts = time;
|
|
|
|
my $rollover = 4294967295;
|
|
|
|
|
2013-04-23 16:50:58 +02:00
|
|
|
my $monthlyCap = ($ENV{monthlycap} or 268435456000);
|
|
|
|
my $warnRate = $monthlyCap/$count30;
|
|
|
|
|
2013-04-23 04:18:40 +02:00
|
|
|
init();
|
2012-01-27 17:57:58 +01:00
|
|
|
|
|
|
|
sub autoconf {
|
|
|
|
$0 =~ /bandwidth_(.+)*$/;
|
|
|
|
$interface = $1;
|
|
|
|
$history = "/var/lib/munin/plugin-state/bandwidth_$interface.state";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub bit32or64 {
|
|
|
|
if ( $input > $rollover || $output > $rollover ) {
|
|
|
|
$rollover = 18446744073709551615;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub retrieve_history {
|
|
|
|
return (undef) unless ( -r $history );
|
|
|
|
my $store = retrieve($history);
|
|
|
|
while ( my ( $key, $value ) = each(%$store) ) {
|
|
|
|
if ( $unix_ts - $key < $count30 ) {
|
|
|
|
$perf_ref->{$key} = $value;
|
|
|
|
}
|
|
|
|
if ( $key =~ /last/ ) {
|
|
|
|
$perf_ref->{$key} = $value;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub suggest {
|
|
|
|
|
|
|
|
# This only works if one of your interfaces has a public IP,
|
|
|
|
# Otherwise it will fail and you will have to set it manually
|
|
|
|
# Multiple public IP addresses can be detected. It won't
|
|
|
|
# Detect IPv6 addresses.
|
|
|
|
my $locate = readpipe("locate -b '\\ifconfig'");
|
|
|
|
my @ifconfig = readpipe($locate);
|
|
|
|
my @old;
|
|
|
|
my $net = "/proc/net/dev";
|
|
|
|
my @interfaces;
|
|
|
|
-f $net || die "Unable to read $net: $!";
|
|
|
|
open( DEV, "<", $net ) || die "Unable to read $net: $!";
|
|
|
|
|
|
|
|
while (<DEV>) {
|
|
|
|
chomp;
|
|
|
|
split;
|
|
|
|
/Inter|face/ and next;
|
|
|
|
split /:/;
|
|
|
|
push( @interfaces, $_[0] );
|
|
|
|
}
|
|
|
|
close(DEV);
|
|
|
|
|
|
|
|
foreach (@ifconfig) {
|
|
|
|
if (/inet addr:([\d.]+)/) {
|
|
|
|
$1
|
|
|
|
=~ /^(127\.\d+|10\.\d+|172\.(1[6-9]|2\d|3[0-1])|192\.168)(\.\d+){2}$/
|
|
|
|
and next;
|
|
|
|
exists $interfaces[ $old[0] ] and print "$old[0]\n";
|
|
|
|
}
|
|
|
|
@old = split;
|
|
|
|
chomp @old;
|
|
|
|
}
|
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub store_history {
|
|
|
|
|
|
|
|
# Store the current values to the new old times
|
|
|
|
$perf_ref->{$unix_ts} = {
|
|
|
|
input => $input,
|
|
|
|
output => $output,
|
|
|
|
};
|
|
|
|
$perf_ref->{last} = {
|
|
|
|
counter_input => $counter_input,
|
|
|
|
counter_output => $counter_output,
|
|
|
|
uptime => $uptime,
|
|
|
|
};
|
|
|
|
store( $perf_ref, $history ) || die "Unable to store $history: $!";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub arg {
|
|
|
|
defined( $ARGV[0] ) or return;
|
|
|
|
switch ( $ARGV[0] ) {
|
|
|
|
case 'autoconf' { print "yes\n"; exit 0; }
|
|
|
|
case 'config' { print_config(); }
|
|
|
|
case 'suggest' { suggest(); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_config {
|
|
|
|
print <<EOM;
|
2013-04-23 17:01:07 +02:00
|
|
|
graph_title Monthly Bandwidth average ($interface)
|
2012-01-27 17:57:58 +01:00
|
|
|
graph_vlabel Bytes (per sec)
|
|
|
|
average.label current 30 day average bytes/sec
|
|
|
|
monthly.label monthly project based on 30 day average
|
|
|
|
30dayusage.label monthly usage
|
|
|
|
average.info Your average network rate based (up to) the last 30 days of data
|
|
|
|
monthly.info Your projected monthly network rate based on your average network rate
|
|
|
|
30dayusage.info Your usage for the last 30 days.
|
2010-07-27 19:12:52 +02:00
|
|
|
graph_category network
|
|
|
|
graph_args --base 1024 -l 0
|
2012-01-27 17:57:58 +01:00
|
|
|
graph_info This graph show your current average bandwidth usage and projected 30 day average based on your last 30 day usage.
|
2013-04-23 16:50:58 +02:00
|
|
|
average.warning $warnRate
|
|
|
|
monthly.warning $monthlyCap
|
|
|
|
30dayusage.warning $monthlyCap
|
2010-07-27 19:12:52 +02:00
|
|
|
EOM
|
2012-01-27 17:57:58 +01:00
|
|
|
exit 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub read_traffic {
|
|
|
|
open( my $rx, "<", "/sys/class/net/$interface/statistics/rx_bytes" )
|
|
|
|
|| die "Unable to read: $!";
|
|
|
|
$counter_input = <$rx>;
|
|
|
|
chomp $counter_input;
|
|
|
|
close($rx);
|
|
|
|
open(my $tx , "<", "/sys/class/net/$interface/statistics/tx_bytes" )
|
|
|
|
|| die "Unable to read: $!";
|
|
|
|
$counter_output = <$tx>;
|
|
|
|
chomp $counter_output;
|
|
|
|
close(DEV);
|
|
|
|
}
|
|
|
|
|
|
|
|
sub uptime {
|
|
|
|
my $puptime = "/proc/uptime";
|
|
|
|
open( TIME, "<", $puptime ) || die "Unable to read $puptime: $!";
|
|
|
|
while (<TIME>) {
|
|
|
|
split;
|
|
|
|
$uptime = @_[0];
|
|
|
|
}
|
|
|
|
close(TIME);
|
|
|
|
chomp $uptime;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub update_stats {
|
|
|
|
|
|
|
|
# First determine if this has ever run before. If not set initial values
|
|
|
|
# to 0.
|
|
|
|
if ( defined $perf_ref->{last}->{uptime} ) {
|
|
|
|
|
|
|
|
# Compute the new totals, caused by reboot. As uptime is measures in
|
|
|
|
# 64-bit jiffies, the chance of a counter rollover is remote
|
|
|
|
if ( $perf_ref->{last}->{uptime} > $uptime ) {
|
|
|
|
$input = $counter_input;
|
|
|
|
$output = $counter_output;
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ( $perf_ref->{last}->{counter_input} > $counter_input ) {
|
|
|
|
$input =
|
|
|
|
$counter_input
|
|
|
|
+ $rollover
|
|
|
|
- $perf_ref->{last}->{counter_input};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$input = $counter_input - $perf_ref->{last}->{counter_input};
|
|
|
|
}
|
|
|
|
if ( $perf_ref->{last}->{counter_output} > $counter_output ) {
|
|
|
|
$output =
|
|
|
|
$counter_output
|
|
|
|
+ $rollover
|
|
|
|
- $perf_ref->{last}->{counter_output};
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$output =
|
|
|
|
$counter_output - $perf_ref->{last}->{counter_output};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$input = 0;
|
|
|
|
$output = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sub sum_old {
|
|
|
|
$oldest_ts = $unix_ts;
|
|
|
|
while ( my ( $key, $value ) = each(%$perf_ref) ) {
|
|
|
|
$key =~ /last/ and next;
|
|
|
|
$input_30days += $perf_ref->{$key}->{'input'};
|
|
|
|
$output_30days += $perf_ref->{$key}->{'output'};
|
|
|
|
$key < $oldest_ts and $oldest_ts = $key
|
|
|
|
}
|
|
|
|
$input_30days += $input;
|
|
|
|
$output_30days += $output;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub munin_output {
|
|
|
|
my $period = $unix_ts - $oldest_ts;
|
2013-04-23 04:18:40 +02:00
|
|
|
return unless $period; #can't estimate anything from a single point, so don't.
|
2013-04-23 16:59:32 +02:00
|
|
|
my $total30 = $output_30days;
|
|
|
|
$total30 += $input_30days unless $ENV{uploadonly};
|
2012-01-27 17:57:58 +01:00
|
|
|
my $average30 = $total30 / $period;
|
|
|
|
print "average.value $average30\n";
|
|
|
|
print "monthly.value " . $average30 * $count30 . "\n";
|
|
|
|
print "30dayusage.value $total30\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
sub init {
|
|
|
|
autoconf();
|
2013-04-24 00:01:11 +02:00
|
|
|
arg();
|
|
|
|
exit 2 unless defined $interface;
|
2012-01-27 17:57:58 +01:00
|
|
|
retrieve_history();
|
|
|
|
read_traffic();
|
|
|
|
bit32or64();
|
|
|
|
uptime();
|
|
|
|
update_stats();
|
|
|
|
sum_old();
|
|
|
|
munin_output();
|
|
|
|
store_history();
|
|
|
|
}
|