Getting live network bandwidth numbers on Linux

May 8, 2008

Today I got curious about a simple question: was my iSCSI target machine actually running at its full potential read speed?

The machine exports individual disks to its clients, so measuring single disk performance wouldn't give me the answer. Summing up IO across all the disks would have given me a number, but so would just getting the network bandwidth utilization; if the machine was saturating its gigabit link, it was clearly running as fast as it could.

There doesn't seem to be a program that will directly show this information (at least not on Red Hat Enterprise 5), but you can get the total byte counts for an interface from ifconfig, which means that with a small script I had what I wanted. (Then I rewrote it to read the stats directly from /proc/net/dev instead of running ifconfig and groping through the output.)

Since it may be useful for other people, here's what I'm calling netvolmon:

#!/bin/sh
# usage: netvolmon DEV [INTERVAL]
DEV=$1
IVAL=5
if [ "$#" -eq 2 ]; then
    IVAL=$2
fi

getrxtx() {
    grep "$1:" /proc/net/dev | sed 's/^.*://' |
        awk '{print $1, $9}'
}

rxtx=$(getrxtx $DEV)
while sleep $IVAL; do
    nrxtx=$(getrxtx $DEV)
    (echo $IVAL $rxtx $nrxtx) |
    awk '{rxd = ($4 - $2) / (1024*1024*$1);
          txd = ($5 - $3) / (1024*1024*$1);
          printf "%6.2f MB/s RX %6.2f MB/s TX\n",
                 rxd, txd}'
    rxtx="$nrxtx"
done

Unfortunately this illustrates one reason why shell scripting is so pervasive: it is such a convenient way of banging rocks together in a hurry. Once I hit on the trick of using awk for all the arithmetic, it probably took me longer to fiddle with the output formatting than to write the rest of the script.

(And I have to give bash a big raspberry for making array variables useless for precisely the situation where they would be most useful, namely picking individual elements out of the output of a command that prints multiple pieces of information.)


Comments on this page:

From 88.97.233.154 at 2008-05-09 04:08:20:

Useful, thanks.

Although not necessarily so portable; Dstat is also a very handy tool to have around for measuring IO on Unix NAS and SAN hosts.

From 198.236.64.24 at 2008-05-09 11:11:28:

Not that I can't appreciate a good shell script, but iptraf is available in RHEL5. Cheers!

-- Dan Young

By cks at 2008-05-09 15:24:21:

Dstat is interesting; thank you for the pointer.

Unfortunately I have to dock iptraf style points for requiring me to be root to get anything out of it. I'm sure there's features that need root access, but I want to get at least the unprivileged statistics (what I'm usually interested in) without having to become root.

From 71.121.1.227 at 2008-05-11 21:01:50:

Come on Chris, a grep followed by a sed followed by an awk? I am sure you could have thrown in a cat or two!

gettxrx(){
    local IFS=$' \t\n:' A
    A=($(grep "$1:" /proc/net/dev))
    echo ${A[2]} ${A[10]}
}

And you could have used the more cryptic

IVAL=${2:-5}

Switching to ksh would have given you floating point, and you could have written the whole script using only builtins.

Icarus Sparry

By cks at 2008-05-11 22:28:37:

I stand corrected about bash's array variables being (not) useful for this sort of thing; evidently I didn't test them carefully enough. Personally, I have never warmed to tricks with $IFS, and so don't use it even when it might help.

From 168.103.159.247 at 2008-05-12 01:10:43:

I think iftop (http://www.ex-parrot.com/~pdw/iftop/) hits the sweet spot for this, much like top for basic load figures. The bpf and regex filtering bits are a nice bonus.

From 71.121.1.227 at 2008-05-12 01:34:17:

The issue in this case is that the format of the /proc/net/dev is not very friendly for anything. Your original solution used sed just to remove the dev name (and the colon). You could have used awk to do the work as well,

getrxtx() {
   awk "/$1:/"' {sub(".*:","",$1); print $1,$9;}' /proc/net/dev
}

I am assuming that as you dislike changing IFS, you would also not want to change awk's FS variable.

If on the other hand /proc/net/dev put a space after the : or else replaced the : with some whitespace then you would not need the 'sub' statement (just add 1 to the 1 and 9 to account for the extra field). It would also allow you not to need 'tricks' with IFS to split the line in my other solution. Of course it is now far too late to change the format of the file, so one has to work around the (lack of) design.

Icarus Sparry

By cks at 2008-05-12 08:21:48:

The really annoying thing about /proc/net/dev is that it sometimes has a space between the : and the received byte count and sometimes doesn't (if the byte count is big enough). Since the space is sometimes there, it might be possible to persuade Linux people that it should always be there, but I suspect it's unlikely since it hasn't been fixed before now.

Written on 08 May 2008.
« Today's Solaris 10 irritation: the fault manager daemon
An advantage of interpreted languages »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Thu May 8 23:18:38 2008
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.