Thursday, January 25, 2018

network-tests: A tool to measure and report a network's latency and bandwidth performance

Because of new IT regulations in my country, since some time the company I work at has to periodically send a report to the IT ministry with performance data that measures our current network bandwidth performance that is used for our customer's services (I work at a company that is kinda of a small ISP for other ISP). 

We had some requirements, like: 
  • Being able to run multiple upload/download/ping tests
  • Calculate some stats over the results, like minimum, maximum and average speeds, and standard deviation, 
  • Send a CSV file with the results (both totals and all tests).

Looking around at the time (mid 2017) there wasn't any tool that could do all of this in one go and doing it manually was a daunting task. Sure, there are lots of tools to measure bandwidth usage  and network latency (like speedtest-cli and the good old ping command) that you could glue together with bash and some sed/grep/awk jujitsu and get all the values and the report as asked, but it could be really painful to develop and maintain thereafter. 

So I decided to write it in python.

For the sake of simplicity and easier maintenance I decided to split network-test's tests functionality in the obvious three:

Each of them share the following features:
  • Run multiple tests in one go.
  • Calculate average speeds for multiple tests.
  • Bandwidth measurement in both Mbps and MB/s.
  • Overall statistics with metrics like minimum, maximum and average speeds, and standard deviation.
  • Save the results and stats to a file with CSV format.

Installation

The program uses setup tools, so after cloning the git repo:
git clone https://github.com/juanluisbaptiste/network-tests

And inside the project directory run:
sudo python setup.py install

Installation is still flaky so maybe there could be some errors. Now lets see some examples of how to use these tools:

 

Network Latency

First lets see which parameters the program accepts:

usage: ping-tester [-h] [-c COUNT] -f PINGFILE [-o OUTFILE] [-I INTERFACE]
                    [-s]

optional arguments:
  -h, --help            show this help message and exit
  -c COUNT, --count COUNT
                        Ping count. Default: 5
  -f PINGFILE, --pingfile PINGFILE
                        List of hosts to ping
  -o OUTFILE, --outfile OUTFILE
                        Destination file for ping results
  -I INTERFACE          Network interface to use for pinging
  -s, --silent          Don't print verbose output from the test
The first thing to do to use it is to put in a file the list of hosts that are going to be ping'ed during the test For example, you could use this small test list:
www.google.com
www.yahoo.com
www.cisco.com
www.facebook.com
Now, for example if you needed to do 5 latency measurements against that list and save the results with stats to a file use the following command:

python ping-tester -c 5 -f hosts.txt -o results.csv

That would yield the following results:
juancho@moon:~$ ping-tester -c 5 -f $PWD/hosts.txt -o $PWD/pingtest.csv
Network Interface: Default
Ping Count: 5
Hosts: 4

Test #1:
Pinging Host www.google.com
Min: 0.488 ms Max: 0.497 ms Average: 0.491 ms Packet Loss Count: 0 Packet Loss Rate: 0.0%

Test #2:
Pinging Host www.yahoo.com
Min: 105.01 ms Max: 114.116 ms Average: 106.967 ms Packet Loss Count: 0 Packet Loss Rate: 0.0%

Test #3:
Pinging Host www.cisco.com
Min: 63.029 ms Max: 63.062 ms Average: 63.044 ms Packet Loss Count: 0 Packet Loss Rate: 0.0%

Test #4:
Pinging Host www.facebook.com
Min: 63.565 ms Max: 63.582 ms Average: 63.572 ms Packet Loss Count: 0 Packet Loss Rate: 0.0%


Time elapsed: 17.0 seconds

Average min: 58.02 ms
Average max: 60.31 ms
Average ping: 58.52 ms
Average packet loss count: 0.0
Average packet loss rate: 0.0 %
Standard deviation: 9.49 ms

And the CSV file has the following content:
Count,Time Elapsed (s),Min (ms),Max (ms),Average (ms),Packet Loss Count,Packet Loss Rate (%),Standard Deviation (ms)
5,17.0,58.02,60.31,58.52,0.0,0.0,9.49

Count,Min (ms),Max (ms),Average (ms),Std Deviation (ms),Lost,% Lost,Host
5,0.488,0.497,0.491,0.0,0,0.0,www.google.com
5,105.01,114.116,106.967,0.0,0,0.0,www.yahoo.com
5,63.029,63.062,63.044,0.0,0,0.0,www.cisco.com
5,63.565,63.582,63.572,0.0,0,0.0,www.facebook.com
There you have some global stats from all the tests, and bellow them are the individual results, with their own stats too.

Bandwidth tests

This tests are split in two programs:

 

Download-tester

These are the command parameters:

usage: download-tester [-h] [-c COUNT]
                         [-l {usw,use,tokyo,washington,sanjose,london}]
                         [-o OUTFILE] [-s] [-u URL]

optional arguments:
  -h, --help            show this help message and exit
  -c COUNT, --count COUNT
                        Number of downloads to do. Default: 1
  -l {usw,use,tokyo,washington,sanjose,london}, --location {usw,use,tokyo,washington,sanjose,london}
                        Server location for the test. Default: use
  -o OUTFILE, --outfile OUTFILE
                        Destination file for test results in CSV format
  -s, --silent          Don't print verbose output from the download process
  -u URL, --url URL     Alternate download URL (it must include path and

To do 5 downloads and save results to a CSV file, use this command:
download-tester -c 5 -o $PWD/download-test.csv

This would be a sample of the program's output:
juancho@moon:~$ download-tester -c 5 -o $PWD/download-test.csv                                
download_speed.pyc 0.1.1                       

Location: use                                  
URL: http://speedtest.newark.linode.com/100MB-newark.bin                                      
Total Tests: 5                                 

Test #1:                                       
[==================================================] 11.65 MB/s - 93.21 Mbpss                 
Downloaded file size: 100.0 MB                 

Average download speed: 11.65 MB/s - 93.21 Mbps                                               

Test #2:                                       
[==================================================] 11.65 MB/s - 93.21 Mbpss                 
Downloaded file size: 100.0 MB

Average download speed: 11.65 MB/s - 93.21 Mbps

Test #3: 
[==================================================] 11.65 MB/s - 93.21 Mbpss
Downloaded file size: 100.0 MB

Average download speed: 11.65 MB/s - 93.21 Mbps

Test #4: 
[==================================================] 13.11 MB/s - 104.86 Mbps
Downloaded file size: 100.0 MB

Average download speed: 13.11 MB/s - 104.86 Mbps

Test #5: 
[==================================================] 11.65 MB/s - 93.21 Mbpss
Downloaded file size: 100.0 MB

Average download speed: 11.65 MB/s - 93.21 Mbps


Test Results:
---- -------

Time Elapsed: 9.0 seconds

Overall Average Download Speed: 11.94MB/s - 95.54Mbps
Maximum download speed: 13.11MB/s - 104.86Mbps
Minimum download speed: 11.65MB/s - 93.21Mbps
Median download speed: 11.65MB/s - 93.21Mbps
Standard Deviation: 0.58MB/s - 4.66Mbps
download-tester includes some download HTTP URL's that can be used by using the -l parameter, although, I think this feature needs some rethinking, at least in the way they are named. You can also use your own HTTP download URL using the -u parameter. It currently only support HTTP downloads.

Like with the ping-tester program, results are saved to a CSV file:
Date,URL,Size (MB),Min (MB/s),Min (Mbps),Max (MB/s),Max (Mbps),Average (MB/s),Average (Mbps),Median (MB/sec),Median (Mbps)
Mon Jul 10 00:14:59 2017,http://speedtest.tokyo.linode.com/100MB-tokyo.bin,100.0,1.29,1.29,1.33,10.62,1.31,1.31,1.31,10.49

Sample#,File Size,Average Speed (MB/sec),Average Throughput (Mbps)
1,100.0,1.31,10.49
2,100.0,1.31,10.49
3,100.0,1.29,10.36
4,100.0,1.31,10.49
5,100.0,1.33,10.62

Upload-tester

These are the command parameters:
usage: upload-tester [-h] [-c COUNT] -f UPLOADFILE [-o OUTFILE] [-s] -l HOST
                       -u USERNAME -p PASSWORD [-P PASSIVE]

optional arguments:
  -h, --help            show this help message and exit
  -c COUNT, --count COUNT
                        Number of uploads to do. Default: 1
  -f UPLOADFILE, --uploadfile UPLOADFILE
                        Test file to upload
  -o OUTFILE, --outfile OUTFILE
                        Destination file for test results in CSV format
  -s, --silent          Don't print verbose output from the upload process
  -l HOST, --host HOST  FTP server for upload test
  -u USERNAME, --username USERNAME
                        FTP user name for upload test
  -p PASSWORD, --password PASSWORD
                        FTP password for upload test
  -P PASSIVE, --passive PASSIVE
                        Sets FTP passive mode. Default: False
The upload tests are done over FTP, so you need to have an ftp server and username available for the test. For example, to do 5 upload tests against ftp.example.com you can use the following command:
upload-tester -c 5 -f $PWD/test10Mb.db -l ftp.example.com -u bob -p mypassword
Yes, I know is not very secure to set the password over the command line, but this is just a testing tool and you are supposed to use a testing account too ;)

That command would show the following output:
juancho@moon:~$ upload-tester -c 5 -f $PWD/test10Mb.db -l ftp.example.com -u bob -p xxxxx
upload_speed.pyc v0.1.1

FTP Host: ftp.example.com
Username: bob
Password: xxxxx
File: /home/juancho/test10Mb.db
Size: 10.0MB

Total Tests: 5

Test #1:
[==================================================] 10.49 MB/s - 83.89 Mbps^[[23~

Average upload speed: 10.49MB/s - 83.89Mbps

Test #2:
[==================================================] 10.49 MB/s - 83.89 Mbps^F

Average upload speed: 5.24MB/s - 41.94Mbps

Test #3:
[==================================================] 5.24 MB/s - 41.94 MbpsG

Average upload speed: 5.24MB/s - 41.94Mbps

Test #4:
[==================================================] 5.24 MB/s - 41.94 Mbps

Average upload speed: 5.24MB/s - 41.94Mbps

Test #5:
[==================================================] 10.49 MB/s - 83.89 Mbps

Average upload speed: 10.49MB/s - 83.89Mbps


Test Results:
---- -------

Time Elapsed: 1.0 seconds

Overall Average download speed: 7.34MB/s - 58.72Mbps
Maximum download speed: 10.49MB/s - 83.89Mbps
Minimum download speed: 5.24MB/s - 41.94Mbps
Median download speed: 5.24MB/s - 41.94Mbps
Standard Deviation: 2.57MB/s - 20.55Mbps
Also with the CSV output:
Date,Server,File,Size,Min (MB/s),Min (Mbps),Max (MB/s),Max (Mbps),Average (MB/s),Average (Mbps),Median (MB/sec),Median (Mbps)
Mon Jul 10 00:11:00 2017,ftp.server.yyy,/home/juancho/test10Mb.db,4.16,0.15,0.15,0.23,1.84,0.18,1.42,0.17,1.34

Sample#,File Size,Average Speed (MB/sec),Average Throughput (Mbps)
1,4.16,0.17,1.34
2,4.16,0.15,1.2
3,4.16,0.23,1.84
4,4.16,0.17,1.34
5,4.16,0.17,1.4

If you are having trouble with the upload you can test FTP passive mode with the -P parameter.


ToDo

There is stuff that I would like to add soon, like:
  • Automatic conversion of speeds depending if the current value is over for ex, 1000kbps it should be shown as Mbps, if less than 1000kbps it should be shown as kbps, etc.
  • FTP download tests, currently only HTTP(S) is supported as a download method.

Contributions welcomed !