#!/bin/bash # Users 'tc' to emulate a link with a set data rate, delay and drop rate # Run 'vn-link -h' to see the help # Returns the current link rate function get_current_rate { interface=$1 linkclass=`tc class show dev $interface`; # Check that the class is set. # If not, then set rate to -1 (meaning not set) if [ ! "$linkclass" ]; then echo "-1"; else # Check there is a parameter paramexist=`echo $linkclass | grep "rate"` if [ "$paramexist" ]; then paramname=`echo $paramexist | cut -d " " -f 9`; paramvalue=`echo $paramexist | cut -d " " -f 10`; if [ "$paramname" = "rate" ]; then echo $paramvalue else echo "-1" fi else echo "-1" fi fi } # Returns the current link delay function get_current_delay { interface=$1 linkvalues=`tc qdisc show dev $interface | grep delay`; # Check that the class is set. # If not, then set rate to -1 (meaning not set) if [ ! "$linkvalues" ]; then echo "-1"; else paramname=`echo $linkvalues | cut -d " " -f 8`; paramvalue=`echo $linkvalues | cut -d " " -f 9`; if [ "$paramname" = "delay" ]; then echo $paramvalue else # Try again in different positions paramname=`echo $linkvalues | cut -d " " -f 10`; paramvalue=`echo $linkvalues | cut -d " " -f 11`; if [ "$paramname" = "delay" ]; then echo $paramvalue else echo "-1" fi fi fi } # Returns the current link jitter function get_current_jitter { interface=$1 echo "-1"; } function print_help { echo "vn-link views and sets virtual link characteristics."; echo "vn-link applies on outgoing links only. It uses tc to"; echo "set the link data rate, delay and jitter. For example,"; echo "with the following network:"; echo " A (eth1) ------- 100Mb/s, 1ms ----- B (eth0) "; echo "there is a real 100Mb/s duplex link with 1ms delay"; echo "between computers A and B. You can use virtnet to "; echo "modify the link characteristics:"; echo " - limit the output data rate (to be less than actual)"; echo " - add extra delay to all outgoing packets"; echo " - add extra jitter to all outgoing packets"; echo "For example, to create the following network:"; echo " A (eth1) ------- 20Mb/s, 5ms ----- B (eth0) "; echo "on computer A run:"; echo " vn-link --interface eth1 --set --rate 20mbit --delay 4.0ms"; echo "Then the output rate for eth1 interface will be set to"; echo "20 Mbit/s, and an additional 4ms delay added (since "; echo "real delay was 1ms, thats should give a total of 5ms)."; echo "A similar command, using eth0, should be used on B"; echo "for the link from B to A."; } # Get command line options # From: http://mywiki.wooledge.org/BashFAQ/035#getopts # Reset all variables that might be set file="" verbose=0 setvalues=0; # By default, get values clearvalues=0; # By default, don't clear values while : do case $1 in -h | --help | -\?) # Call your Help() or usage() function here. print_help exit 0 # This is not an error, User asked help. Don't do "exit 1" ;; -c | --clear) # Clear values clearvalues=1; shift ;; -s | --set) # Set values setvalues=1; shift ;; -g | --get) # Get values setvalues=0; shift ;; -i | --interface) # Interface interface=$2 shift 2 ;; --interface=*) interface=${1#*=} shift ;; -r | --rate) # Link output rate rate=$2 shift 2 ;; --rate=*) rate=${1#*=} shift ;; -d | --delay) # Link delay delay=$2 shift 2 ;; --delay=*) delay=${1#*=} shift ;; -j | --jitter) # Link jitter jitter=$2 shift 2 ;; --jitter=*) jitter=${1#*=} shift ;; -f | --file) file=$2 # You might want to check if you really got FILE shift 2 ;; --file=*) file=${1#*=} # Delete everything up till "=" shift ;; -v | --verbose) # Each instance of -v adds 1 to verbosity verbose=$((verbose+1)) shift ;; --) # End of all options shift break ;; -*) echo "WARN: Unknown option (ignored): $1" >&2 shift ;; *) # no more options. Stop while loop break ;; esac done # Suppose some options are required. Check that we got them. #if [ ! "$file" ]; then # echo "ERROR: option '--file FILE' not given. See --help" >&2 # exit 1 #fi # Rest of the program here. # If there are input files (for example) that follow the options, they # will remain in the "$@" positional parameters. # Every operation must be on an interface, i.e. the -i option is required if [ ! "$interface" ]; then echo "ERROR: option '--interface INTERFACE' not given. See --help" >&2 exit 1 fi # Set parameters to given values if [ "$setvalues" = "1" ]; then # First retrieve the current values. We will only change the # values that are given on the command line. Other values will # be kept the same as before (unless a reset is requested) currentrate=`get_current_rate $interface` currentdelay=`get_current_delay $interface` currentjitter=`get_current_jitter $interface` # If the value is not given on command line, then check if # there is a current value. If so, then use it. if [ ! "$rate" ]; then if [ "$currentrate" != "-1" ]; then rate=$currentrate; fi fi if [ ! "$delay" ]; then if [ "$currentdelay" != "-1" ]; then delay=$currentdelay; fi fi if [ ! "$jitter" ]; then if [ "$currentjitter" != "-1" ]; then delay=$currentjitter; fi fi # Display the current values echo "Old values" if [ "$currentrate" != "-1" ]; then echo " Rate: $currentrate" else echo " Rate: not set" fi if [ "$currentdelay" != "-1" ]; then echo " Delay: $currentdelay" else echo " Delay: not set" fi if [ "$currentjitter" != "-1" ]; then echo " Jitter: $currentjitter" else echo " Jitter: not set" fi # If the value exists, then set it. # First delete the current tc qdisc tc qdisc del dev $interface root # Now add the parent tc qdisc add dev $interface root handle 1:0 htb default 10 echo "New values" # Set the rate if it exists if [ "$rate" ]; then tc class add dev $interface parent 1:0 classid 1:10 htb rate $rate echo " Rate: $rate" else # tc class add dev $interface parent 1:0 classid 1:10 htb echo " Rate: not set" fi if [ "$delay" ]; then if [ "$jitter" ]; then tc qdisc change dev $interface parent 1:10 handle 10:0 netem delay $delay $jitter echo " Delay: $delay" echo " Jitter: $jitter" else tc qdisc add dev $interface parent 1:10 handle 10:0 netem delay $delay echo " Delay: $delay" echo " Jitter: not set" fi else echo " Delay: not set" echo " Jitter: not set" fi else # Clear the values if [ "$clearvalues" = "1" ]; then tc qdisc del dev $interface root fi # Get values currentrate=`get_current_rate $interface` currentdelay=`get_current_delay $interface` currentjitter=`get_current_jitter $interface` echo "Current values" if [ "$currentrate" != "-1" ]; then echo " Rate: $currentrate" else echo " Rate: not set" fi if [ "$currentdelay" != "-1" ]; then echo " Delay: $currentdelay" else echo " Delay: not set" fi if [ "$currentjitter" != "-1" ]; then echo " Jitter: $currentjitter" else echo " Jitter: not set" fi fi