Skip to content

Instantly share code, notes, and snippets.

@guangmuzhu
Forked from ole1986/traffic-control.sh
Last active February 25, 2020 04:48
Show Gist options
  • Save guangmuzhu/cfbf176fe9d1ec933521f883d26d2f6d to your computer and use it in GitHub Desktop.
Save guangmuzhu/cfbf176fe9d1ec933521f883d26d2f6d to your computer and use it in GitHub Desktop.
Traffic control script for incoming and outgoing packages using TC (on a specific ip address)
#!/bin/bash
VERSION="1.0.7"
# Interface connect to out lan
INTERFACE="eth0"
# Interface virtual for incomming traffic
VIRTUAL="ifb0"
# Try to skip reset
CHANGE=0
# set the direction (1 = outgoing only, 2 = incoming only 3 = both)
DIRECTION=3
# Speed
SPEED_DOWNLOAD="10mbit"
SPEED_UPLOAD="10mbit"
# Queue length (in packet)
LIMIT=100
# Loss in percent (0 = no loss)
LOSS="0%"
# Delay in milliseconds (0 = no delay)
DELAY="40ms"
function show_usage {
echo
echo "Bandwidth Control using TC"
echo "Version: $VERSION | Author: ole1986, cambda"
echo
echo "Usage: $1 [-h|--help] [-I|--if=] [-c|--change] [-r|--remove] [-i|--incoming] [-o|--outgoing] [-L|--limit=] [-d|--delay=] [-l|--loss=] [-U|--uspeed=] [-D|--dspeed=] <IP>"
echo
echo "Arguments:"
echo " -h|--help : show usage"
echo " -I|--if=<if> : the interface to connect"
echo " -c|--change : not removes all traffic control being set automatically"
echo " -r|--remove : removes all traffic control being set"
echo " -i|--incoming : limit the bandwidth only for incoming packetes"
echo " -o|--outgoing : limit the bandwidth only for outgoing packetes"
echo " -L|--limit=100 : define the queue length (default: 100)"
echo " -d|--delay=40ms : define the latency (default: 40ms)"
echo " -l|--loss=0% : define the loss (default: 0%)"
echo " -U|--uspeed=<speed>: define the upload speed (default: 10mbit)"
echo " -D|--dspeed=<speed>: define the download speed (default: 10mbit)"
echo " <IP> : the ip address to limit the traffic for"
echo
echo "Changelog:"
echo "v1.0.7 - add help as argument"
echo "v1.0.6 - add change mode as argument"
echo "v1.0.5 - add queue length as argument"
echo "v1.0.4 - add loss as argument adn modify default values"
echo "v1.0.3 - add interface as argument"
echo "v1.0.2 - make use of the 'tc change' instead of removing"
echo "v1.0.1 - add uspeed and dspeed to setup limit as argument"
echo "v1.0.0 - initial version"
}
function remove_tc {
echo "Unlimit traffic on $INTERFACE (in/out)"
# clean up outgoing
[[ $(tc qdisc | grep '^qdisc htb 1:') ]] && tc qdisc del root dev $INTERFACE
# clean up incoming
if [[ $(tc qdisc | grep '^qdisc htb 2:') ]]; then
tc qdisc del dev $INTERFACE handle ffff: ingress
tc qdisc del root dev $VIRTUAL
# Unload the virtual network module
ip link set dev $VIRTUAL down
modprobe -r ifb
fi
}
function tc_outgoing {
echo "Limit outgoing traffic"
# update outgoing speed (if already exists)
echo "- upload speed $SPEED_UPLOAD"
if [[ $CHANGE -ne 0 || $(tc class show dev $INTERFACE | grep '^class htb 1:1') ]]; then
TCC="tc class change"
else
# Add classes per ip
tc qdisc add dev $INTERFACE root handle 1: htb direct_qlen 2
TCC="tc class add"
fi
$TCC dev $INTERFACE parent 1: classid 1:1 htb rate $SPEED_UPLOAD quantum 1600
# update netem
echo "- queue length $LIMIT"
echo "- latency $DELAY"
echo "- loss $LOSS"
if [[ $CHANGE -ne 0 || $(tc qdisc | grep '^qdisc netem 10:') ]]; then
TCN="tc qdisc change"
else
TCN="tc qdisc add"
fi
$TCN dev $INTERFACE parent 1:1 handle 10: netem limit $LIMIT delay $DELAY loss $LOSS
# Match ip and put it into the respective class
echo "- filter on IP $ADDRESS"
if [[ $CHANGE -ne 0 || $(tc filter show dev $INTERFACE | grep '^filter parent 1: protocol ip pref 1') ]]; then
TCF="tc filter change"
else
TCF="tc filter add"
fi
$TCF dev $INTERFACE protocol ip parent 1: handle 800::801 prio 1 u32 match ip dst $ADDRESS flowid 1:1
}
function tc_incoming {
# setup virtual interface to redirect incoming traffic
if [ $CHANGE -eq 0 ]; then
modprobe ifb numifbs=1
ip link set dev $VIRTUAL up
fi
echo "Limit incoming traffic"
# update incoming speed (if already exists)
echo "- download speed $SPEED_DOWNLOAD"
if [[ $CHANGE -ne 0 || $(tc class show dev $VIRTUAL | grep '^class htb 2:1') ]]; then
TCC="tc class change"
else
tc qdisc add dev $INTERFACE handle ffff: ingress
# Redirecto ingress eth0 to egress ifb0
tc filter add dev $INTERFACE parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $VIRTUAL
# Add classes per ip
tc qdisc add dev $VIRTUAL root handle 2: htb direct_qlen 2
TCC="tc class add"
fi
$TCC dev $VIRTUAL parent 2: classid 2:1 htb rate $SPEED_DOWNLOAD quantum 1600
# update netem
echo "- queue length $LIMIT"
echo "- latency $DELAY"
echo "- loss $LOSS"
if [[ $CHANGE -ne 0 || $(tc qdisc | grep '^qdisc netem 20:') ]]; then
TCN="tc qdisc change"
else
TCN="tc qdisc add"
fi
$TCN dev $VIRTUAL parent 2:1 handle 20: netem limit $LIMIT delay $DELAY loss $LOSS
# Match ip and put it into the respective class
echo "- filter on IP $ADDRESS"
if [[ $CHANGE -ne 0 || $(tc filter show dev $VIRTUAL | grep '^filter parent 1: protocol ip pref 1') ]]; then
TCF="tc filter change"
else
TCF="tc filter add"
fi
$TCF dev $VIRTUAL protocol ip parent 2: handle 800::802 prio 1 u32 match ip src $ADDRESS flowid 2:1
}
if [ $# -eq 0 ]; then
show_usage $0
exit 0
fi
for i in "$@"
do
case $i in
-h|--help)
show_usage $0
exit 0
;;
-c|--change)
CHANGE=1
shift
;;
-r|--remove)
DIRECTION=0
shift
;;
-o|--outgoing)
DIRECTION=1
shift
;;
-i|--incoming)
DIRECTION=2
shift
;;
-I=*|--if=*)
INTERFACE=${i#*=}
shift
;;
-L=*|--limit=*)
LIMIT=${i#*=}
shift
;;
-l=*|--loss=*)
LOSS=${i#*=}
shift
;;
-d=*|--delay=*)
DELAY=${i#*=}
shift
;;
-U=*|--uspeed=*)
SPEED_UPLOAD="${i#*=}"
shift
;;
-D=*|--dspeed=*)
SPEED_DOWNLOAD="${i#*=}"
shift
;;
esac
done
[ $CHANGE -eq 0 ] && remove_tc
[ -n $1 ] && ADDRESS=$1
[ $DIRECTION -eq 0 ] && exit 0
if [ -z $ADDRESS ]; then
echo
echo "No IP address defined"
exit 0
fi
[ $DIRECTION -eq 1 ] && tc_outgoing
[ $DIRECTION -eq 2 ] && tc_incoming
if [ $DIRECTION -eq 3 ]; then
tc_outgoing
tc_incoming
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment