10

I want to display the current network utilization (bandwidth usage) of one interface of a Debian box on a website. It is not supposed to be very elaborate or precise, just a simple number such as "52 Mbit/s".

Typical network bandwidth monitors such as iftop give me no way to simply extract such a value.

How can I best retrieve it?

For example, I guess I might parse /proc/net/dev every few minutes. Not sure if this is really the best way to do this though.

5 Answers 5

13

I think ifstat will help you :

[root@localhost ~]# ifstat -i eth0 -q 1 1
       eth0
 KB/s in  KB/s out
 3390.26     69.69
7

The best way to do it simply is probably to parse /proc/net/dev (be warned that /proc is not portable). Here's a bash script I quickly put together that should be able to calculate it:

#!/bin/bash

_die() {
    printf '%s\n' "$@"
    exit 1
}

_interface=$1

[[ ${_interface} ]] || _die 'Usage: ifspeed [interface]'
grep -q "^ *${_interface}:" /proc/net/dev || _die "Interface ${_interface} not found in /proc/net/dev"

_interface_bytes_in_old=$(awk "/^ *${_interface}:/"' { if ($1 ~ /.*:[0-9][0-9]*/) { sub(/^.*:/, "") ; print $1 } else { print $2 } }' /proc/net/dev)
_interface_bytes_out_old=$(awk "/^ *${_interface}:/"' { if ($1 ~ /.*:[0-9][0-9]*/) { print $9 } else { print $10 } }' /proc/net/dev)

while sleep 1; do
    _interface_bytes_in_new=$(awk "/^ *${_interface}:/"' { if ($1 ~ /.*:[0-9][0-9]*/) { sub(/^.*:/, "") ; print $1 } else { print $2 } }' /proc/net/dev)
    _interface_bytes_out_new=$(awk "/^ *${_interface}:/"' { if ($1 ~ /.*:[0-9][0-9]*/) { print $9 } else { print $10 } }' /proc/net/dev)

    printf '%s: %s\n' 'Bytes in/sec'  "$(( _interface_bytes_in_new - _interface_bytes_in_old ))" \
                      'Bytes out/sec' "$(( _interface_bytes_out_new - _interface_bytes_out_old ))"

    # printf '%s: %s\n' 'Kilobytes in/sec'  "$(( ( _interface_bytes_in_new - _interface_bytes_in_old ) / 1024 ))" \
    #                   'Kilobytes out/sec' "$(( ( _interface_bytes_out_new - _interface_bytes_out_old ) / 1024 ))"

    # printf '%s: %s\n' 'Megabits in/sec'  "$(( ( _interface_bytes_in_new - _interface_bytes_in_old ) / 131072 ))" \
    #                   'Megabits out/sec' "$(( ( _interface_bytes_out_new - _interface_bytes_out_old ) / 131072 ))"

    _interface_bytes_in_old=${_interface_bytes_in_new}
    _interface_bytes_out_old=${_interface_bytes_out_new}
done

Bear in mind that sleep does not consider the amount of time it takes to do the operations in the while loop, so this is (very slightly) inaccurate. On my 600mhz coppermine, the loop takes 0.011 seconds -- a negligible inaccuracy for most purposes. Bear in mind also when using the (commented out) kilobyte/megabit outputs, bash only understands integer arithmetic.

3
  • I think that this should be the chosen answer. Every other solution relays, behind the scenes, on parsing /proc/net/dev, without actually understanding what and how this magic happens.
    – Eran
    Apr 27, 2016 at 9:30
  • This solution worked for me on a router / busybox.
    – cloneman
    Sep 14, 2016 at 1:19
  • Use date +%s.%N to get the unix timestamp for every iteration and divide the bytes difference by the timestamp difference. Then you avoid the problem of loop iterations being longer than 1s.
    – Arnavion
    Aug 6, 2019 at 17:35
3

There are network traffic monitors like vnstat that keeps monthly records of your traffic, or slurm which takes it's values directly from those stored in kernel. It's available in most distro repos.

Here is what I see when I run slurm -i ra0:

enter image description here

3

Here is a very simple shell script to calculate this:

#!/bin/sh

dev=$1

grep -q "^$dev:" /proc/net/dev || exec echo "$dev: no such device"

read rx <"/sys/class/net/$dev/statistics/rx_bytes"
read tx <"/sys/class/net/$dev/statistics/tx_bytes"

while sleep 1; do
    read newrx <"/sys/class/net/$dev/statistics/rx_bytes"
    read newtx <"/sys/class/net/$dev/statistics/tx_bytes"

    # convert bytes to kbit/s: bytes * 8 / 1000 => bytes / 125
    echo "$dev  {rx: $(((newrx-rx) / 125)), tx: $(((newtx-tx) / 125))}"

    rx=$newrx
    tx=$newtx
done

just start the script passing the interface name, eg. ./shtraf eth1

3
  • 2
    Can you explain this a little?  Exactly what should the parameter be?  What is the significance of 125?  Please do not respond in comments; edit your answer to make it clearer and more complete. Feb 7, 2018 at 16:42
  • It would be interesting why you divide by 125
    – Aleksandar
    Dec 20, 2020 at 11:53
  • @Aleksandar yeah, it shouldn't be divided by 125. I patched it and added some formatting dpaste.com/5TW5YD53T Jun 26, 2021 at 16:31
0

I can't comment because I don't have enough reputation so I'll just post another answer but no credit to me it's the exact same script posted by teknoraver here. I've only added a space to make it work on dafang.

So if you are like me and are looking for a way to watch bandwidth usage on xiaomi-dafang-hacks and can't install tools, this script will work. The only difference is the space at the beginning of the /proc/net/dev. I don't know why but on dafang, the line doesn't start with the interface but rather space and interface. Hope this can help someone.

#!/bin/sh

dev=$1

grep -q "^ $dev:" /proc/net/dev || exec echo "$dev: no such device"

read rx <"/sys/class/net/$dev/statistics/rx_bytes"
read tx <"/sys/class/net/$dev/statistics/tx_bytes"

while sleep 1; do
    read newrx <"/sys/class/net/$dev/statistics/rx_bytes"
    read newtx <"/sys/class/net/$dev/statistics/tx_bytes"

    # convert bytes to kbit/s: bytes * 8 / 1000 => bytes / 125
    echo "$dev  {rx: $(((newrx-rx) / 125)), tx: $(((newtx-tx) / 125))}"

    rx=$newrx
    tx=$newtx
done

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.