Previous page: Link Quality v2
Next page: Hourly Graphs

Bandwidth

Version 2.0.2

Here is another modification that I used on 1.14 but couldn't easily convert to 2.0.  So I rewrote the modification to produce what I wanted.  And that was a graphical means of seeing which machines in green were using what bandwidth.  Here's the output:


and this is how that relates to my (modified) red graph:

It delivers what I consider to be a nice indication of machines/subnets and their share of the bandwidth being used.

Here's how it's done.

1. The data is taken from iptables, so you need first of all to have a rule or rules to work with.  I decided to create a brand new pre- and post-routing chain for my use (although the mod only uses post-routing for the download bandwidth).  The best way to add this table is to make use of the preferred method - editing /etc/rc.d/rc.firewall.local.  Here's the one I use (you'll obviously need to amend this to suite your set up and requirements)


#!/bin/sh
# Used for private firewall rules
#
# $Id: rc.firewall.local 1912 2008-09-16 20:11:47Z owes $
#

# read variables
eval $(/usr/local/bin/readhash /var/ipcop/ethernet/settings)
if [ -f /var/ipcop/red/iface ]; then
REAL_RED=`cat /var/ipcop/red/iface`
fi

# See how we were called.
case "$1" in
start)
## add your 'start' rules here
iptables -t mangle -N EAKPRE
iptables -t mangle -I PREROUTING 1 -j EAKPRE
iptables -t mangle -N EAKPST
iptables -t mangle -I POSTROUTING 1 -j EAKPST
#
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.224/27 -j RETURN
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.192/27 -j RETURN
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.160/27 -j RETURN
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.128/27 -j RETURN
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.96/27 -j RETURN
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.64/27 -j RETURN
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.32/27 -j RETURN
iptables -t mangle -A EAKPRE -i lan-1 -s 192.168.0.0/27 -j RETURN
#
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.224/27 -j RETURN
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.192/27 -j RETURN
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.160/27 -j RETURN
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.128/27 -j RETURN
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.96/27 -j RETURN
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.64/27 -j RETURN
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.32/27 -j RETURN
iptables -t mangle -A EAKPST -o lan-1 -d 192.168.0.0/27 -j RETURN
;;
stop)
## add your 'stop' rules here
iptables -t mangle -D PREROUTING 1
iptables -t mangle -D POSTROUTING 1
iptables -t mangle -F EAKPRE
iptables -t mangle -X EAKPRE
iptables -t mangle -F EAKPST
iptables -t mangle -X EAKPST
;;
reload)
$0 stop
$0 start
## add your 'reload' rules here
;;
*)
echo "Usage: $0 {start|stop|reload}"
;;
esac

2. Run this (/etc/rc.d/rc.firewall.local) and check the table in the ipcop GUI (mine's in the mangle section)


3. There is probably a better way to do this, but I couldn't find it, so have resorted to the hard way, be parsing the output of the iptables -L command. Open file /usr/local/bin/makegraphs, add a couple of procedures to do the work! The first one to maintain the rrd:


# ---------------------------------------------
# Added for bandwidth graphs
# Creates and updates a link quality database
# ---------------------------------------------
sub updatebandwidthin {
if ( ! -e "$rrdlog/bwin.rrd") {
RRDs::create ("$rrdlog/bwin.rrd", "--step=300",
"DS:devices:COUNTER:600:0:100000000",
"DS:servers:COUNTER:600:0:100000000",
"DS:allans:COUNTER:600:0:100000000",
"DS:karens:COUNTER:600:0:100000000",
"DS:kevins:COUNTER:600:0:100000000",
"DS:carls:COUNTER:600:0:100000000",
"DS:others:COUNTER:600:0:100000000",
"DS:dhcps:COUNTER:600:0:100000000",
"RRA:AVERAGE:0.5:1:576",
"RRA:AVERAGE:0.5:6:672",
"RRA:AVERAGE:0.5:24:732",
"RRA:AVERAGE:0.5:144:1460");
$ERROR = RRDs::error;
print "Error in RRD::create for bandwidth-in quality: $ERROR\n" if $ERROR;
}

# get postrouting lines and wack them into a table
my $table = `/sbin/iptables -t mangle -xnvL EAKPST`;
# now split the lines so we can do something with them
my @tablelines = split(/\n/, $table);
# forget the 1st line, it's a title.  Get the other linee - Thanks to John who provided an improvement
my @device = split(/ +/," ".$tablelines[2]);
my @server = split(/ +/," ".$tablelines[3]);
my @allan  = split(/ +/," ".$tablelines[4]);
my @karen  = split(/ +/," ".$tablelines[5]);
my @kevin  = split(/ +/," ".$tablelines[6]);
my @carl   = split(/ +/," ".$tablelines[7]);
my @other  = split(/ +/," ".$tablelines[8]);
my @dhcp   = split(/ +/," ".$tablelines[9]);
# get the 'byte' counter as this is what we use
my $ndevices = $device[2];
my $nservers = $server[2];
my $nallans  = $allan[2];
my $nkarens  = $karen[2];
my $nkevins  = $kevin[2];
my $ncarls   = $carl[2];
my $nothers  = $other[2];
my $ndhcps   = $dhcp[2];

RRDs::update("$rrdlog/bwin.rrd", "-t", "devices:servers:allans:karens:kevins:carls:others:dhcps", "N:$ndevices:$nservers:$nallans:$nkarens:$nkevins:$ncarls:$nothers:$ndhcps");
$ERROR = RRDs::error;
print "Error in RRD::update for bandwidth-in: $ERROR\n" if $ERROR;
}


4. In the same file, add a procedure to make the actual graphs:


sub updatebandwidthingraph {
my $period = $_[0];
my @rrd = ();

push @rrd, @{&rrd_header("bwin", $period, "$Lang::tr{'bwin'} ($Lang::tr{$period})", -1, -1, -1)};
push @rrd, "-v bandwidth";
push @rrd, "DEF:bdevices=$rrdlog/bwin.rrd:devices:AVERAGE";
push @rrd, "DEF:bservers=$rrdlog/bwin.rrd:servers:AVERAGE";
push @rrd, "DEF:ballans=$rrdlog/bwin.rrd:allans:AVERAGE";
push @rrd, "DEF:bkarens=$rrdlog/bwin.rrd:karens:AVERAGE";
push @rrd, "DEF:bkevins=$rrdlog/bwin.rrd:kevins:AVERAGE";
push @rrd, "DEF:bcarls=$rrdlog/bwin.rrd:carls:AVERAGE";
push @rrd, "DEF:bothers=$rrdlog/bwin.rrd:others:AVERAGE";
push @rrd, "DEF:bdhcps=$rrdlog/bwin.rrd:dhcps:AVERAGE";

push @rrd, "CDEF:devices=bdevices,8,*";
push @rrd, "CDEF:servers=bservers,8,*";
push @rrd, "CDEF:allans=ballans,8,*";
push @rrd, "CDEF:karens=bkarens,8,*";
push @rrd, "CDEF:kevins=bkevins,8,*";
push @rrd, "CDEF:carls=bcarls,8,*";
push @rrd, "CDEF:others=bothers,8,*";
push @rrd, "CDEF:dhcps=bdhcps,8,*";
push @rrd, "CDEF:hardware=devices,servers,+";
push @rrd, "CDEF:guests=others,dhcps,+";
push @rrd, "CDEF:total=guests,hardware,allans,karens,kevins,carls,+,+,+,+,+";

push @rrd, "COMMENT:User                          Latest                    Average                     Maximum\\r";
push @rrd, "AREA:guests#FF0000:$Lang::tr{'guests'}  ";
push @rrd, "GPRINT:guests:LAST:%9.0lf k";
push @rrd, "GPRINT:guests:AVERAGE:%9.0lf k";
push @rrd, "GPRINT:guests:MAX:%9.0lf k\\j";

push @rrd, "STACK:hardware#C0C0C0:$Lang::tr{'hardware'}";
push @rrd, "GPRINT:hardware:LAST:%9.0lf k";
push @rrd, "GPRINT:hardware:AVERAGE:%9.0lf k";
push @rrd, "GPRINT:hardware:MAX:%9.0lf k\\j";

push @rrd, "STACK:allans#80FF80:$Lang::tr{'allans'}   ";
push @rrd, "GPRINT:allans:LAST:%9.0lf k";
push @rrd, "GPRINT:allans:AVERAGE:%9.0lf k";
push @rrd, "GPRINT:allans:MAX:%9.0lf k\\j";

push @rrd, "STACK:karens#8080FF:$Lang::tr{'karens'}   ";
push @rrd, "GPRINT:karens:LAST:%9.0lf k";
push @rrd, "GPRINT:karens:AVERAGE:%9.0lf k";
push @rrd, "GPRINT:karens:MAX:%9.0lf k\\j";

push @rrd, "STACK:kevins#FFB381:$Lang::tr{'kevins'}   ";
push @rrd, "GPRINT:kevins:LAST:%9.0lf k";
push @rrd, "GPRINT:kevins:AVERAGE:%9.0lf k";
push @rrd, "GPRINT:kevins:MAX:%9.0lf k\\j";

push @rrd, "STACK:carls#FF8080:$Lang::tr{'carls'}    ";
push @rrd, "GPRINT:carls:LAST:%9.0lf k";
push @rrd, "GPRINT:carls:AVERAGE:%9.0lf k";
push @rrd, "GPRINT:carls:MAX:%9.0lf k\\j";

push @rrd, "LINE1:total#000000";

push @rrd, @{&rrd_lastupdate()};
RRDs::graph(@rrd);

$ERROR = RRDs::error;
print "Error in RRD::graph for bandwidth-in: $ERROR\n" if $ERROR;
}

5. Finaly in makegraphs, add the calls to the two procdures (I'm using my hourly mod' too :-):


###
### System graphs
###

updatebandwidthin();
updatebandwidthingraph("hour");
updatebandwidthingraph("day");
updatebandwidthingraph("week");
updatebandwidthingraph("month");
updatebandwidthingraph("year");

updatecpudata();
updatecpugraph("hour");
updatecpugraph("day");
updatecpugraph("week");

6. Add a (new) language file in /var/ipcop/addons/lang/, here's mine:


# Added
%tr = ( %tr,
'bw' => 'Bandwidth',
'bwin' => 'Bandwidth in',
'bwout' => 'Bandwidth out',
'devices' => 'Hardware',
'servers' => 'Servers',
'allans' => 'Allan',
'karens' => 'Karen',
'kevins' => 'Kevin',
'carls' => 'Carl',
'others' => 'OTHERS',
'dhcps' => 'DHCP',
'hardware' => 'Hardware',
'guests' => 'Guests',
);

7. If you've added a language file, run the command rebuildlangtexts

8. Next in /home/httpd/cgi-bin/graphs.cgi add the following lines as indicated:



$ENV{'QUERY_STRING'} =~ s/&//g;
@cgigraphs = split(/graph=/,$ENV{'QUERY_STRING'});
$cgigraphs[1] = '' unless defined $cgigraphs[1];

if ($cgigraphs[1] =~ /(network|GREEN|BLUE|ORANGE|RED|bwin)/) {
&Header::openpage($Lang::tr{'network traffic graphs'}, 1, '');
}
else {
&Header::openpage($Lang::tr{'system graphs'}, 1, '');
}
&Header::openbigbox('100%', 'left');

if ($cgigraphs[1] =~ /(GREEN|BLUE|ORANGE|RED|cpu|memory|diskuse|disk|bwin)/) {
# Display 1 specific graph

my $graph = $cgigraphs[1];
my ($graphname, $count) = split('_', lc($graph));
my $back = '';
my $title = '';
if ($graph =~ /(GREEN|BLUE|ORANGE|RED|bwin)/) {


$title = ($count >= 2) ? $Lang::tr{$graphname}." ".$count : $Lang::tr{$graphname};
$back = "<a href='/cgi-bin/graphs.cgi?graph=network'>";
$title = $Lang::tr{'bwin'} if ($graph eq 'bwin');

and


elsif ($cgigraphs[1] =~ /network/) {
# Display network graphs

push (@graphs, ("bwin"));

# RED_1 will always be there even in case of RED_COUNT==0
# as makegraphs will create RED_1 for MODEM/ISDN type connections
push (@graphs, ("RED_1"));

for my $color ('GREEN', 'ORANGE', 'BLUE') {

You can see my latest graph output here.


^Top
Previous page: Link Quality v2
Next page: Hourly Graphs