#!/usr/bin/perl
#
# Simple script to do vmstat-like monitoring of network traffic.
#
# Authors:
#  Andre Tomt <andre@tomt.net>
# 

use strict;
use warnings;
use Carp;
use Perl6::Form;

# Defaults
my $dev = 'eth0';
my $delay = 5;
my $header_each = 22;
my $showsys = 0;

# Deal with command line options
while ( scalar @ARGV > 0 )
{
	my $option = shift;

    if ( $option eq '-s' )
    {
        $showsys = 1;
    }
	elsif ( $option eq '-w' )
	{
		$delay = shift;
	}
	elsif ( $option eq '-e' )
	{
		$header_each = shift;
	}
    elsif ( $option eq '--help' || $option eq '-h' )
    {
        showusage();
        exit 0;
    }
	elsif ( scalar @ARGV == 0 )
	{
		$dev = $option;
	}
	else {
		croak "Invalid option $option";
	}
}

# Validate them
croak "-w value not numeric"         if $delay !~ /^\d+$/;
croak "-e value not numeric"         if $header_each !~ /^\d+$/;
croak "device specified not valid"   if $dev !~ /^[\w\.\:]+$/;


my $prev = devdata($dev);
my $cur = $prev;
#my $cur = \%{ $prev };

my $i = 0;
my $first = 1;

while ( 1 )
{
	$i++;
	
	if ( $i == 1 )
	{
		print "         <-- mbit/s -->      <-- mbyte/s -->    <-- kpacket/s -->\n";
		print "    dev      in     out           in     out           in     out\n";
		if ( $first == 1 )
		{
			sleep($delay);
			$first = 0;
		}
	}

	$cur = devdata($dev);

	my $timediff = ($cur->{'time'} - $prev->{'time'});
	
	my $deltas = {
		'txbits'     => ( ($cur->{'txbits'} - $prev->{'txbits'}) / $timediff ),
		'rxbits'     => ( ($cur->{'rxbits'} - $prev->{'rxbits'}) / $timediff ),

		'txbytes'    => ( ($cur->{'txbytes'} - $prev->{'txbytes'}) / $timediff ),
		'rxbytes'    => ( ($cur->{'rxbytes'} - $prev->{'rxbytes'}) / $timediff ),
		
		'txpackets'  => ( ($cur->{'txpackets'} - $prev->{'txpackets'}) / $timediff ),
		'rxpackets'  => ( ($cur->{'rxpackets'} - $prev->{'rxpackets'}) / $timediff ),
	};
	
	print form "{]]]]]} {]]]]]} {]]]]]}      {]]]]]} {]]]]]}      {]]]]]} {]]]]]}",
	  (
	    $dev,
	    sprintf("%.2f", ($deltas->{'rxbits'} / 1000 / 1000)),
	    sprintf("%.2f", ($deltas->{'txbits'} / 1000 / 1000)),
	    sprintf("%.2f", ($deltas->{'rxbytes'} / 1024 / 1024)),
	    sprintf("%.2f", ($deltas->{'txbytes'} / 1024 / 1024)),
	    sprintf("%.2f", ($deltas->{'rxpackets'} / 1000)),
	    sprintf("%.2f", ($deltas->{'txpackets'} / 1000))
	  );
	  
	$prev = $cur;
	sleep($delay);
	$i = 0 if $i == $header_each;
}
	

sub devdata
{
	my ($dev) = @_;

	open my $netdev, '<', '/proc/net/dev'
	  or croak "failed opening dev: $!";

	while ( my $line = <$netdev> )
	{
		next if $. <= 2;
		next if $line !~ /^( +)?$dev[\s\:]+/;
		$line =~ s/^ +//;

		my ($n_dev, $n_rxbytes, $n_rxpackets, $n_txbytes, $n_txpackets) = (split(/[ :]+/, $line))[0,1,2,9,10];
	
		my $data = {
			'time' => time,
			'rxbytes' => $n_rxbytes,
			'rxbits' => $n_rxbytes * 8,
			'rxpackets' => $n_rxpackets,
			'txbytes' => $n_txbytes,
			'txbits' => $n_txbytes * 8,
			'txpackets' => $n_txpackets,
		};

		close $netdev;
		return $data;
	}

    croak "No matching device found..";
}

sub showusage
{
    print "$0 [options] <device>\n\n";
    print "Where [options] can be:\n";
    print " -e <n>   print header each n times\n";
    print " -w <n>   pause n second between each line\n";
    print " -s       show system resource counters too\n";
}
