NetStress

From RidgeRun Developer Wiki
Revision as of 19:47, 28 February 2013 by Mgruner (talk | contribs)

Overview

NetStress is a command line utility that simulates bad network conditions for multiple kinds of streaming. It is meant for testing multimedia server and client robustness by stressing the transmission channel. To do so NetStress provides two different packet modeling:

  • Loss: Percentage in which the packets are randomly dropped. For a 1% loss: 1 of 100 packets is dropped randomly.
  • Delay: Amount of milliseconds to delay samples.

Both parameters apply in a bidirectional way, this is, for packets coming from the server and entering the client, and packets entering the server coming from the client.


Dependencies

NetStress is based on GNU/Linux traffic control (tc). This tool is distributed as part of the iproute package.

Basic Usage

~# netstress -h
~# netstress -a ip [-d delay ] [-l loss]

Arguments

Argument Purpose Nature
-h Help Optional
-a IP address Mandatory
-d Delay (ms) Optional
-l Loss (%) Optional


Adding packet delay

To add a 10ms delay to every packet sent and received from a RTSP stream produced by a device with IP address: 192.168.1.58

~# netstress -d 10 -a 192.168.1.58

Adding packet loss

To add a 5% loss to every packet sent and received from an UPD stream produced by a device with IP address: 10.251.101.66

~# netstress -l 5 -a 10.251.101.66

Adding packet delay and loss

To add a 1% loss and 20ms delay to every packet sent and received from a RTP stream produced by a device with IP address: 10.251.101.146

~# netstress -l 1 -d 20 -a 10.251.101.146

Clearing up simulation

To clear up any current configured simulation

~# netstress 


Download

Copy this script into a file named netstress.sh and give it read and execution permissions

#!/bin/sh

LOSS=0%
DELAY=0ms
INTERFACE=eth0
ADDRESS=0
DIR="bi"

usage()
{
    cat <<EOF
This script simulates bad streaming conditions by dropping or delaying network packets streamed to a given port.
Root is the only user allowed to run this script

Options:
-h             : Prints this help
-i <interface> : Specifies the interface to be used on the simulation. Defaults to 'eth0'. 
-l <loss>      : Defines the percentage of packets to drop. Defaults to 0.
-d <delay>     : Defines the amount of miliseconds to delay packets. Defaults to 0.
-a <ipaddress> : Mandatory argument to specifies the ip address to apply the simulation to. The loss and delay will be applied to
                 the packets coming from and going to this address.
-o             : Apply simulation to outgoing packets only. If neither -o or -i option is specified then simulation will be applied bidirectionaly.
-n             : Apply simulation to incoming packets only. If neither -o or -i option is specified then simulation will be applied bidirectionaly.
Examples:

Drop 1% of the packets received through a UDP stream at address 192.168.1.168 on both incoming and outgoing packets
  ~# netstress -l 1 -a 192.168.1.168

Drop 10% of the outgoing packets and apply a delay of 5ms of a RTSP stream from device 10.251.101.135 received using the eth1 interface.
  ~# netstress -l 10 -d 5 -i eth1 -a 10.251.101.135 -o

Erase all the simulations applied to the interface 'eth1'
  ~# netstress -i eth1

Erase all the simulations applied to the default interface 'eth0'
  ~# netstress 

Copyright (c) RidgeRun 2013
Michael Gruner <michael.gruner@ridgerun.com>
EOF
}

logerror()
{
    echo "NetStress: error: $1" 1>&2 
    exit 1
}

parseop()
{
   while getopts "honi:l:d:a:" OP
    do
	case $OP in
	    h)
		usage
		exit 0
		;;
	    
	    i)
		INTERFACE=$OPTARG
		;;
	    
	    l)
		LOSS="$OPTARG"% 
		;;
	    
	    d)
		DELAY="$OPTARG"ms
		;;
	    a)
		ADDRESS=$OPTARG
		;;
	    o)
		DIR="out"
		;;
	    n)
		DIR="in"
		;;

	    *)
		usage
		exit 1
		;;
	esac
    done
}

redirecttraffic()
{
    # Insert the module if not already
    modprobe ifb
    ip link set dev ifb0 up

    # Grab the incomming packets and redirect them to ifb0
    tc qdisc del dev $INTERFACE ingress 2>/dev/null || echo ""
    tc qdisc add dev $INTERFACE ingress

    # Redirect to ifb0
    tc filter add dev $INTERFACE parent ffff: \
	protocol ip u32 match u32 0 0 \
	action mirred egress redirect dev ifb0    
}

createtree()
{
    # Tree layout
    #
    #         Ingress 1:0 (ifb0)        Egress 2:0 (eth0)
    #                 |                        |
    #            Class 1:1                 Class 2:1
    #                 |                        |
    #         (Attach netem leaf)      (Attach netem leaf)    
    #
    
    # Root of the tree for all the non-filtered input packets
    tc qdisc add dev ifb0 root handle 1: htb

    # Create a class to attach the filter. Netem leafs can attach to this class
    tc class add dev ifb0 parent 1: classid 1:1 htb rate 100Mbps

    # Root of the tree for all the non-filtered ouput packets
    tc qdisc add dev $INTERFACE root handle 2: htb

    # Create a class to attach the filter. Netem leafs can attach to this class
    tc class add dev $INTERFACE parent 2: classid 2:1 htb rate 100Mbps
}

applyrules()
{
    echo -n "Aplying rules..."
    # Input packets
    tc qdisc add dev ifb0 parent 1:1 handle 10: netem delay $DELAY loss $LOSS || \
	logerror "Failed to apply rules"
    # Output packets
    tc qdisc add dev $INTERFACE parent 2:1 handle 20: netem delay $DELAY loss $LOSS || \
	logerror "Failed to apply rules"
    echo " done!"
}

applyfilter()
{
    echo -n "Aplying filters..."
    #Incoming packets
    if [ $DIR != "out" ]; then
	tc filter add dev ifb0 protocol ip parent 1: prio 3 u32 match ip src $ADDRESS flowid 1:1
    fi

    #Outgoing packets
    if [ $DIR != "in" ]; then
	tc filter add dev $INTERFACE protocol ip parent 2: prio 3 u32 match ip dst $ADDRESS flowid 2:1
    fi
    echo " done!"
}

checkroot()
{
    if [ "root" != `whoami` ]; then
	logerror "Only root is allowed to run this script!"
    fi
}

stopsimulation()
{
    echo -n "Stopping simulation at interface $INTERFACE..."
    
    # Avoid any problems if there was no simulation running 
    tc qdisc del dev $INTERFACE ingress 2>/dev/null || echo -n ""
    tc qdisc del dev $INTERFACE root 2>/dev/null || echo -n ""
    tc qdisc del dev ifb0 root 2>/dev/null || echo -n ""

    echo " done!"
}

main()
{
    #Parse the options passed through the cmdline
    parseop $@
    
    #Check that the user is root
    checkroot

    stopsimulation

    #Check if user wants to erase all rules 
    if $LOSS ==  "0%" && $DELAY == "0ms" ; then
	exit 0
    fi

    #Ip is a mandatory argument
    if $ADDRESS == "0" ; then
	logerror "Ip address is a mandatory parameter"
    fi
   
    echo "Simulation configured to"
    echo -e "\tInterface: $INTERFACE"
    echo -e "\tLoss: $LOSS"
    echo -e "\tDelay: $DELAY"
    echo -e "\tAddress: $ADDRESS"


    redirecttraffic
    createtree
    applyrules
    applyfilter
}

#Calling starting point
main $@

Known Limitations

  • Only one IP address can be filtered at a time.
  • Port filtering is not supported yet


Support

Michael Gruner <michael.gruner@ridgerun.com>