#! /usr/bin/perl -w
# netflow.pl 2008.1020
# Randy Dunlap <rdunlap@xenotime.net>
#
# Changelog:
# version 0.
#
# Prints RX/TX traffic for one network interface,
# based on /proc/net/dev (without the leading '#'):
#Inter-|   Receive                                                |  Transmit
# face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
#    lo:   23864     396    0    0    0     0          0         0    23864     396    0    0    0     0       0          0
#  eth1:297253349  208453    0    0    0     0          0         0 16481340  204169    0    0    0     0       0          0
#  eth0:       0  785051    0    0    0     0          0         0        0   18700    0    0    0     0       1          0
#<<< wait 10 seconds  >>>
#Inter-|   Receive                                                |  Transmit
# face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
#    lo:   23864     396    0    0    0     0          0         0    23864     396    0    0    0     0       0          0
#  eth1:297253667  208456    0    0    0     0          0         0 16481580  204172    0    0    0     0       0          0
#  eth0:       0  786145    0    0    0     0          0         0        0   18726    0    0    0     0       1          0

my $netif = "eth0";
my $interval = 5;			# seconds to sleep between updates
my $loopcount = 0;			# number of loops to stay alive; 0 = forever

my $prevrxbytes = 0;
my $prevrxpackets = 0;
my $prevrxerrs = 0;
my $prevtxbytes = 0;
my $prevtxpackets = 0;
my $prevtxerrs = 0;

sub usage
{
	print "usage:  netflow.pl net_interface [delay_in_seconds [loop_count]]\n";
	print "  defaults: net_interface = eth0, delay = 5, count = forever\n";
} # end usage

sub do_stats
{
	my $tag = "";
	my $rest;
	my $stats;
	my @words;

	seek (DEV, 0, 0);		# to BOF
	while ($stats = <DEV>)		# DEV has multiple lines
	{
		chomp $stats;
		###print "raw stats: [$stats]\n";
		# split at ':' to look for netif
		($tag, $rest) = split /:/, $stats;
		$tag =~ s/ //g;
		print "tag = '$tag'\n";
		if ($tag !~ qq/$netif/)	# don't care about this line
		{
			next;
		}

		# split $rest into words
		@words = split / +/, $rest;
		###print "raw words: [@words]\n";
		last;
	}
	if ($tag !~ qq/$netif/)
	{
		print STDERR "net interface '$netif' not found\n";
		exit 1;
	}

	my ($rxbytes, $rxpackets, $rxerrs, $rxdrop, $rxfifo, $rxframe,
		$rxcompressed, $rxmcast, $txbytes, $txpackets, $txerrs,
		$txdrop, $txfifo, $txcollision, $txcarrier, $txcompressed) =
		@words;

	my $rxbytesrate = ($rxbytes - $prevrxbytes) / $interval;
	my $rxpacketsrate = ($rxpackets - $prevrxpackets) / $interval;
	my $rxerrsrate = ($rxerrs - $prevrxerrs) / $interval;
	my $txbytesrate = ($txbytes - $prevtxbytes) / $interval;
	my $txpacketsrate = ($txpackets - $prevtxpackets) / $interval;
	my $txerrsrate = ($txerrs - $prevtxerrs) / $interval;
	print "rxB = $rxbytes ($rxbytesrate / sec), rxP = $rxpackets ($rxpacketsrate / sec), ";
	print "rxE = $rxerrs ($rxerrsrate / sec)\n";
	print "txB = $txbytes ($txbytesrate / sec), txP = $txpackets ($txpacketsrate / sec), ";
	print "txE = $txerrs ($txerrsrate / sec)\n";

	$prevrxbytes = $rxbytes;
	$prevrxpackets = $rxpackets;
	$prevrxerrs = $rxerrs;
	$prevtxbytes = $txbytes;
	$prevtxpackets = $txpackets;
	$prevtxerrs = $txerrs;
} # end do_stats

###################### main ######################

if (scalar (@ARGV) > 0)
{
	$net_if = (shift (@ARGV));
	print "net_if changed from eth0 to $net_if\n";
}

if (scalar (@ARGV) > 0)
{
	$interval = int (shift (@ARGV));
	print "update interval changed from 5 seconds to $interval\n";
	if ($interval <= 0)
	{
		print "invalid interval: $interval\n";
		usage();
		exit 2;
	}
}

if (scalar (@ARGV) > 0)
{
	$loopcount = int (shift (@ARGV));
	print "update loopcount changed from 0 to $loopcount\n";
	if ($loopcount < 0)
	{
		print "invalid loopcount: $loopcount\n";
		usage();
		exit 2;
	}
}

# get /proc/cmdline and /proc/version one time only
open (PROCFILE, "</proc/cmdline") or die "cannot open /proc/cmdline\n";
$cmdline = <PROCFILE>;
chomp $cmdline;
close PROCFILE;

open (PROCFILE, "</proc/version") or die "cannot open /proc/version\n";
$version = <PROCFILE>;
chomp $version;
close PROCFILE;
 
open (DEV, "</proc/net/dev")       or die "cannot open /proc/net/dev\n";
 
$tm = localtime;
print "time: $tm\n";
print "cmdline: $cmdline\n";
print "version: $version\n";
print "==================================================\n";

# do until killed or loopcount times:
LOOPER:
while (1)
{
	$tm = localtime;
	print "time:  $tm\n";

	do_stats();			# /proc/net/dev file

	print "==================================================\n";
	sleep ($interval);

	if ($loopcount)			# is being used
	{
		$loopcount--;
		last LOOPER if $loopcount == 0;
	}
} # end forever/LOOPER


close (DEV);

exit 0;
# end netflow.pl
