changes to log network traffic
authorbdemsky <bdemsky>
Wed, 28 Jan 2009 21:40:21 +0000 (21:40 +0000)
committerbdemsky <bdemsky>
Wed, 28 Jan 2009 21:40:21 +0000 (21:40 +0000)
Robust/src/Benchmarks/Prefetch/html/README [new file with mode: 0644]
Robust/src/Benchmarks/Prefetch/run.sh
Robust/src/Benchmarks/Prefetch/switch/fetch_stat.pl [new file with mode: 0755]

diff --git a/Robust/src/Benchmarks/Prefetch/html/README b/Robust/src/Benchmarks/Prefetch/html/README
new file mode 100644 (file)
index 0000000..2a612bd
--- /dev/null
@@ -0,0 +1 @@
+Directory is for the Output of Script
index abdb5a02ca201131ece81db7d9492628bf186bf9..ba24705fe6bc3147b5ce3a1493b5b59d241646ac 100755 (executable)
@@ -2,8 +2,9 @@
 
 #set -x
 MACHINELIST='dc-1.calit2.uci.edu dc-2.calit2.uci.edu dc-3.calit2.uci.edu dc-4.calit2.uci.edu dc-5.calit2.uci.edu dc-6.calit2.uci.edu dc-7.calit2.uci.edu dc-8.calit2.uci.edu'
+benchmarks='1152fft2d 40962dconv 20482dconv 600mmver moldynverA em3dver40001306'
 
-LOGDIR=/home/adash/research/Robust/src/Benchmarks/Prefetch/runlog
+LOGDIR=~/research/Robust/src/Benchmarks/Prefetch/runlog
 TOPDIR=`pwd`
 
 function run {
@@ -52,7 +53,14 @@ function run {
       echo ""
     done
     sleep 2
-    /usr/bin/time -f "%e" ./$3 master $arg 2>> ${LOGDIR}/${2}Thrd_${3}_${EXTENSION}.txt
+    perl -x${TOPDIR} ${TOPDIR}/switch/fetch_stat.pl clear_stats settings=switch/clearsettings.txt
+    /usr/bin/time -f "%e" ./$3 master $arg 2> ${LOGDIR}/tmp
+    perl -x${TOPDIR} ${TOPDIR}/switch/fetch_stat.pl settings=switch/settings.txt
+    cat ${LOGDIR}/tmp >> ${LOGDIR}/${2}Thrd_${3}_${EXTENSION}.txt
+    if [ $i -eq 0 ];then echo "<h3> Benchmark=${3} Thread=${2} Extension=${EXTENSION}</h3><br>" > ${LOGDIR}/${3}_${EXTENSION}_${2}Thrd_a.html  ;fi
+    cat ${LOGDIR}/tmp >> ${LOGDIR}/${3}_${EXTENSION}_${2}Thrd_a.html
+    echo "<a href=\"${2}Thrd_${3}_${EXTENSION}_${i}.html\">Network Stats</a><br>" >> ${LOGDIR}/${3}_${EXTENSION}_${2}Thrd_a.html
+    mv ${TOPDIR}/html/dell.html ${LOGDIR}/${2}Thrd_${3}_${EXTENSION}_${i}.html
     echo "Terminating ... "
     for machine in `echo $MACHINES`
     do
@@ -90,7 +98,11 @@ function localrun {
 # done
   i=0;
   while [ $i -lt $1 ]; do
-    /usr/bin/time -f "%e" ./${NONPREFETCH_NONCACHE} master $ARGS1 2>> ${LOGDIR}/${NONPREFETCH_NONCACHE}_local_${EXTENSION}.txt
+    /usr/bin/time -f "%e" ./${NONPREFETCH_NONCACHE} master $ARGS1 2> ${LOGDIR}/tmp
+    cat ${LOGDIR}/tmp >> ${LOGDIR}/${NONPREFETCH_NONCACHE}_local_${EXTENSION}.txt
+    if [ $i -eq 0 ];then echo "<h3> Benchmark=${NONPREFETCH_NONCACHE} Thread=1local Extension=${EXTENSION}</h3><br>" > ${LOGDIR}/${NONPREFETCH_NONCACHE}_${EXTENSION}_1local_a.html  ;fi
+    cat ${LOGDIR}/tmp >> ${LOGDIR}/${NONPREFETCH_NONCACHE}_${EXTENSION}_1local_a.html
+    echo "<br>" >> ${LOGDIR}/${NONPREFETCH_NONCACHE}_${EXTENSION}_1local_a.html
     sleep 2
     i=`expr $i + 1`
   done
@@ -114,7 +126,7 @@ function callrun {
 #  oneremote 1 1 $PREFETCH
 
 
-for count in 2 3 4 5 6 7 8
+for count in 2 4 6 8
 do
 echo "------- Running $count threads $BMDIR non-prefetch + non-cache on $count machines -----"
 run 1 $count $NONPREFETCH_NONCACHE
@@ -138,7 +150,11 @@ function callrunjavasingle {
 function javasinglerun {
   i=0;
   while [ $i -lt $1 ]; do
-    /usr/bin/time -f "%e" ./${BENCHMARK}.bin $ARGS1 2>> ${LOGDIR}/${BENCHMARK}_javasingle_${EXTENSION}.txt
+    /usr/bin/time -f "%e" ./${BENCHMARK}.bin $ARGS1 2> ${LOGDIR}/tmp
+    cat ${LOGDIR}/tmp >> ${LOGDIR}/${BENCHMARK}_javasingle_${EXTENSION}.txt
+    if [ $i -eq 0 ];then echo "<h3> Benchmark=${BENCHMARK} Thread=1java Extension=${EXTENSION}</h3><br>" > ${LOGDIR}/${BENCHMARK}_${EXTENSION}_1java_a.html  ;fi
+    cat ${LOGDIR}/tmp >> ${LOGDIR}/${BENCHMARK}_${EXTENSION}_1java_a.html
+    echo "<br>" >> ${LOGDIR}/${BENCHMARK}_${EXTENSION}_1java_a.html
     sleep 2
     i=`expr $i + 1`
   done
@@ -160,7 +176,6 @@ function callmicrorun {
   cd $TOPDIR
 }
 
-benchmarks='1152fft2d 40962dconv 20482dconv 600mmver moldynverA'
 
 echo "---------- Clean old files ---------- "
 rm runlog/*
diff --git a/Robust/src/Benchmarks/Prefetch/switch/fetch_stat.pl b/Robust/src/Benchmarks/Prefetch/switch/fetch_stat.pl
new file mode 100755 (executable)
index 0000000..eb437c4
--- /dev/null
@@ -0,0 +1,2375 @@
+#!/usr/bin/perl\r
+##\r
+## fetch_stat.pl\r
+##\r
+## Fetches and summarizes stats from Dell PowerConnect 27xx\r
+## Written by Joakim Andersson, joakim at iqcc dot se\r
+##\r
+## 1) Install the Perl-modules you might be missing\r
+## 2) Adjust the settings in the settings-file\r
+## 3) Run the script\r
+##\r
+## Arguments: \r
+## clear_stats  - Clear the portstats when script starts\r
+## clear_session - Forces a cached session to be ignored, useful for testing only \r
+## clear_wraps   - Forgets about previous counter-wraps\r
+## settings=file - Read settings from this file\r
+##\r
+## For changelog please visit http://www.iqcc.se\r
+##\r
+\r
+my $ver = '1.42 (2007-04-19)';\r
+\r
+use 5.004;\r
+use strict;\r
+use Digest::MD5  qw(md5_hex);\r
+use LWP::UserAgent;\r
+use Net::HTTP;\r
+use Time::HiRes;\r
+\r
+####################################################\r
+##\r
+## File containing settings\r
+##\r
+\r
+my $SETTINGS_FILE = 'settings.txt';\r
+\r
+##################################################\r
+\r
+my @do_delta = qw(goodOctetRCV rxGood goodOctetSND txGood rx64Octets rx65TO127Octets rx128TO255Octets rx256TO511Octets rx512TO1023Octets rx1024ToMa );\r
+\r
+my $TR_COLOR = '#FFFF80';\r
+my %graph_names = ('bps' => 'bits per second', 'pps' => 'packets per second');\r
+my %graph_rev_type = ('bps' => 'pps', 'pps' => 'bps');\r
+\r
+my $cookie = '';\r
+\r
+my %SET = ( 'VERBOSE' => 3 );  # Settings\r
+my %STATS = ();                        # To maintain delta-stats \r
+my %OLD_STATS = ();            # To cache previous values\r
+my %PORTS = ();                        # To maintain non-statistics info about each port\r
+my %WRAPS = ();                        # To maintain counter-wraps\r
+my %system = ();               # System-info\r
+my @GRAPHS = ();               # Graphs to create\r
+my @do_ports = ();\r
+\r
+# Setting time\r
+my %time = ();\r
+&upd_time();\r
+\r
+# Looking for valid args\r
+my $clear_session = 0;\r
+my $clear_stat = 0;\r
+my $clear_wraps = 0;\r
+\r
+foreach (@ARGV)\r
+{\r
+       ($_, my $value) = split(/=/);\r
+       \r
+       if (/^clear_stats?$/)\r
+       {\r
+               $clear_stat = 1;\r
+       }\r
+       elsif (/^clear_sessions?$/)\r
+       {\r
+               $clear_session = 1;\r
+       }\r
+       elsif (/^clear_wraps?$/)\r
+       {\r
+               $clear_wraps = 1;\r
+       }\r
+       elsif (/^settings$/ && $value)\r
+       {\r
+               $SETTINGS_FILE = $value;\r
+       }\r
+}\r
+\r
+my $numberOfPorts = 0;\r
+my $numberOfTrunks = 0;\r
+\r
+# Reading settings\r
+# Will be refreshed when changed later\r
+if (&refresh_settings() == 2)\r
+{\r
+       ##\r
+       ## Errors in the settings!\r
+       ##\r
+       \r
+       die "Errors exists in '$SETTINGS_FILE', unable to start fetch_stat.pl $ver!";\r
+}\r
+\r
+# Settings was OK\r
+&log("fetch_stat.pl $ver started at $time{'date_time'}", $SET{'VERBOSE'});\r
+\r
+# Creating UserAgent-object\r
+my $ua = LWP::UserAgent->new();\r
+$ua->agent("Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");\r
+\r
+# Reads cached cookie, if wanted\r
+if ($SET{'COOKIE_FILE'})\r
+{\r
+       open (COOKIE, $SET{'COOKIE_FILE'}) || warn "Unable to open cookie-file $SET{'COOKIE_FILE'}, first run ever?\n";\r
+       $cookie = <COOKIE>;\r
+       close COOKIE;\r
+}\r
+\r
+if ($clear_session && $cookie)\r
+{\r
+       $cookie = '';\r
+       print "Cleared old session-cookie\n" if ($SET{'VERBOSE'});\r
+}\r
+elsif ($cookie)\r
+{\r
+       $cookie =~ tr/\n\r\t//d;\r
+       print "Trying to reuse old session-cookie '$cookie'\n" if ($SET{'VERBOSE'});\r
+       \r
+       # Fetches system info\r
+       # Will reset $cookie if failure\r
+       print "Polling link- and system info...\n" if ($SET{'VERBOSE'} >= 2);\r
+       &get_system_info;\r
+}\r
+\r
+##\r
+## If we don't have a valid session login and fetch system info again\r
+##\r
+\r
+unless ($cookie)\r
+{\r
+       &login;\r
+       print "Polling link- and system info...\n" if ($SET{'VERBOSE'} >= 2);\r
+       &get_system_info;\r
+}\r
+\r
+\r
+##\r
+## Reading or clearing wraps\r
+##\r
+\r
+if ($SET{'WRAPS_FILE'})\r
+{\r
+       if ($clear_wraps || $clear_stat)\r
+       {\r
+               ##\r
+               ## Removes cached wraps\r
+               ##\r
+               \r
+               if (-e $SET{'WRAPS_FILE'})\r
+               {\r
+                       &log("Clearing cached wraps", $SET{'VERBOSE'});\r
+                       unlink $SET{'WRAPS_FILE'};\r
+               }\r
+       }\r
+       else\r
+       {\r
+               ##\r
+               ## Reads cached wraps\r
+               ##\r
+               \r
+               open (WRAPS, $SET{'WRAPS_FILE'});\r
+               while (<WRAPS>)\r
+               {\r
+                       my ($name, $value) = split(/\t/, $_, 2);\r
+                       chop $value;\r
+                       \r
+                       $WRAPS{$name} = $value;\r
+                       #print "$name = $value\n";\r
+               }\r
+               close WRAPS;\r
+       }\r
+}\r
+\r
+##\r
+## Loops forever, hopefully\r
+##\r
+\r
+my $loop = 0;\r
+my $runtime = 'n/a';\r
+my $maxlen_portname = 10;\r
+my $autoadded_ports = 0;\r
+\r
+my %do_ports = {};\r
+#my @do_ports = ();\r
+\r
+print "\n" if ($SET{'VERBOSE'});       #Init complete\n\r
+$| = 1;\r
+\r
+while ( $loop == 0)\r
+{\r
+    $loop++;\r
+       ##\r
+       ## Refreshes settings if needed\r
+       ##\r
+       \r
+       my $settings_changed = &refresh_settings();\r
+       \r
+       if ($settings_changed == 2)\r
+       {\r
+               ##\r
+               ## Errors!\r
+               ##\r
+               \r
+               &log("Errors found in the settings, keeping the old settings!", $SET{'VERBOSE'});\r
+               #sleep $SET{'REFRESH_RATE'};\r
+               #next;\r
+               $settings_changed = 0;\r
+       }\r
+       elsif ($settings_changed || ($loop == 1) || $autoadded_ports)\r
+       {\r
+               ##\r
+               ## New settings read, or first loop\r
+               ## Also if ports has been auto-added\r
+               ##\r
+               \r
+               %do_ports = %{$SET{'PORTS'}};   # Ports on the switch\r
+\r
+               ##\r
+               ## Finds longest portname + clears stats if wanted\r
+               ##\r
+               \r
+               $maxlen_portname = 10;\r
+               foreach my $portnum (@do_ports)\r
+               {\r
+                       my $this_len = length($do_ports{$portnum});\r
+                       $maxlen_portname = $this_len if ($maxlen_portname < $this_len);\r
+                       \r
+                       ##\r
+                       ## Clears stats of these ports if program was called with arg clear_stat\r
+                       ##\r
+                       \r
+                       if ($clear_stat)\r
+                       {\r
+                               print "Clearing stats for port $portnum...\n" if ($SET{'VERBOSE'});\r
+                               &clear_stat($portnum);\r
+                       }\r
+               }\r
+\r
+               if ($clear_stat)\r
+               {\r
+                   exit;\r
+               }\r
+\r
+               $autoadded_ports = 0;\r
+       }\r
+       \r
+       ##\r
+       ## Login if we miss a valid session\r
+       ##\r
+       \r
+       &login unless ($cookie);\r
+       \r
+       # Remembers the time when this loop started\r
+       my $start_time = [ Time::HiRes::gettimeofday() ];\r
+       \r
+       # Updates time\r
+       &upd_time();\r
+       \r
+       ##\r
+       ## Polling every defined port\r
+       ##\r
+       \r
+       my $wraps_occured = 0;\r
+       print "Polling stats ($time{'time'})...\n" if ($SET{'VERBOSE'} >= 2);\r
+       \r
+       foreach my $portnum (@do_ports)\r
+       {\r
+               ##\r
+               ## Initiates the hashes\r
+               ##\r
+               \r
+               my $STAT = { 'time' => [ Time::HiRes::gettimeofday() ] };\r
+               my $OLD_STAT = $STATS{$portnum};\r
+               my $PORT = $PORTS{$portnum} ||= {};\r
+               \r
+               if ($SET{'VERBOSE'} >= 2)\r
+               {\r
+                       # Builds the info\r
+                       my $name = "$portnum:";\r
+                       print $name, ' ' x (6 - length($name));\r
+                       \r
+                       $name = $do_ports{$portnum};    #"$do_ports{$portnum}...";\r
+                       print $name, ' ' x ($maxlen_portname - length($name) + 2);\r
+               }\r
+               \r
+               ##\r
+               ## Is it a switchport or a local interface?\r
+               ##\r
+               \r
+               if ($portnum =~ /^T?\d+$/)\r
+               {\r
+                       ##\r
+                       ## Polls this port on the switch\r
+                       ##\r
+                       \r
+                       my $arg = ($portnum =~ /^T(\d+)$/) ? "TrunkNo=$1" : "PortNo=$portnum";\r
+                       \r
+                       # Fetches the page\r
+                       my $res = $ua->get("http://$SET{'SWITCH'}/portStats.htm?$arg",\r
+                              'Cookie' => $cookie\r
+                                );\r
+                       \r
+                       &log_n_die("Unable to fetch /portStats.htm?$arg - ".$res->status_line) unless ($res->is_success);\r
+                       \r
+                       # Parsing content\r
+                       my $data = $res->content;\r
+                       $data =~ tr/\r//d;\r
+                       \r
+                       if ($data =~ /^<title>Login<\/title>$/m)\r
+                       {\r
+                               ##\r
+                               ## Invalid session!\r
+                               ##\r
+                               \r
+                               &log("Session invalid", $SET{'VERBOSE'});\r
+                               \r
+                               $cookie = '';\r
+                               last;\r
+                       }\r
+                       \r
+                       ##\r
+                       ## Parses the data, is stored in javascript-variables in the beginning of the page\r
+                       ##\r
+                       \r
+                       my $row = 0;\r
+                       my $wraps = 0;\r
+                       my @wraps = ();\r
+                       \r
+                       foreach (split(/\n+/, $data))\r
+                       {\r
+                               $row++;\r
+                               #print "RAD $row: $_\n";\r
+                               \r
+                               last if (/^<\/script>$/);       # May need adjustment for future firmwares\r
+                               next unless (/^var (.+)="(\d*)";$/);\r
+                               \r
+                               my $name = $1;\r
+                               next if ($STAT->{$name});               # Skips already found variables, a bug in the current firmware\r
+                               \r
+                               my $value = reverse $2;         # Values are stored reversed in the HTML-page\r
+                               $value += 0;                            # Perhaps unneeded, but zero is better that nothing\r
+                               \r
+                               # To determine wraps we need the current value\r
+                               # Ugly as hell\r
+                               $STAT->{"curr:$name"} = $value;\r
+                               \r
+                               ##\r
+                               ## Adding previous wraps of this counter\r
+                               ##\r
+                               \r
+                               if ($WRAPS{"$portnum:$name"})\r
+                               {\r
+                                       $value += 4294967296 * $WRAPS{"$portnum:$name"};\r
+                               }\r
+                               \r
+                               ##\r
+                               ## Looking for wrapped counters\r
+                               ## 32bit counters is not enough\r
+                               ##                      \r
+                               \r
+                               if ($OLD_STAT && $value < $OLD_STAT->{$name})\r
+                               {\r
+                                       ##\r
+                                       ## We guess this is a wrap\r
+                                       ## With 32bit counters 4294967296 is the max value\r
+                                       ## Resets of the statistics may cause problems here\r
+                                       ##\r
+                                       \r
+                                       if ($wraps < 2)\r
+                                       {\r
+                                               ##\r
+                                               ## Max two wraps per poll is considered valid\r
+                                               ##\r
+                                               \r
+                                               my $tmp = ++$WRAPS{"$portnum:$name"};\r
+                                               my $new = $STAT->{"curr:$name"};\r
+                                               my $old = $OLD_STAT->{"curr:$name"};\r
+                                               \r
+                                               &log("$do_ports{$portnum} (port $portnum): Probable wrap of $name has occured. $old -> $new. (tot $OLD_STAT->{$name} -> $value, wraps $tmp)", $SET{'VERBOSE'} >= 3);\r
+                                               \r
+                                               $value += 4294967296;\r
+                                               \r
+                                               $wraps++;\r
+                                               $wraps_occured++;\r
+                                               push (@wraps, $name);\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               ##\r
+                                               ## Hmmm, this is probably *not* a wrap\r
+                                               ## Resetting the wrap-counter and old stats\r
+                                               ##\r
+                                       \r
+                                               &log("$do_ports{$portnum} (port $portnum): Wasn't wraps, most likely a reset of the stats instead. Resetting our old stats and wraps", $SET{'VERBOSE'} >= 3);\r
+                                               \r
+                                               undef $OLD_STAT;\r
+                                               delete $OLD_STATS{$portnum};\r
+                                               \r
+                                               # Reverting previous wraps\r
+                                               foreach (@wraps)\r
+                                               {\r
+                                                       $STAT->{$_} = $STAT->{"curr:$_"};\r
+                                               }\r
+                                               @wraps = ();\r
+                                               \r
+                                               # Cleaning wraps for this port\r
+                                               foreach (keys %WRAPS)\r
+                                               {\r
+                                                       next unless (/^$portnum:/);\r
+                                                       #print "Deleted $_: $WRAPS{$_}\n";\r
+                                                       delete $WRAPS{$_};\r
+                                               }\r
+                                       }\r
+                               }\r
+                               \r
+                               # Memorizing this counter\r
+                               $STAT->{$name} = $value;\r
+                       }\r
+                       \r
+                       unless ($STAT->{'portIndex'} || $STAT->{'portTrunkIndex'})\r
+                       {\r
+                               ##\r
+                               ## Hmmmmm, didn't find any of those expected variables\r
+                               ##\r
+                               \r
+                               if ($portnum =~ /^T(\d+)$/ && ($numberOfTrunks < $1))\r
+                               {\r
+                                       # Port out of bounds\r
+                                       &log_n_die("Unable to poll trunk $1 ($portnum), because max supported by switch is $numberOfTrunks");\r
+                               }\r
+                               elsif ($portnum =~ /^(\d+)$/ && ($numberOfPorts < $1))\r
+                               {\r
+                                       # Trunk out of bounds\r
+                                       &log_n_die("Unable to poll port $1, because max supported by switch is $numberOfPorts");\r
+                               }\r
+                               \r
+                               # Should always recieve portIndex, just a failsafe\r
+                               &log("Bug? Unable to poll port $portnum, unknown cause", $SET{'VERBOSE'});\r
+                               print $data;\r
+                               exit;\r
+                       }\r
+               }\r
+               elsif ($portnum =~ /^C\d+$/)\r
+               {\r
+                       ##\r
+                       ## This was a local iptables' chain\r
+                       ## Variables are added to $STAT if successful\r
+                       ##\r
+                       \r
+                       my $def = ${$SET{'CHAINS'}}{$portnum};\r
+                       unless (&poll_chain($def, $STAT))\r
+                       {\r
+                               ##\r
+                               ## The poll failed\r
+                               ##\r
+                               \r
+                               &log("Poll of chain $portnum definition '$def' failed!");\r
+                               next;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       ##\r
+                       ## This was assumes to be a local interface\r
+                       ## Variables are added to $STAT if successful\r
+                       ##\r
+                       \r
+                       unless (&poll_interface($portnum, $STAT))\r
+                       {\r
+                               ##\r
+                               ## The poll failed\r
+                               ##\r
+                               \r
+                               &log("Poll of local interface '$portnum' failed!");\r
+                               next;\r
+                       }\r
+               }\r
+               \r
+               ##\r
+               ## Do we have old info, so we can compute delta-values?\r
+               ##\r
+               \r
+               if (defined $OLD_STAT)\r
+               {\r
+                       ##\r
+                       ## Computing delta values of some variables\r
+                       ##\r
+                       \r
+                       # Elapsed time since last run\r
+                       $STAT->{'delta_time'} = Time::HiRes::tv_interval($OLD_STAT->{'time'}, $STAT->{'time'});\r
+                       \r
+                       if ($STAT->{'delta_time'} > 0)\r
+                       {\r
+                               ##\r
+                               ## Calcs delta for some variables\r
+                               ##\r
+                               \r
+                               foreach (@do_delta)\r
+                               {\r
+                                       my $diff = $STAT->{$_} - $OLD_STAT->{$_};\r
+                                       $STAT->{"delta_$_"} = $diff / $STAT->{'delta_time'};\r
+                                       \r
+                                       if ($diff < 0)\r
+                                       {\r
+                                               ##\r
+                                               ## Should never get a negative value!\r
+                                               ##\r
+                                               \r
+                                               &log("Negative delta! Port $portnum, variable $_: now '$STAT->{$_}', prev '$OLD_STAT->{$_}' = diff '$diff'", $SET{'VERBOSE'});\r
+                                       }\r
+                               }\r
+                               \r
+                               ##\r
+                               ## Calcs errors/sec per in/out\r
+                               ##\r
+                               \r
+                               # error-pps in\r
+                               my $value = 0;\r
+                               $value += ($STAT->{$_} - $OLD_STAT->{$_}) foreach (qw(rxFCS rxUnderSize rxOverSize rxFragment rxJabber));\r
+                               $STAT->{'err_in_pps'} = $value / $STAT->{'delta_time'};\r
+                               \r
+                               # error-pps out\r
+                               $value = 0;\r
+                               $value += ($STAT->{$_} - $OLD_STAT->{$_}) foreach (qw(txDrop txCollisions));\r
+                               $STAT->{'err_out_pps'} = $value / $STAT->{'delta_time'};\r
+                               \r
+                               ##\r
+                               ## Show stats in the shell?\r
+                               ##\r
+                               \r
+                               if ($SET{'VERBOSE'} >= 2)\r
+                               {\r
+                                       my @values = ();\r
+                                       \r
+                                       foreach (qw(goodOctetRCV rxGood goodOctetSND txGood))\r
+                                       {\r
+                                               my $value = $STAT->{"delta_$_"};\r
+                                               \r
+                                               if ($PORT->{'has_link'} || $value > 0)\r
+                                               {\r
+                                                       if (/Octet/)\r
+                                                       {\r
+                                                               # Bytes -> bits\r
+                                                               $value = &shorten_num($value*8,undef,1024) . 'bps';\r
+                                                       }\r
+                                                       else\r
+                                                       {\r
+                                                               # Packets\r
+                                                               $value = &shorten_num($value,undef,1000) . 'pps';\r
+                                                       }\r
+                                               }\r
+                                               else\r
+                                               {\r
+                                                       $value = '-';\r
+                                               }\r
+                                               push (@values, $value);\r
+                                       }\r
+                                       \r
+                                       print "out:", ' ' x (8 - length($values[0])), $values[0];\r
+                                       print " / ", ' ' x (8 - length($values[1])), $values[1];\r
+                                       \r
+                                       print "     in:", ' ' x (8 - length($values[2])), $values[2];\r
+                                       print " / ", ' ' x (8 - length($values[3])), $values[3];\r
+                                       \r
+                                       my $tot_err_pps = $STAT->{'err_in_pps'}+$STAT->{'err_out_pps'};\r
+                                       if ($tot_err_pps > 0)\r
+                                       {\r
+                                               $tot_err_pps = &shorten_num($tot_err_pps,undef,1000) . 'pps';\r
+                                       }\r
+                                       else\r
+                                       {\r
+                                               $tot_err_pps = '-';\r
+                                       }\r
+                                       print "     err:", ' ' x (8 - length($tot_err_pps)), $tot_err_pps;\r
+                                       \r
+                                       my $show = &shorten_num($STAT->{'delta_time'}, 6);\r
+                                       print "     delta: ${show}s";\r
+                               }\r
+                       }\r
+                       \r
+                       ##\r
+                       ## Shall we write to RRD-file\r
+                       ##\r
+                       \r
+                       if ($SET{'RRD_FILE_PREFIX'} && !$SET{"RRD_SKIP_PORT_$portnum"})\r
+                       {\r
+                               ##\r
+                               ## Yep, we shall save RRD data for this port\r
+                               ##\r
+                               \r
+                               my $filename = $SET{'RRD_FILE_PREFIX'} . "_$portnum.rrd";\r
+                               my $status = 1;\r
+                               \r
+                               unless (-e $filename)\r
+                               {\r
+                                       # Doesn't exist, create it\r
+                                       ($status, my $message) = &create_rrd($filename);\r
+                                       &log("Port $portnum: $message", $SET{'VERBOSE'} >= 4);\r
+                                       \r
+                                       if ($status == 0)\r
+                                       {\r
+                                               # Will not try create RRD for this port again\r
+                                               $SET{"RRD_SKIP_PORT_$portnum"} = 1;\r
+                                               &log("Create failed, disabling RRD for port $portnum", 1);\r
+                                       }\r
+                               }\r
+                               \r
+                               if ($status == 1)\r
+                               {\r
+                                       ##\r
+                                       ## No errors found, writing\r
+                                       ##\r
+                                       ## Order of data:\r
+                                       ## kbps out and in\r
+                                       ## pps out and in\r
+                                       ## error-pps out and in\r
+                                       ##\r
+                                       \r
+                                       my @values = ();\r
+                                       \r
+                                       foreach (qw(delta_goodOctetSND delta_goodOctetRCV\r
+                                                               delta_txGood delta_rxGood\r
+                                                               err_out_pps err_in_pps\r
+                                                       ))\r
+                                       {\r
+                                               my $value = $STAT->{$_};\r
+                                               $value *= 8/1024 if (/Octet/);  # Octets -> kbit\r
+                                               $value =~ s/(\.\d\d)\d+$/$1/;\r
+                                               push(@values, $value);\r
+                                       }\r
+                                       \r
+                                       # Uses the timestamp from our previous Time::HiRes gettimeofday\r
+                                       # HOWEVER if we're syncing to RRD and we're in sync the loop-start-time is used\r
+                                       my $timestamp = ${$STAT->{'time'}}[0];\r
+                                       $timestamp = $time{'unixtime'} if ($SET{'rrd_in_sync'});\r
+                                       \r
+                                       #print "\n$timestamp - ", scalar localtime( $timestamp ), "\n";\r
+                                       \r
+                                       my $string = join(':', $timestamp, @values);\r
+                                       \r
+                                       ##\r
+                                       ## Updates the RRD\r
+                                       ##\r
+                                       \r
+                                       RRDs::update($filename, $string);\r
+                                       \r
+                                       my $error = &RRDs::error;\r
+                                       &log("Unable to update RRD '$filename' with '$string'!: $error", $SET{'VERBOSE'} >= 1) if ($error);\r
+                               }\r
+                       }\r
+                       \r
+                       ##\r
+                       ## Is this port considered active?\r
+                       ## Used when we hide inactive ports in the HTML\r
+                       ##\r
+                       \r
+                       $PORT->{'is_active'} = $PORT->{'has_link'};\r
+                       if (!$PORT->{'is_active'} && ($STAT->{'delta_txGood'} || $STAT->{'delta_rxGood'}))\r
+                       {\r
+                               ##\r
+                               ## According to last polling of linkinfo the port is down, but\r
+                               ## the count of packets travelling the port has increased since\r
+                               ## last loop, so we assume it's gone up\r
+                               ##\r
+                               \r
+                               $PORT->{'is_active'} = 1;\r
+                               $STAT->{'link_changed'} = 1;\r
+                       }\r
+               }\r
+                               \r
+               # Memorizes the previous stat for this port\r
+               $OLD_STATS{$portnum} = $STATS{$portnum} if ($STATS{$portnum});\r
+               $STATS{$portnum} = $STAT;\r
+               \r
+               print "\n" if ($SET{'VERBOSE'} >= 2);\r
+       }\r
+       \r
+       ##\r
+       ## Writes cached wraps\r
+       ##\r
+       \r
+       if ($wraps_occured > 0 && $SET{'WRAPS_FILE'})\r
+       {\r
+               #&log("Saving wraps-cache", $SET{'VERBOSE'} >= 2);\r
+               \r
+               open (WRAPS, ">$SET{'WRAPS_FILE'}") || &log("Failed to save wraps-cache to file '$SET{'WRAPS_FILE'}'!", $SET{'VERBOSE'});\r
+               foreach (sort keys %WRAPS)\r
+               {\r
+                       print WRAPS "$_\t$WRAPS{$_}\n";\r
+               }\r
+               close WRAPS;\r
+       }\r
+       \r
+       # Ends loop here if we don't have a valid session\r
+       next unless ($cookie);\r
+       \r
+       ##\r
+       ## Checking and logging increased errors, but only if a logfile is defined\r
+       ##\r
+       \r
+       if ($SET{'LOG_FILE'})\r
+       {\r
+               foreach my $portnum (@do_ports)\r
+               {\r
+                       my $STAT = $STATS{$portnum};\r
+                       next unless ($STAT->{'delta_time'});\r
+                       \r
+                       my $OLD_STAT = $OLD_STATS{$portnum};\r
+                       \r
+                       foreach (qw(txDrop txCollisions rxFCS rxUnderSize rxOverSize rxFragment rxJabber))\r
+                       {\r
+                               my $diff = $STAT->{$_} - $OLD_STAT->{$_};\r
+                               next unless ($diff > 0);\r
+\r
+                               my $deltatime = &shorten_num($STAT->{'delta_time'}, 4); # Only stripping decimals\r
+                               my $rate = &shorten_num($diff / $STAT->{'delta_time'}, 3, 1000);\r
+                               \r
+                               # Log and possibly print if verbose >= 3\r
+                               &log("$do_ports{$portnum} (port $portnum): $_ has increased by $diff the last $deltatime secs (rate ${rate}pps)", $SET{'VERBOSE'} >= 3);\r
+                       }\r
+               }\r
+       }\r
+       \r
+       ##\r
+       ## We doesn't fetches system and linkinfo every loop, since it takes a while\r
+       ##\r
+       \r
+       if ($settings_changed || ($loop % $SET{'POLL_LINKINFO_EVERY_NTH_LOOP'} == 0))\r
+       {\r
+               ##\r
+               ## Also fetches general system-info now\r
+               ##\r
+               \r
+               print "Polling link- and system info...\n" if ($SET{'VERBOSE'} >= 2);\r
+               &get_system_info;\r
+       }\r
+       else\r
+       {\r
+               # Won't fetch, so we assumes the switch has been up\r
+               # We assumes that the whole loop will take refresh_rate seconds \r
+               $system{'sysUpTime'} += $SET{'REFRESH_RATE'}*100;\r
+               &parse_sysuptime;\r
+       }\r
+       \r
+       # Ends loop here if we don't have a valid session\r
+       next unless ($cookie);\r
+       \r
+       ##\r
+       ## Generates graphs\r
+       ##\r
+       \r
+       if ($SET{'HTML_FILE'} && $SET{'GRAPH_BPS_EVERY_NTH_LOOP'} && (($loop+1) % $SET{'GRAPH_BPS_EVERY_NTH_LOOP'} == 0))\r
+       {\r
+               print "Graphing BPS...\n" if ($SET{'VERBOSE'} >= 2);\r
+               &generate_rrd_graphs('bps');\r
+       }\r
+       \r
+       if ($SET{'HTML_FILE'} && $SET{'GRAPH_PPS_EVERY_NTH_LOOP'} && (($loop+1) % $SET{'GRAPH_PPS_EVERY_NTH_LOOP'} == 0))\r
+       {\r
+               print "Graphing PPS...\n" if ($SET{'VERBOSE'} >= 2);\r
+               &generate_rrd_graphs('pps');\r
+       }\r
+       \r
+       ##\r
+       ## Generates web-page if wanted\r
+       ##\r
+       \r
+       if ($SET{'HTML_FILE'})\r
+       {\r
+               $runtime = Time::HiRes::tv_interval($start_time, [ Time::HiRes::gettimeofday() ]);\r
+               &generate_html;\r
+       }\r
+       \r
+       ##\r
+       ## Pauses\r
+       ##\r
+       \r
+       $runtime = Time::HiRes::tv_interval($start_time, [ Time::HiRes::gettimeofday() ]);\r
+       my $sleep = $SET{'REFRESH_RATE'} - $runtime;\r
+       \r
+       ##\r
+       ## RRD creates "sharper" graphs if data is polled near each RRD_STEP-interval\r
+       ## If wanted we try to 'slide' to stay near that interval\r
+       ##\r
+       \r
+       if ($SET{'RRD_FILE_PREFIX'} && $SET{'SYNC_SLEEP_TO_RRD'})\r
+       {\r
+               # If using the default RRD_STEP 30s, we get a value between 0 and +30\r
+               # 0 is the ideal point\r
+               # Negative means we need to sleep a bit shorter to get near 0\r
+               # Positive means we need to sleep a bit longer to get near 0\r
+               my $half_step = $SET{'RRD_STEP'} / 2;\r
+               my $diff = $half_step - ($time{'unixtime'}+$half_step) % $SET{'RRD_STEP'};\r
+               \r
+               if ($diff != 0)\r
+               {\r
+                       ##\r
+                       ## Need adjusting\r
+                       ##\r
+                       \r
+                       # Max 5 seconds each loop\r
+                       $diff = 5 if ($diff > 5);\r
+                       $diff = -5 if ($diff < -5);\r
+                       $sleep += $diff;\r
+                       \r
+                       $diff = '+'.$diff if ($diff > 0);\r
+                       &log("Adjusting sleep with $diff secs to sync with RRD_STEP = $SET{'RRD_STEP'} secs", $SET{'VERBOSE'});\r
+                       $SET{'rrd_in_sync'} = 0;\r
+               }\r
+               elsif ($SET{'rrd_in_sync'} != 1)\r
+               {\r
+                       print "Sync with RRD_STEP = $SET{'RRD_STEP'} secs is OK\n" if ($SET{'VERBOSE'} >= 2);\r
+                       $SET{'rrd_in_sync'} = 1;\r
+               }\r
+       }\r
+       \r
+       # Always sleeps atleast 2 secs!\r
+       $sleep = 2 if ($sleep < 1);\r
+       \r
+       print "\n" if ($SET{'VERBOSE'} > 1);\r
+#      Time::HiRes::sleep($sleep);\r
+}\r
+\r
+exit;\r
+\r
+\r
+##\r
+## Create the HTML-page\r
+##\r
+\r
+sub generate_html\r
+{\r
+       #print "HTML refresh: $refresh\n";\r
+       \r
+       open (HTML, ">$SET{'HTML_FILE'}") || warn "Unable to write to html-file '$SET{'HTML_FILE'}'!";\r
+       print HTML <<END;\r
+<html>\r
+<head>\r
+<title>Statistics for $SET{'SWITCH'} - $system{'systemName'} $system{'locationName'}</title>\r
+<meta http-equiv="Refresh" content="$SET{'REFRESH_RATE'}">\r
+</head>\r
+\r
+<body bgcolor="White" text="Black" link="Black" vlink="Black">\r
+\r
+<center>\r
+<p>\r
+<table border="0" cellpadding="4" cellspacing="0" style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 10;" width="980">\r
+\r
+<tr align=left valign=bottom>\r
+<th align=right rowspan=2 bgcolor="silver">#</th>\r
+<th rowspan=2 bgcolor="silver">Equipment</th>\r
+<th colspan=4 bgcolor="lime"><a title="When polling a local interface, it's traffic transmitted from it">OUT: Switch -&gt; Equipment:</a></th>\r
+<th colspan=2 bgcolor="red">Errors</th>\r
+<td bgcolor="silver"></td>\r
+<th colspan=4 bgcolor="lime"><a title="When polling a local interface, it's traffic recieved by it">IN: Equipment -&gt; Switch:</a></th>\r
+<th colspan=5 bgcolor="red">Errors</th>\r
+</tr>\r
+<tr align=left valign=bottom>\r
+<th bgcolor="lime" colspan=2><a title="goodOctetSND (bytes), txGood (packets)">TOT</a></th>\r
+<th bgcolor="lime"><a title="txBroadcast (packets)">Bcast</a></th>\r
+<th bgcolor="lime"><a title="txMulticast (packets)">Mcast</a></th>\r
+<th bgcolor="red"><a title="txDrop (packets)">Drop</a></th>\r
+<th bgcolor="red"><a title="txCollisions (packets)">Coll</a></th>\r
+<td bgcolor="silver"></td>\r
+\r
+<th bgcolor="lime" colspan=2><a title="goodOctetRCV (bytes), rxGood (packets)">TOT</a></th>\r
+<th bgcolor="lime"><a title="rxBroadcast (packets)">Bcast</a></th>\r
+<th bgcolor="lime"><a title="rxMulticast (packets)">Mcast</a></th>\r
+<th bgcolor="red"><a title="rxFCS (packets)">FCS</a></th>\r
+<th bgcolor="red"><a title="rxUnderSize (packets)">Usize</a></th>\r
+<th bgcolor="red"><a title="rxOverSize (packets)">Osize</a></th>\r
+<th bgcolor="red"><a title="rxFragment (packets)">Frag</a></th>\r
+<th bgcolor="red"><a title="rxJabber (packets)">Jabb</a></th>\r
+</tr>\r
+END\r
+       \r
+       foreach my $portnum (@do_ports)\r
+       {\r
+               ##\r
+               ## Each port\r
+               ##\r
+               \r
+               my $STAT = $STATS{$portnum};\r
+               my $OLD_STAT = $OLD_STATS{$portnum};\r
+               my $PORT = $PORTS{$portnum};\r
+               my $is_err = 0;\r
+               \r
+               # Hides ports that are not active\r
+               next if ($SET{'HIDE_INACTIVE_PORTS'} && !$PORT->{'is_active'} && !$SET{"ALWAYS_SHOW_PORT_$portnum"});\r
+               \r
+               ##\r
+               ## Shall we add a link and/or title?\r
+               ##\r
+               \r
+               my $portnum_link = '';\r
+               my $portnum_title = '';\r
+               \r
+               if ($PORT->{'rrd_bps_file'})\r
+               {\r
+                       # Link to BPS-graph\r
+                       $portnum_link = $PORT->{'rrd_bps_file'};\r
+                       $portnum_title = "Click to view graphs";\r
+               }\r
+               elsif ($PORT->{'rrd_pps_file'})\r
+               {\r
+                       # Link to PPS-graph\r
+                       $portnum_link = $PORT->{'rrd_pps_file'};\r
+                       $portnum_title = "Click to view graphs";\r
+               }\r
+               \r
+               if ($portnum =~ /^C\d+$/)\r
+               {\r
+                       # Chain\r
+                       my @def = split(/\s*,\s*/, ${$SET{'CHAINS'}}{$portnum});\r
+                       \r
+                       $portnum_title .= ", " if ($portnum_title);\r
+                       $portnum_title .= "OUT = chain $def[0] row $def[1]";\r
+                       $portnum_title .= ", IN = chain $def[2] row $def[3]" if ($def[2]);\r
+               }\r
+               \r
+               $portnum_link  = "href=\"$portnum_link\"" if ($portnum_link);\r
+               $portnum_title = "title=\"$portnum_title\"" if ($portnum_title);\r
+               \r
+               ##\r
+               ## Writing\r
+               ##\r
+               \r
+               print HTML <<END;\r
+<tr align=right valign=top onmouseover="this.style.backgroundColor='$TR_COLOR'" onmouseout="this.style.backgroundColor=''">\r
+<th bgcolor="silver"><a $portnum_link $portnum_title>$portnum</a></th>\r
+<td align=left>$do_ports{$portnum}</td>\r
+END\r
+                       \r
+               foreach (qw(\r
+goodOctetSND txGood txBroadcast txMulticast\r
+is_err txDrop txCollisions no_err\r
+space\r
+goodOctetRCV rxGood rxBroadcast rxMulticast\r
+is_err rxFCS rxUnderSize rxOverSize rxFragment rxJabber no_err\r
+                       ))      # txError rxError \r
+               {\r
+                       ##\r
+                       ## Visar värden\r
+                       ##\r
+                       \r
+                       if ($_ eq 'space')\r
+                       {\r
+                               print HTML "<td></td>";\r
+                               next;\r
+                       }\r
+                       elsif ($_ eq 'is_err')\r
+                       {\r
+                               $is_err = 1;\r
+                               next;\r
+                       }\r
+                       elsif ($_ eq 'no_err')\r
+                       {\r
+                               $is_err = 0;\r
+                               next;\r
+                       }\r
+                       \r
+                       my $value = my $real_value = $STAT->{$_};\r
+                       my $diff = $value - $OLD_STAT->{$_};\r
+                       my $make_boldred = ($is_err && defined $OLD_STAT->{$_} && ($diff > 0));\r
+                       $diff = ($make_boldred) ? " (+$diff)" : '';\r
+                       \r
+\r
+                       # Exact value for mouse-over\r
+                       my $value_sep = &add_sep($real_value);\r
+                       \r
+                       # Writing da stuff\r
+                       print HTML "<td><a title=\"$value_sep$diff\">$value</a></td>";\r
+               }\r
+               \r
+               print HTML "</tr>\n";\r
+       }\r
+       \r
+       print HTML <<END;\r
+</table>\r
+\r
+<br><br><br>\r
+<table border="0" cellpadding="4" cellspacing="0" style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 10;" width=980>\r
+\r
+<tr align=left valign=bottom>\r
+<th align=right rowspan=2 bgcolor="silver">#</th>\r
+<th rowspan=2 bgcolor="silver">Equipment</th>\r
+<th bgcolor="lime"></th>\r
+<th bgcolor="silver" width=0></th>\r
+<th colspan=23 bgcolor="lime">IN: Equipment -> Switch: Amount of packets per framesize</th>\r
+</tr>\r
+<tr align=center valign=bottom>\r
+<th bgcolor="lime">Link</th>\r
+<th bgcolor="silver" width=0></th>\r
+<th bgcolor="lime" colspan=3><a title="rx64Octets (packets, percent, packets/s)">64 byte</a></th>\r
+<td bgcolor="silver" width=0></td>\r
+<th bgcolor="lime" colspan=3><a title="rx65TO127Octets (packets, percent, packets/s)">65-127 byte</a></th>\r
+<td bgcolor="silver" width=0></td>\r
+<th bgcolor="lime" colspan=3><a title="rx128TO255Octets (packets, percent, packets/s)">128-255 byte</a></th>\r
+<td bgcolor="silver" width=0></td>\r
+<th bgcolor="lime" colspan=3><a title="rx256TO511Octets (packets, percent, packets/s)">256-511 byte</a></th>\r
+<td bgcolor="silver" width=0></td>\r
+<th bgcolor="lime" colspan=3><a title="rx512TO1023Octets (packets, percent, packets/s)">512-1024 byte</a></th>\r
+<td bgcolor="silver" width=0></td>\r
+<th bgcolor="lime" colspan=3><a title="rx1024ToMa (packets, percent, packets/s)">1025- byte</a></th>\r
+</tr>\r
+END\r
+       \r
+       foreach my $portnum (@do_ports)\r
+       {\r
+               ##\r
+               ## Each port\r
+               ##\r
+               \r
+               next unless ($portnum =~ /^T?\d+$/);    # No such info for local interfaces\r
+               \r
+               my $STAT = $STATS{$portnum};\r
+               my $OLD_STAT = $OLD_STATS{$portnum};\r
+               my $PORT = $PORTS{$portnum};\r
+               \r
+               # Hides ports that are not up, if wanted\r
+               next if ($SET{'HIDE_INACTIVE_PORTS'} && !$PORT->{'is_active'} && !$SET{"ALWAYS_SHOW_PORT_$portnum"});\r
+               \r
+               ##\r
+               ## Shall we add a link to graphs?\r
+               ##\r
+               \r
+               my $graph_link = '';\r
+               \r
+               if ($PORT->{'rrd_bps_file'})\r
+               {\r
+                       # Link to BPS-graph\r
+                       $graph_link = $PORT->{'rrd_bps_file'};\r
+               }\r
+               elsif ($PORT->{'rrd_pps_file'})\r
+               {\r
+                       # Link to PPS-graph\r
+                       $graph_link = $PORT->{'rrd_pps_file'};\r
+               }\r
+               \r
+               $graph_link = "href=\"$graph_link\" title=\"Click to view graphs\"" if ($graph_link);\r
+               \r
+               ##\r
+               ## Make linkinfo bold if it recently changed\r
+               ##\r
+               \r
+               my $link = $PORT->{'link'};\r
+               $link = 'up?' if ($link eq 'down' && $PORT->{'is_active'});\r
+               $link = "<b>$link</b>" if ($STAT->{'link_changed'});\r
+               \r
+               ##\r
+               ## Writing\r
+               ##\r
+               \r
+               print HTML <<END;\r
+<tr align=right valign=top onmouseover="this.style.backgroundColor='$TR_COLOR'" onmouseout="this.style.backgroundColor=''">\r
+<th bgcolor="silver"><a $graph_link>$portnum</a></th>\r
+<td align=left>$do_ports{$portnum}</td>\r
+<td align=right><a title="$PORT->{'link_change_at'}">$link</a></td>\r
+<td></td>\r
+END\r
+               \r
+               foreach (qw( rx64Octets rx65TO127Octets rx128TO255Octets rx256TO511Octets rx512TO1023Octets rx1024ToMa ))\r
+               {\r
+                       ##\r
+                       ## The amount of packets\r
+                       ##\r
+                       \r
+                       my $tmp = $STAT->{$_};\r
+                       my $value_sep = &add_sep($tmp);\r
+                       my $value = $tmp;\r
+                       my $proc = 0;\r
+                       eval { $proc = int($tmp / $STAT->{'rxGood'} * 100) };\r
+                       \r
+                       \r
+                       print HTML "<td><a title=\"$value_sep\">$value</a></td>";\r
+                       \r
+                       ##\r
+                       ## Percent of total\r
+                       ##\r
+                       \r
+                       \r
+                       print HTML "<td>$proc\%</td>";\r
+                       \r
+                       ##\r
+                       ## Delta\r
+                       ##\r
+                       \r
+                       my $delta = $STAT->{"delta_$_"};\r
+                       \r
+                       if ($delta > 0)\r
+                       {\r
+                               $value = &shorten_num($delta, undef, 1000) . 'pps';\r
+                               $value = "<b>$value</b>" if ($SET{'BOLD_ABOVE_PPS'} && $delta > $SET{'BOLD_ABOVE_PPS'} && $value =~ /pps$/);\r
+                               $value = "<font color=\"silver\">$value</font>" if ($SET{'GREY_BELOW_PPS'} && $delta < $SET{'GREY_BELOW_PPS'});\r
+                       }\r
+                       else\r
+                       {\r
+                               $value = '';\r
+                       }\r
+                       \r
+                       $value_sep = &add_sep($delta);\r
+                       \r
+                       print HTML "<td><a title=\"$value_sep\">$value</a></td>";\r
+                       print HTML "<td></td>" unless ($_ eq 'rx1024ToMa');\r
+               }\r
+               \r
+               print HTML "</tr>\n";\r
+       }\r
+       \r
+       my $created = localtime;\r
+       my $tmp = $runtime;\r
+       $tmp =~ s/(\.\d\d).+$/$1/;\r
+       \r
+       # ServiceTag $system{'serviceTag'}, Serial $system{'serialNum'}\r
+       print HTML <<END;\r
+</table>\r
+\r
+<p>\r
+<font color=silver>Generated by fetch_stat.pl ver $ver written by Joakim Andersson - http://www.iqcc.se</font>\r
+</div>\r
+\r
+</center>\r
+\r
+</body>\r
+</html>\r
+END\r
+       \r
+       close HTML;\r
+}\r
+\r
+##\r
+## Logga in mot Dell-switchen för att få sessions-cookien\r
+##\r
+\r
+sub login\r
+{\r
+       ##\r
+       ## Fetched the loginpage to get the initial Session-value\r
+       ##\r
+       \r
+       &log("Logging in into $SET{'SWITCH'}...", $SET{'VERBOSE'});\r
+       \r
+       my $res = $ua->get("http://$SET{'SWITCH'}/login11.htm");\r
+       &log_n_die("Unable to fetch /login11.htm - ".$res->status_line) unless ($res->is_success);\r
+       \r
+       my $data = $res->content;\r
+       my $session = '';\r
+       \r
+       # Finds the Session-value, needed to compute the password that is sent when logging in\r
+       if ($data =~ /^<input type="hidden" name="Session" value="(.*)">/m)\r
+       {\r
+               $session = $1;\r
+       }\r
+       \r
+       unless ($session)\r
+       {\r
+               &log_n_die("Unable to find variable Session in the page! $data");\r
+       }\r
+       \r
+       if ($session =~ /^0+$/)\r
+       {\r
+               &log_n_die("Session $session is invalid! You may need to wait a while, or possibly reboot the switch");\r
+       }\r
+       \r
+       print "Found 'Session': $session\n" if ($SET{'VERBOSE'} >= 2);\r
+       #$session = '8c6e05969fb0748f7fa239628432ffe4';\r
+       \r
+       ##\r
+       ## Logging in to fetch the cookie\r
+       ##\r
+       \r
+       my $md5_password = md5_hex($SET{'USERNAME'} . $SET{'PASSWORD'} . $session);\r
+       print "Computed MD5: $md5_password\n" if ($SET{'VERBOSE'} >= 2);\r
+       \r
+       my $sock = Net::HTTP->new(Host => $SET{'SWITCH'}) || die $@;\r
+       $sock->write_request(POST => "/tgi/login.tgi",\r
+                                       'User-Agent' => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)",\r
+                                       'Content-Type' => 'application/x-www-form-urlencoded',\r
+                                       'Cache-Control' => 'no-cache',\r
+                                       'Accept' => '*/*',\r
+                                       "Username=$SET{'USERNAME'}&Password=$md5_password&Session=$session"\r
+                       );\r
+       \r
+       my($code, $mess, %h) = $sock->read_response_headers;\r
+       \r
+       unless ($code == 302)\r
+       {\r
+               &log_n_die("Didn't recieve code 302 when logging in! $mess");\r
+       }\r
+       \r
+       ##\r
+       ## Finding the Cookie we should recieve when logged in successfully\r
+       ##\r
+       ## Set-Cookie : SSID=0f9a03b3d15acd65af5dfcf6550c5eb6; path=/\r
+       ##\r
+       \r
+       unless ($h{'Set-Cookie'})\r
+       {\r
+               foreach (sort keys %h)\r
+               {\r
+                       print "$_ = $h{$_}\n";\r
+               }\r
+                       \r
+               &log_n_die("Didn't recieve cookie! $h{'Set-Cookie'}");\r
+       }\r
+       \r
+       $h{'Set-Cookie'} =~ /(SSID=.+?)\;/ || &log_n_die("Unable to interpret SSID from $h{'Set-Cookie'}!");\r
+       $cookie = $1;\r
+       \r
+       &log("Logged in, using session-cookie: $cookie", $SET{'VERBOSE'});\r
+       \r
+       ##\r
+       ## Caching the session for future runs\r
+       ## Prevents hanging of the web-interface if script is restarted un too often\r
+       ##\r
+       \r
+       if ($SET{'COOKIE_FILE'})\r
+       {\r
+               open (COOKIE, ">$SET{'COOKIE_FILE'}") || &log_n_die("Unable to save the cookie to file $SET{'COOKIE_FILE'}!");\r
+               print COOKIE $cookie;\r
+               close COOKIE;\r
+       }\r
+       else\r
+       {\r
+               print "Doesn't cache session\n" if ($SET{'VERBOSE'} >= 2);\r
+       }\r
+}\r
+\r
+##\r
+## Resets stats for a port\r
+##\r
+\r
+sub clear_stat\r
+{\r
+       my $portnum = shift;\r
+       \r
+       # Port- / Trunk-specifik options\r
+       my $arg = ($portnum =~ /^T(\d+)$/) ? "TrunkNo=$1&TrunkNo\$select=$1" : "PortNo=$portnum&PortNo\$select=$portnum";\r
+\r
+       my $sock = Net::HTTP->new(Host => $SET{'SWITCH'}) || die $@;\r
+       $sock->write_request(POST => "/tgi/portstats.tgi",\r
+                       'User-Agent' => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)",\r
+                       'Content-Type' => 'application/x-www-form-urlencoded',\r
+                       'Cache-Control' => 'no-cache',\r
+                       'Accept' => '*/*',\r
+                       'Cookie' => $cookie,\r
+                       'Referer' => "http://$SET{'SWITCH'}/portStats.htm",\r
+                       "$arg&RefreshRate\$select=15000&clrCnts=OK"\r
+       );\r
+       \r
+       my ($code, $mess, %h) = $sock->read_response_headers;\r
+       #print "$code : $mess\n";\r
+       \r
+       #foreach (sort keys %h)\r
+       #{\r
+       #       print "  $_ : $h{$_}\n";\r
+       #}\r
+       \r
+       #unless ($code == 302)\r
+       #{\r
+       #       print "Fick inte tillbaka code 302! $mess\n";\r
+       #}\r
+       \r
+       #my $buf;\r
+       #$sock->read_entity_body($buf, 1024);\r
+       #print $buf;\r
+       \r
+       return ($code == 302);          # 302 = Probably OK\r
+}\r
+\r
+##\r
+## Reading systeminfo that doesn't change\r
+##\r
+\r
+sub get_system_info\r
+{\r
+       my $res = $ua->get("http://$SET{'SWITCH'}/portConfig.htm",\r
+              'Cookie' => $cookie\r
+                );\r
+       \r
+       &log_n_die("Unable to fetch /portConfig.htm - ".$res->status_line) unless ($res->is_success);\r
+       \r
+       # Content\r
+       my $data = $res->content;\r
+       $data =~ tr/\r//d;\r
+       \r
+       if ($data =~ /^<title>Login<\/title>$/m)\r
+       {\r
+               ##\r
+               ## Invalid session!\r
+               ##\r
+               \r
+               &log("Session invalid", $SET{'VERBOSE'});\r
+               \r
+               $cookie = '';\r
+               return 0;\r
+       }\r
+       \r
+       ##\r
+       ## Finds the info we needs\r
+       ##\r
+       \r
+       my $row = 0;\r
+       my %vars = ();\r
+       foreach (split(/\n+/, $data))\r
+       {\r
+               $row++;\r
+               #print "RAD $row: $_\n";\r
+               \r
+               last if (/^<\/script>$/);       # May need adjustment in future firmwares\r
+               next unless (/^var (.+)="(\d*)";$/);\r
+               \r
+               my $name = $1;\r
+               my $value = $2;\r
+               \r
+               #next if ($stat{$name});\r
+               #print "  $name -> $value\n";\r
+               $vars{$name} = $value;\r
+       }\r
+       \r
+       ##\r
+       ## Parses info about every port\r
+       ##\r
+       \r
+       # Setting NumOfPorts if we don't have it\r
+       $numberOfPorts  = $vars{'numberOfPorts'};\r
+       $numberOfTrunks = $vars{'numberOfTrunks'};\r
+       \r
+       my $tot = $numberOfPorts + $numberOfTrunks;\r
+       \r
+       foreach my $num (1 .. $tot)\r
+       {\r
+               my $trunknum = $num - $numberOfPorts;\r
+               my $portnum = $num;\r
+               $portnum = "T$trunknum" if ($trunknum > 0);     # It's a trunk\r
+               \r
+               my $PORT = $PORTS{$portnum} ||= { 'link_changes' => 0, 'link_change_at' => 'No change detected' };\r
+               \r
+               # var portLinkList="0101110101011100000000";\r
+               # var portSpeedList="0202110201012200333333";\r
+               # var portDuplexList="0101110101011100222222";\r
+               # var portANList="1111111111111111222222";\r
+               # var portBPList="0000000000000000222222";\r
+               # var portFcList="0100000100000000333333";\r
+               \r
+               my $index = $num - 1;\r
+               my $portLink   = substr($vars{'portLinkList'},   $index, 1);\r
+               my $portSpeed  = substr($vars{'portSpeedList'},  $index, 1);\r
+               my $portDuplex = substr($vars{'portDuplexList'}, $index, 1);\r
+               #my $portAN     = substr($vars{'portANList'},     $index, 1);\r
+               my $portFc     = substr($vars{'portFcList'},     $index, 1);\r
+               my $portBP     = substr($vars{'portBPList'},     $index, 1);\r
+               \r
+               #$PORT->{'link'} = '-' if ($PORT->{'link'} eq 'up?');\r
+               my $link = 'down';\r
+               \r
+               if ($portLink)\r
+               {\r
+                       $link = ('10','100','1000','active')[$portSpeed];\r
+                       $link .= ('/Half','/Full','')[$portDuplex];\r
+                       $link .= '/FC' if ($portFc == 1);\r
+                       $link .= '/BP' if ($portBP == 1);\r
+               }\r
+               \r
+               if ($PORT->{'link'} && ($link ne $PORT->{'link'}))\r
+               {\r
+                       &log("$do_ports{$portnum} (port $portnum): Change of link detected; $PORT->{'link'} -> $link", $SET{'VERBOSE'} >= 3);\r
+                       \r
+                       # To show in the HTML\r
+                       $PORT->{'link_changes'}++;\r
+                       $PORT->{'link_change_at'} = "Change detected $time{'date_time'}; $PORT->{'link'} -> $link. $PORT->{'link_changes'} changes";\r
+                       \r
+                       # Triggers the link to be shown in bold\r
+                       $STATS{$portnum}->{'link_changed'} = 1;\r
+               }\r
+               \r
+               $PORT->{'link'} = $link;\r
+               $PORT->{'is_active'} = $PORT->{'has_link'} = $portLink;\r
+               \r
+               if ($SET{'AUTOADD_ACTIVE_PORTS'} && $portLink && !defined $SET{'PORTS'}->{$portnum})\r
+               {\r
+                       ##\r
+                       ## We shall autoadd active ports\r
+                       ##\r
+                       \r
+                       if ($trunknum > 0)\r
+                       {\r
+                               $SET{'PORTS'}->{$portnum} = "Trunk $trunknum";\r
+                               &log("Auto-added trunk $portnum as $portnum, link detected", $SET{'VERBOSE'} >= 1);\r
+                       }\r
+                       else\r
+                       {\r
+                               $SET{'PORTS'}->{$portnum} = "Port $portnum";\r
+                               &log("Auto-added port $portnum, link detected", $SET{'VERBOSE'} >= 1);\r
+                       }\r
+                       \r
+                       $autoadded_ports = 1;\r
+               }\r
+       }\r
+       return 1;\r
+}\r
+\r
+\r
+##\r
+## Rewrites 1024 as 1k, with a given number of digits\r
+##\r
+\r
+sub shorten_num\r
+{\r
+       my $num = shift;\r
+       my $digits = shift || 3;\r
+       my $base = shift || 1024;\r
+       my $unit = '';\r
+       \r
+       foreach (qw(k M G T P E Z Y))\r
+       {\r
+               last if ($num < $base);\r
+               \r
+               $unit = $_;\r
+               $num /= $base;\r
+       }\r
+       \r
+       $num = ($num >= 1000) ? substr($num, 0, 4) : substr($num, 0, $digits);\r
+       $num =~ s/(\.\d*)0+$/$1/;\r
+       $num =~ s/\.$//;\r
+       \r
+       return $num . $unit;\r
+}\r
+\r
+sub log\r
+{\r
+       my $text = shift;\r
+       my $print_too = shift;\r
+       \r
+       print "$text\n" if ($print_too);\r
+       \r
+       unless (fileno(LOG))\r
+       {\r
+               return unless ($SET{'LOG_FILE'});\r
+               open (LOG, ">>$SET{'LOG_FILE'}") || die("Unable to write to $SET{'LOG_FILE'}!");\r
+               \r
+               select LOG;\r
+               $| = 1;\r
+               select STDOUT;\r
+       }\r
+\r
+       print LOG "$time{'date_time'}: $text\n";\r
+}\r
+\r
+sub log_n_die\r
+{\r
+       my $text = shift;\r
+       &log($text);\r
+       die $text;\r
+}\r
+\r
+\r
+sub upd_time\r
+{\r
+       my $unixtime = shift || time;\r
+\r
+       my ($sec,$min,$hour,$daynum,$monnum,$year,$weekdaynum) = localtime($unixtime);\r
+       $sec = "0$sec" if ($sec < 10);\r
+       $min = "0$min" if ($min < 10);\r
+       $hour = "0$hour" if ($hour < 10);\r
+       my $day = $daynum;\r
+       $day = "0$day" if ($day < 10);\r
+       my $mon = $monnum + 1;\r
+       $mon = "0$mon" if ($mon < 10);\r
+       $year += 1900;\r
+\r
+       %time = (sec => $sec, min => $min, hour => $hour, day => $day, daynum => $daynum, weekdaynum => $weekdaynum, mon => $mon, monnum => $monnum, year => $year, unixtime => $unixtime, date_time => "$year-$mon-$day $hour:$min:$sec", date => "$year-$mon-$day", 'time' => "$hour:$min:$sec");\r
+}\r
+\r
+##\r
+## Reads the settings\r
+## Returns 0 when fails\r
+##\r
+\r
+sub refresh_settings\r
+{\r
+       ##\r
+       ## Checks if the settings-file has changed\r
+       ##\r
+       \r
+       my $file_modified = (stat($SETTINGS_FILE))[9];\r
+       die "Unable to access settings-file '$SETTINGS_FILE'!" unless ($file_modified);\r
+       \r
+       if ($file_modified eq $SET{'_modified'})\r
+       {\r
+               # 0 = No change\r
+               return 0;\r
+       }\r
+       \r
+       ##\r
+       ## Changed, re-reading settings\r
+       ##\r
+       \r
+       my %NEW_SET = ();\r
+       $NEW_SET{'_modified'} = $file_modified;\r
+       \r
+       if ($SET{'_modified'})\r
+       {\r
+               &log("Refreshing settings from $SETTINGS_FILE...", $SET{'VERBOSE'});\r
+       }\r
+       \r
+       # Prevents attempts to re-read settings if errors are found\r
+       $SET{'_modified'} = $NEW_SET{'_modified'};\r
+       \r
+       ##\r
+       ## Reads the settings\r
+       ##\r
+       \r
+       open (SET, $SETTINGS_FILE) || &log_n_die("Unable to open settings-file '$SETTINGS_FILE'!");\r
+       while (<SET>)\r
+       {\r
+               next if (/^#/);         # Ignoring comments\r
+               tr/\n\r//d;                     # Stripping linefeeds\r
+               s/\s+$//;                       # Stripping trailing white spaces\r
+               next unless ($_);       # Ignores empty lines\r
+               \r
+               my ($name, $value) = split(/\s*=\s*/, $_, 2);\r
+               \r
+               $NEW_SET{$name} = $value;\r
+       }\r
+       close SET;\r
+       \r
+       ##\r
+       ## Checking basic required variables\r
+       ##\r
+       \r
+       my $errors = 0;\r
+       \r
+       foreach (qw(SWITCH USERNAME PASSWORD REFRESH_RATE POLL_LINKINFO_EVERY_NTH_LOOP\r
+                               VERBOSE GRAPHS_PER_ROW GRAPH_WIDTH GRAPH_HEIGHT))\r
+       {\r
+               next if (defined $NEW_SET{$_});\r
+               \r
+               &log("Error: Required setting $_ is not defined", 1);\r
+               $errors++;\r
+       }\r
+       \r
+       ##\r
+       ## Checking numerical-only settings\r
+       ##\r
+       \r
+       foreach (qw(REFRESH_RATE POLL_LINKINFO_EVERY_NTH_LOOP VERBOSE\r
+                               AUTOADD_ACTIVE_PORTS HIDE_INACTIVE_PORTS\r
+                               GREY_BELOW_PPS BOLD_ABOVE_PPS GREY_BELOW_BPS\r
+                               BOLD_ABOVE_BPS GREY_BELOW_PROC\r
+                               GRAPH_BPS_EVERY_NTH_LOOP GRAPH_PPS_EVERY_NTH_LOOP\r
+                               RRD_STEP GRAPH_WIDTH GRAPH_HEIGHT GRAPHS_PER_ROW\r
+                               GRAPH_SLOPE_MODE ))\r
+       {\r
+               next unless (defined $NEW_SET{$_});\r
+               next if ($NEW_SET{$_} =~ /^\d+$/);\r
+               \r
+               # Permits simple expressions\r
+               if ($NEW_SET{$_} =~ /^[\d\-+*\/\.\,]+$/)\r
+               {\r
+                       my $new_value = eval $NEW_SET{$_};\r
+                       if ($new_value =~ /^(\d+)(\.\d+)?$/)\r
+                       {\r
+                               #print "$new_value = $1 (stripped $2);\n";\r
+                               $NEW_SET{$_} = $1;\r
+                       }\r
+                       else\r
+                       {\r
+                               &log("Error: Setting $_; evaluation of expression '$NEW_SET{$_}' failed $!", 1);                                \r
+                               $errors++;\r
+                       }\r
+                       next;\r
+               }\r
+               \r
+               &log("Error: Setting $_ requires a numerical integer value, has value '$NEW_SET{$_}'", 1);\r
+               $errors++;\r
+       }\r
+       \r
+       ##\r
+       ## Checking >1 values\r
+       ##\r
+       \r
+       foreach (qw(REFRESH_RATE POLL_LINKINFO_EVERY_NTH_LOOP RRD_STEP\r
+                               GRAPH_WIDTH GRAPH_HEIGHT))\r
+       {\r
+               next unless (defined $NEW_SET{$_});\r
+               next if ($NEW_SET{$_} >= 1);\r
+               \r
+               &log("Error: Setting $_ requires a numerical integer value larger that zero, has value '$NEW_SET{$_}'", 1);\r
+               $errors++;\r
+       }\r
+       \r
+       ##\r
+       ## Checking if RRDs should be written and the module can be loaded\r
+       ##\r
+       \r
+       if ($NEW_SET{'RRD_FILE_PREFIX'})\r
+       {\r
+               ##\r
+               ## Shall log to RRD\r
+               ##\r
+               \r
+               eval('use RRDs;');\r
+               if ($@)\r
+               {\r
+                       ##\r
+                       ## Unable to load the RRDs-module!\r
+                       ##\r
+                       \r
+                       $NEW_SET{'RRD_FILE_PREFIX'} = '';\r
+                       &log("Setting 'RRD_FILE_PREFIX' is set, but the perl-module RRDs.pm could not be loaded! Disabling RRD", 1);\r
+               }\r
+       }\r
+       \r
+       ##\r
+       ## Shall some ports be excluded from RRD and graphing?\r
+       ##\r
+       \r
+       foreach my $portnum (split(/\s*,\s*/, $NEW_SET{'RRD_SKIP_THESE_PORTS'}))\r
+       {\r
+               # Rewrites the list for easy checking\r
+               $NEW_SET{"RRD_SKIP_PORT_$portnum"} = 1;\r
+       }\r
+       \r
+       ##\r
+       ## If hiding inactive ports, always show these ports\r
+       ##\r
+       \r
+       foreach my $portnum (split(/\s*,\s*/, $NEW_SET{'ALWAYS_SHOW_THESE_PORTS'}))\r
+       {\r
+               # Rewrites the list for easy checking\r
+               $NEW_SET{"ALWAYS_SHOW_PORT_$portnum"} = 1;\r
+       }\r
+\r
+       foreach my $portnum (split(/\s*,\s*/, $NEW_SET{'SHOW_THESE_PORTS'}))\r
+       {\r
+               # Rewrites the list for easy checking\r
+           @do_ports=(@do_ports,$portnum);\r
+       }\r
+       \r
+       ##\r
+       ## Parsing ports and graphs\r
+       ##\r
+       \r
+       my %PORTS = ();\r
+       my %CHAINS = ();\r
+       my @GRAPHS = ();\r
+       my @RRD_RRA = ();\r
+       \r
+       foreach (sort keys %NEW_SET)\r
+       {\r
+               #print "$_\n";\r
+               \r
+               if (/^(PORT|TRUNK|INTERFACE)\s*(.+)$/)\r
+               {\r
+                       ##\r
+                       ## This is a switch PORT/TRUNK or a local interface\r
+                       ## PORT 1 = Router\r
+                       ##\r
+                       \r
+                       my $port = $2;\r
+                       $port = "T$2" if ($1 eq 'TRUNK');\r
+                       #$port = "I$2" if ($1 eq 'INTERFACE');\r
+                       # Skips already defined ports\r
+                       if ($PORTS{$port})\r
+                       {\r
+                               &log("Warn: Port $port is already defined, ignoring this definition", 1);\r
+                               next;\r
+                       }\r
+                       \r
+                       # Memorizing this name\r
+                       $PORTS{$port} = $NEW_SET{$_};\r
+               }\r
+               elsif (/^CHAIN\s*(\d+)\s*(.+)$/)\r
+               {\r
+                       ##\r
+                       ## This is a CHAIN\r
+                       ## CHAIN 1 joxx:-1 = Router\r
+                       ##\r
+                       \r
+                       my $port = "C$1";\r
+                       \r
+                       # Skips already defined ports\r
+                       if ($PORTS{$port})\r
+                       {\r
+                               &log("Warn: Port $port is already defined, ignoring this definition", 1);\r
+                               next;\r
+                       }\r
+                       \r
+                       $CHAINS{$port} = $2;\r
+                       \r
+                       # Memorizing this name\r
+                       $PORTS{$port} = $NEW_SET{$_};\r
+               }\r
+               elsif (/^GRAPH\s*(\d+)\s*\"(.+)\"$/)\r
+               {\r
+                       ##\r
+                       ## This is a GRAPH\r
+                       ## GRAPH "Past 3 hours" = 60*60*3\r
+                       ##\r
+                       \r
+                       my $index = $1;\r
+                       my $name = $2;\r
+                       \r
+                       # Permits simple expressions\r
+                       if ($NEW_SET{$_} =~ /^[\d\-+*\/\.\,]+$/)\r
+                       {\r
+                               my $new_value = eval $NEW_SET{$_};\r
+                               if ($new_value =~ /^(\d+)(\.\d+)?$/)\r
+                               {\r
+                                       #print "$new_value = $1 (stripped $2);\n";\r
+                                       $NEW_SET{$_} = $1;\r
+                               }\r
+                               else\r
+                               {\r
+                                       &log("Error: Setting $_; evaluation of expression '$NEW_SET{$_}' failed $!", 1);                                \r
+                                       $errors++;\r
+                                       next;\r
+                               }\r
+                       }\r
+                       \r
+                       # Memorizing this graph\r
+                       push (@GRAPHS, [$index, $name, $NEW_SET{$_}] );\r
+               }\r
+               elsif (/^RRD_RRA/)\r
+               {\r
+                       ##\r
+                       ## This is a RRD RRA-statement\r
+                       ## RRD_RRA 1 = RRA:AVERAGE:0.5:1:360\r
+                       ##\r
+                       \r
+                       # Memorizing this RRA-definition\r
+                       push (@RRD_RRA, $NEW_SET{$_});\r
+               }\r
+       }\r
+       \r
+       if ($NEW_SET{'SYNC_SLEEP_TO_RRD'} && ($NEW_SET{'RRD_STEP'} != $NEW_SET{'REFRESH_RATE'}))\r
+       {\r
+               &log("Can only sync sleep to RRD_STEP if REFRESH_RATE == RRD_STEP", 1);\r
+               $NEW_SET{'SYNC_SLEEP_TO_RRD'} = 0;\r
+       }\r
+       \r
+       # No ports defined?\r
+       unless (%PORTS)\r
+       {\r
+               &log("Err:  No PORTs to poll is defined!", 1);\r
+               $errors++;\r
+       }\r
+       \r
+       # Memorizing the ports\r
+       $NEW_SET{'PORTS'} = \%PORTS;\r
+       \r
+       # No graphs defined?\r
+       if (($NEW_SET{'GRAPH_BPS_EVERY_NTH_LOOP'} || $NEW_SET{'GRAPH_PPS_EVERY_NTH_LOOP'}) && !@GRAPHS)\r
+       {\r
+               &log("Err:  No GRAPHs to create is defined!", 1);\r
+               $errors++;\r
+       }\r
+\r
+       # Is selected GRAPH_OVERVIEW defined? FIXME\r
+       #if ($NEW_SET{'GRAPH_RRD_EVERY_NTH_LOOP'} && !defined $GRAPHS[ $NEW_SET{'GRAPH_OVERVIEW'}-1 ])\r
+       #{\r
+       #       &log("Err:  Selected GRAPH_OVERVIEW $NEW_SET{'GRAPH_OVERVIEW'} does not exist!", 1);\r
+       #       $errors++;\r
+       #}\r
+       \r
+       # Memorizing the ports\r
+       $NEW_SET{'GRAPHS'} = \@GRAPHS;\r
+\r
+       # No RRD RRAs defined?\r
+       if ($NEW_SET{'RRD_FILE_PREFIX'} && !@RRD_RRA)\r
+       {\r
+               &log("Err:  No RRD_RRAs is defined! Cannot create RRD-files without any", 1);\r
+               $errors++;\r
+       }\r
+       \r
+       # Memorizing the RRA definitions\r
+       $NEW_SET{'RRD_RRA'} = \@RRD_RRA;\r
+       \r
+       # Memorizing the chains\r
+       $NEW_SET{'CHAINS'} = \%CHAINS;\r
+       \r
+       ##\r
+       ## Returns a 2 if basic errors are encountered\r
+       ##\r
+       \r
+       return 2 if ($errors);\r
+       \r
+       # Activating settings\r
+       %SET = %NEW_SET;\r
+       close LOG;\r
+       \r
+       # 1 = Settings changed\r
+       return 1;\r
+}\r
+\r
+##\r
+## Rewrites sysUpTime to a readable time\r
+##\r
+\r
+sub parse_sysuptime\r
+{\r
+       my $secs = $system{'sysUpTime'};\r
+       $secs =~ s/\d\d$//;     # Strips last two digits to only have seconds left\r
+       \r
+       my $uptime = '';\r
+       my $days = int($secs / 86400);\r
+       if ($days)\r
+       {\r
+               $secs -= $days*86400;\r
+               $uptime .= "${days}d";\r
+       }\r
+       my $hours = int($secs / 3600);\r
+       if ($hours || $days)\r
+       {\r
+               $secs -= $hours*3600;\r
+               $uptime .= "${hours}h";\r
+       }\r
+       my $mins = int($secs / 60);\r
+       $uptime .= "${mins}m";\r
+       #$secs -= $mins*60;\r
+       #$uptime .= "${mins}m${secs}s";\r
+       \r
+       $system{'uptime'} = $uptime;\r
+}\r
+\r
+##\r
+## 12345678 -> 12'345'678\r
+##\r
+\r
+sub add_sep\r
+{\r
+       my $value = shift;\r
+       $value =~ s/(\.\d+)$//;\r
+       my $decimals = ($1 && $value < 10) ? $1 : '';\r
+       $value = reverse $value;\r
+       \r
+       $value =~ s/(\d\d\d)/$1\'/g;\r
+       $value =~ s/\'$//;\r
+       return (reverse $value) . substr($decimals, 0, 3);\r
+}\r
+\r
+##\r
+## Creates a empty RRD-file\r
+##\r
+\r
+sub create_rrd\r
+{\r
+       my $filename = shift || &error("No filename given to create as a RRD-file!");\r
+       \r
+       # Will not overwrite a existing file\r
+       return (1,"File '$filename' already existed!") if (-e $filename);\r
+       \r
+       # Creating RRD-file\r
+       RRDs::create(\r
+               $filename,\r
+               '--step',\r
+               $SET{'RRD_STEP'},\r
+               'DS:kbps_out:GAUGE:60:0:1000000',\r
+               'DS:kbps_in:GAUGE:60:0:1000000',\r
+               'DS:pps_out:GAUGE:60:0:10000000',\r
+               'DS:pps_in:GAUGE:60:0:10000000',\r
+               'DS:err_pps_out:GAUGE:60:0:10000000',\r
+               'DS:err_pps_in:GAUGE:60:0:10000000',\r
+               @{$SET{'RRD_RRA'}}\r
+       );\r
+       \r
+       my $error = &RRDs::error;\r
+       return(0, "Unable to create RRD-file '$filename'!: $error") if ($error);\r
+       \r
+       my $size = -s $filename;\r
+       unless ($size > 0)\r
+       {\r
+               unlink $filename;       # Removes the file so we won't try to write to it later\r
+               return(0, "Unable to create RRD-file '$filename'!: Zero size file");\r
+       }\r
+       \r
+       return (1, "File '$filename' created, size $size bytes");\r
+}\r
+\r
+##\r
+## Generate graphs\r
+##\r
+\r
+sub generate_rrd_graphs\r
+{\r
+       my $type = shift || 'bps';      # bps or pps\r
+       \r
+       ##\r
+       ## Yep, let's create a bunch of files \r
+       ##\r
+       \r
+       $SET{'HTML_FILE'} =~ /^(.*\/)?([^\/]+)(\.[^.]+)$/;\r
+       my $path = $1;          # path/to/\r
+       my $base = $2;          # stats-file\r
+       my $suffix = $3;        # .html\r
+       \r
+       #print "$path - $base - $suffix\n";\r
+       \r
+       # How often the graph-page will change\r
+       my $refresh = $SET{'REFRESH_RATE'} * $SET{'GRAPH_' . uc $type . '_EVERY_NTH_LOOP'};\r
+       \r
+       # Shall we also graph the other type? Otherwise no links\r
+       my $graph_other_type = $SET{'GRAPH_' . uc $graph_rev_type{$type} . '_EVERY_NTH_LOOP'};\r
+       \r
+       my $ucname = ucfirst $graph_names{$type};\r
+       my $rev = $graph_rev_type{$type};       # bps -> pps, pps -> bps\r
+       my $switch = $system{'systemName'} || $SET{'SWITCH'};\r
+       \r
+       my @index_graphs = ();          # We will create the page last\r
+       \r
+       ##\r
+       ## Creates a overview for this type\r
+       ##\r
+       \r
+       foreach my $portnum (@do_ports)\r
+       {\r
+               ##\r
+               ## Does each port\r
+               ##\r
+               \r
+               # Skip this port\r
+               next if ($SET{"RRD_SKIP_PORT_$portnum"});\r
+               \r
+               my $rrd_filename = $SET{'RRD_FILE_PREFIX'} . "_$portnum.rrd";\r
+               next unless (-s $rrd_filename); # Will not proceed unless the rrd-data exist\r
+               \r
+               ##\r
+               ## Writes indexfile for each port that will contain the graphs\r
+               ##\r
+               \r
+               my @port_graphs = ();           # We will create the page last\r
+               \r
+               my $rrd_port_file = "${base}_${type}_${portnum}$suffix";\r
+               $PORTS{$portnum}->{"rrd_${type}_file"} = $rrd_port_file;        # Remembering\r
+               \r
+               ##\r
+               ## Creating graphs\r
+               ##\r
+               \r
+               my @graph_args = ('--interlaced','--lazy');\r
+               push (@graph_args, '--slope-mode') if ($SET{'GRAPH_SLOPE_MODE'});\r
+               \r
+               foreach my $graph_ref (@{$SET{'GRAPHS'}})\r
+               {\r
+                       my $i                   = $graph_ref->[0];\r
+                       my $graph_name  = $graph_ref->[1];\r
+                       my $graph_secs  = $graph_ref->[2];\r
+                       \r
+                       my $image_filename = "${base}_${type}_$portnum-$i.png";\r
+                       #unlink $image_filename if ($erase_images);\r
+                       \r
+                       ##\r
+                       ## Mega graph command\r
+                       ##\r
+                       \r
+                       my $averages = my $xsize = my $ysize = 0;\r
+                       \r
+                       if ($type eq 'bps')\r
+                       {\r
+                               ##\r
+                               ## Bits/s\r
+                               ##\r
+                               \r
+                               ($averages,$xsize,$ysize) = RRDs::graph("$path$image_filename",\r
+                                       "--start=end-$graph_secs",\r
+                                       "--title=$do_ports{$portnum} ($portnum) on $switch - $graph_name",\r
+                                       "--vertical-label=$graph_names{$type}",\r
+                                       '--base=1024',\r
+                                       '--imgformat=PNG',\r
+                                       "--width=$SET{'GRAPH_WIDTH'}",\r
+                                       "--height=$SET{'GRAPH_HEIGHT'}",\r
+                                       '--alt-y-mrtg',\r
+                                       @graph_args,\r
+                                       "DEF:b=$rrd_filename:kbps_out:AVERAGE",\r
+                                       "DEF:a=$rrd_filename:kbps_in:AVERAGE",\r
+                                       'CDEF:B=b,1024,*',\r
+                                       'CDEF:A=a,1024,*',\r
+                                       'AREA:B#00FF00:bit/s OUT',\r
+                                       'VDEF:B_AVERAGE=B,AVERAGE',\r
+                                       'GPRINT:B_AVERAGE:Avg\: %7.2lf%s ',\r
+                                       'VDEF:B_MAX=B,MAXIMUM',\r
+                                       'GPRINT:B_MAX:Max\: %7.2lf%s ',\r
+                                       'VDEF:B_LAST=B,LAST',\r
+                                       'GPRINT:B_LAST:Last\: %7.2lf%s\n',\r
+                                       'LINE1:A#0000FF:bit/s IN ',\r
+                                       'VDEF:A_AVERAGE=A,AVERAGE',\r
+                                       'GPRINT:A_AVERAGE:Avg\: %7.2lf%s ',\r
+                                       'VDEF:A_MAX=A,MAXIMUM',\r
+                                       'GPRINT:A_MAX:Max\: %7.2lf%s ',\r
+                                       'VDEF:A_LAST=A,LAST',\r
+                                       'GPRINT:A_LAST:Last\: %7.2lf%s'\r
+                               );\r
+                       }\r
+                       else\r
+                       {\r
+                               ##\r
+                               ## Packets/s\r
+                               ##\r
+                               \r
+                               ($averages,$xsize,$ysize) = RRDs::graph("$path$image_filename",\r
+                                       "--start=end-$graph_secs",\r
+                                       "--title=$do_ports{$portnum} ($portnum) on $switch - $graph_name",\r
+                                       "--vertical-label=$graph_names{$type}",\r
+                                       '--base=1000',\r
+                                       '--imgformat=PNG',\r
+                                       "--width=$SET{'GRAPH_WIDTH'}",\r
+                                       "--height=$SET{'GRAPH_HEIGHT'}",\r
+                                       '--alt-y-mrtg',\r
+                                       @graph_args,\r
+                                       "DEF:d=$rrd_filename:pps_out:AVERAGE",\r
+                                       "DEF:c=$rrd_filename:pps_in:AVERAGE",\r
+                                       "DEF:f=$rrd_filename:err_pps_out:AVERAGE",\r
+                                       "DEF:e=$rrd_filename:err_pps_in:AVERAGE",\r
+                                       'AREA:d#00FF00:Pkts/s OUT    ',\r
+                                       'VDEF:d_AVERAGE=d,AVERAGE',\r
+                                       'GPRINT:d_AVERAGE:Avg\: %7.2lf%s',\r
+                                       'VDEF:d_MAX=d,MAXIMUM',\r
+                                       'GPRINT:d_MAX:Max\: %7.2lf%s',\r
+                                       'VDEF:d_LAST=d,LAST',\r
+                                       'GPRINT:d_LAST:Last\: %7.2lf%s\n',\r
+                                       'LINE1:c#0000FF:Pkts/s IN     ',\r
+                                       'VDEF:c_AVERAGE=c,AVERAGE',\r
+                                       'GPRINT:c_AVERAGE:Avg\: %7.2lf%s',\r
+                                       'VDEF:c_MAX=c,MAXIMUM',\r
+                                       'GPRINT:c_MAX:Max\: %7.2lf%s',\r
+                                       'VDEF:c_LAST=c,LAST',\r
+                                       'GPRINT:c_LAST:Last\: %7.2lf%s\n',\r
+                                       'LINE1:f#FFA500:Err pkts/s OUT',\r
+                                       'VDEF:f_AVERAGE=f,AVERAGE',\r
+                                       'GPRINT:f_AVERAGE:Avg\: %7.2lf%s',\r
+                                       'VDEF:f_MAX=f,MAXIMUM',\r
+                                       'GPRINT:f_MAX:Max\: %7.2lf%s',\r
+                                       'VDEF:f_LAST=f,LAST',\r
+                                       'GPRINT:f_LAST:Last\: %7.2lf%s\n',\r
+                                       'LINE1:e#FF0000:Err pkts/s IN ',\r
+                                       'VDEF:e_AVERAGE=e,AVERAGE',\r
+                                       'GPRINT:e_AVERAGE:Avg\: %7.2lf%s',\r
+                                       'VDEF:e_MAX=e,MAXIMUM',\r
+                                       'GPRINT:e_MAX:Max\: %7.2lf%s',\r
+                                       'VDEF:e_LAST=e,LAST',\r
+                                       'GPRINT:e_LAST:Last\: %7.2lf%s'\r
+                               );\r
+                       }\r
+                       \r
+                       my $error = &RRDs::error;\r
+                       &log("Unable to create graph '$path$image_filename'! $error", 1) if ($error);\r
+                       \r
+                       ##\r
+                       ## We create graphs first and then the page\r
+                       ##\r
+                       \r
+                       push (@port_graphs,  "<img src=\"$image_filename\" width=$xsize height=$ysize>");\r
+                       push (@index_graphs, "<a href=\"$rrd_port_file\"><img src=\"$image_filename\" width=$xsize height=$ysize border=0></a>") if ($i == $SET{'GRAPH_OVERVIEW'});\r
+                       \r
+                       # This graph is done\r
+               }\r
+               \r
+               ##\r
+               ## All graphs for this port done, create the page\r
+               ##\r
+               \r
+               my $switch_link = ($graph_other_type) ? "<br><a href=\"${base}_${rev}_$portnum$suffix\">Switch to $graph_names{$rev}</a>" : '';\r
+\r
+               open(HTML, ">$path$rrd_port_file");\r
+               print HTML <<END;\r
+<html>\r
+<head>\r
+<title>$ucname for $do_ports{$portnum} (port $portnum) on $SET{'SWITCH'} - $system{'systemName'} $system{'locationName'}</title>\r
+<meta http-equiv="Refresh" content="$refresh">\r
+</head>\r
+\r
+<body bgcolor="White" text="Black" link="Black" vlink="Black" alink="Red" style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 9;">\r
+<center>\r
+<div style="font-size: 13; font-weight: bold;">$ucname - $do_ports{$portnum} (port $portnum)</div>\r
+$switch_link\r
+<br><a href="${base}_$type$suffix">Show overview for $graph_names{$type}</a>\r
+\r
+<p>\r
+END\r
+                       \r
+               my $i = 0;\r
+               foreach (@port_graphs)\r
+               {\r
+                       print HTML $_;\r
+                       print HTML "<br>\n" if ($SET{'GRAPHS_PER_ROW'} && (++$i % $SET{'GRAPHS_PER_ROW'} == 0));\r
+               }\r
+               \r
+               print HTML <<END;\r
+<p>Page updated $time{'date_time'}, refreshes every $refresh sec\r
+               \r
+</center>\r
+</body>\r
+</html>\r
+END\r
+               close HTML;\r
+               # Page for BPS or PPS done för this port\r
+       }\r
+       \r
+       ##\r
+       ## Writing the index-page for this type\r
+       ##\r
+       \r
+       my $type_index_file = "${base}_${type}$suffix";\r
+       my $switch_link = ($graph_other_type) ? "<br><a href=\"${base}_$rev$suffix\">Switch to $graph_names{$rev}</a>" : '';\r
+       \r
+       open(HTML, ">$path$type_index_file");\r
+       print HTML <<END;\r
+<html>\r
+<head>\r
+<title>Overview $graph_names{$type} on $SET{'SWITCH'} - $system{'systemName'} $system{'locationName'}</title>\r
+<meta http-equiv="Refresh" content="$refresh">\r
+</head>\r
+\r
+<body bgcolor="White" text="Black" link="Black" vlink="Black" alink="Red" style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 9;">\r
+<center>\r
+<div style="font-size: 13; font-weight: bold;">$ucname - Overview</div>\r
+$switch_link\r
+<br><a href="$base$suffix">Return to statistics</a>\r
+<p>\r
+END\r
+       \r
+       my $i = 0;\r
+       foreach (@index_graphs)\r
+       {\r
+               print HTML $_;\r
+               print HTML "<br>\n" if ($SET{'GRAPHS_PER_ROW'} && (++$i % $SET{'GRAPHS_PER_ROW'} == 0));\r
+       }\r
+       \r
+       print HTML <<END;\r
+<p>Page updated $time{'date_time'}, refreshes every $refresh sec\r
+\r
+</center>\r
+</body>\r
+</html>\r
+END\r
+       close HTML;\r
+       \r
+       ##\r
+       ## All ports done\r
+       ##\r
+       \r
+       return 1;\r
+}\r
+\r
+##\r
+## Poll local interface\r
+## We could easily have done this buffered instead\r
+##\r
+\r
+sub poll_interface\r
+{\r
+       my $interface = shift;\r
+       my $STAT = shift || {};\r
+       my $ok = 0;\r
+       \r
+       if ($SET{'USE_ETHTOOL'})\r
+       {\r
+               ##\r
+               ## Poll using ethtool, hopefully\r
+               ##\r
+\r
+               unless (open (ETHTOOL, "$SET{'USE_ETHTOOL'} -S $interface |"))\r
+               {\r
+                       ##\r
+                       ## Unable to poll successfully!\r
+                       ##\r
+                       \r
+                       &log("Unable to run command '$SET{'USE_ETHTOOL'} -S $interface'! Disabling polling using ethtool", 1);\r
+                       $SET{'USE_ETHTOOL'} = '';\r
+               }\r
+               else\r
+               {\r
+                       ##\r
+                       ## We were able to run the command (hopefully)\r
+                       ##\r
+                       \r
+                       my %E = ();\r
+                       \r
+                       while (<ETHTOOL>)\r
+                       {\r
+                               #     rx_packets: 6207689\r
+                               #     tx_packets: 2174409\r
+                               #     rx_bytes: 4192981116\r
+                               \r
+                               chomp;\r
+                               s/^\s*//;\r
+                               my ($name, $value) = split(/\s*\:\s*/, $_, 2);\r
+                               next unless ($value =~ /^\d+$/);        # Makes sure we don't take crap\r
+                               \r
+                               $E{$name} = $value;\r
+                       }\r
+                       close ETHTOOL;\r
+                       \r
+                       ##\r
+                       ## Sanity-check\r
+                       ##\r
+                       \r
+                       my $not_ok = 0;\r
+                       \r
+                       foreach (qw(rx_bytes rx_packets tx_bytes tx_packets))\r
+                       {\r
+                               next if (defined $E{$_});\r
+                               \r
+                               &log("Ethtool didn't provide expected variable $_!", 1);\r
+                               $not_ok++;\r
+                       }\r
+                       \r
+                       if ($not_ok)\r
+                       {\r
+                               &log("Disabling polling using ethtool, ($SET{'USE_ETHTOOL'} -S $interface)", 1);\r
+                               $SET{'USE_ETHTOOL'} = '';\r
+                       }\r
+                       else\r
+                       {\r
+                               ##\r
+                               ## Okay, I'm not certain about the more unusual errors like FCS\r
+                               ##\r
+                               \r
+                               $STAT->{'goodOctetRCV'} = $E{'rx_bytes'};\r
+                               $STAT->{'rxGood'}               = $E{'rx_packets'};\r
+                               $STAT->{'rxBroadcast'}  = $E{'rx_broadcast'} if (defined $E{'rx_broadcast'});\r
+                               $STAT->{'rxMulticast'}  = $E{'rx_multicast'} if (defined $E{'rx_multicast'});\r
+                               $STAT->{'rxFCS'}                = $E{'rx_align_errors'} + $E{'rx_crc_errors'} if (defined $E{'rx_align_errors'} || defined $E{'rx_crc_errors'});\r
+                               $STAT->{'rxUnderSize'}  = $E{'rx_short_length_errors'} if (defined $E{'rx_short_length_errors'});\r
+                               $STAT->{'rxOverSize'}   = $E{'rx_long_length_errors'} if (defined $E{'rx_long_length_errors'});\r
+                               $STAT->{'rxFragment'}   = '';   # Available?\r
+                               $STAT->{'rxJabber'}             = '';   # Available?\r
+                               \r
+                               $STAT->{'goodOctetSND'} = $E{'tx_bytes'};\r
+                               $STAT->{'txGood'}               = $E{'tx_packets'};\r
+                               $STAT->{'txBroadcast'}  = $E{'tx_broadcast'} if (defined $E{'tx_broadcast'});\r
+                               $STAT->{'txMulticast'}  = $E{'tx_multicast'} if (defined $E{'tx_multicast'});\r
+                               $STAT->{'txDrop'}               = $E{'tx_dropped'} if (defined $E{'tx_dropped'});\r
+                               $STAT->{'txCollisions'} = $E{'collisions'} if (defined $E{'collisions'});\r
+                               \r
+                               $ok = 1;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       unless ($SET{'USE_ETHTOOL'})\r
+       {\r
+               ##\r
+               ## Don't poll using ethtool\r
+               ## Opens /proc/net/dev to read some statistics\r
+               ##\r
+               \r
+               unless (open (DEV, '/proc/net/dev'))\r
+               {\r
+                       &log("Unable to open '/proc/net/dev'!", 1);\r
+                       return 0;\r
+               }\r
+               \r
+               # Searching for this interface\r
+               while (<DEV>)\r
+               {\r
+                       #Inter-|   Receive                                                |  Transmit\r
+                       # face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed\r
+                       #  eth0:230864891  964901    0    0    0     0          0         0 867172607  936222    0    0    0     0       0          0\r
+                       \r
+                       if (/^\s*$interface\:\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)$/)\r
+                       {\r
+                               ##\r
+                               ## Remembering some data\r
+                               ##\r
+                               \r
+                               $STAT->{'goodOctetRCV'} = $1;\r
+                               $STAT->{'rxGood'}               = $2;\r
+                               $STAT->{'rxFCS'}                = $6;\r
+                               $STAT->{'rxUnderSize'}  = '';\r
+                               $STAT->{'rxOverSize'}   = '';\r
+                               $STAT->{'rxFragment'}   = '';\r
+                               $STAT->{'rxJabber'}             = '';\r
+                               \r
+                               $STAT->{'goodOctetSND'} = $9;\r
+                               $STAT->{'txGood'}               = $10;\r
+                               $STAT->{'txDrop'}               = $12;\r
+                               $STAT->{'txCollisions'} = $14;\r
+                               \r
+                               $ok = 1;\r
+                               \r
+                               last;\r
+                       }\r
+               }\r
+               close DEV;\r
+       }\r
+       \r
+       return $ok;\r
+}\r
+\r
+##\r
+## Polls values from a local iptables' chain\r
+##\r
+\r
+sub poll_chain\r
+{\r
+       my $chain = shift;\r
+       my $STAT = shift || {};\r
+       my $ok = 0;\r
+       \r
+       $STAT->{'goodOctetRCV'} = 0;\r
+       $STAT->{'rxGood'}               = 0;\r
+       $STAT->{'rxFCS'}                = '';\r
+       $STAT->{'rxUnderSize'}  = '';\r
+       $STAT->{'rxOverSize'}   = '';\r
+       $STAT->{'rxFragment'}   = '';\r
+       $STAT->{'rxJabber'}             = '';\r
+       \r
+       $STAT->{'goodOctetSND'} = 0;\r
+       $STAT->{'txGood'}               = 0;\r
+       $STAT->{'txDrop'}               = '';\r
+       $STAT->{'txCollisions'} = '';\r
+       \r
+       ##\r
+       ## Reads info from iptables\r
+       ## chain1,1,chain2,1\r
+       ##\r
+       \r
+       my @def = split(/\s*,\s*/, $chain);\r
+       my @chains = (['OUT',$def[0],$def[1]], ['IN',$def[2],$def[3]]);\r
+       \r
+       foreach my $ref (@chains)\r
+       {\r
+               my $type = $$ref[0];\r
+               my $chain = $$ref[1];\r
+               my $row = $$ref[2] || -1;       # Defaults to last row\r
+               next unless ($chain);\r
+               \r
+               unless (open (CHAIN, "iptables -vxn -L $chain |"))\r
+               {\r
+                       &log("Unable to execute command 'iptables -vxn -L $chain'!", 1);\r
+                       return 0;\r
+               }\r
+               \r
+               my @lines = <CHAIN>;\r
+               close CHAIN;\r
+               \r
+               # Make -1 become the last actual row\r
+               # If 4 lines total, 4-1 = 3 = lines[3] = last row\r
+               $row = scalar @lines + $row if ($row < 0);\r
+               \r
+               # Pick the line to parse\r
+               my $line = $lines[$row];\r
+               \r
+               # Parse that line, expect the first two lines to be packets and bytes\r
+               #     7477   478570 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0\r
+               unless ($line =~ /^\s*(\d+)\s+(\d+)\s/)\r
+               {\r
+                       &log("Parsing chain '$chain'; row $row contained '$line', unable to parse!", 1);\r
+                       return 0;\r
+               }\r
+               \r
+               #print "$type: $chain - row $row = $line -> pkts $1, bytes $2\n";\r
+               \r
+               if ($type eq 'OUT')\r
+               {\r
+                       $STAT->{'goodOctetSND'} = $2;\r
+                       $STAT->{'txGood'}               = $1;\r
+               }\r
+               else\r
+               {\r
+                       $STAT->{'goodOctetRCV'} = $2;\r
+                       $STAT->{'rxGood'}               = $1;\r
+               }\r
+       }\r
+       return 1;\r
+}\r