First, lets setup some bash variables to point to the various commands we will use throughout the script. We will also set variables to indicate our maximum bandwidth in both directions.
TC=
"/usr/sbin/tc"
IPT=
"/usr/sbin/iptables"
IP=
"/usr/sbin/ip"
INSMOD=
"/sbin/insmod"
RMMOD=
"/sbin/rmmod"
DNLD_BANDWIDTH=
"12288kbit"
UPLD_BANDWIDTH=
"2048kbit"
Next, lets setup the download shaping by adding a queuing discipline (qdisc) to device br0 and tell the qdisc the maximum throughput.
TCA=
"${TC} class add dev br0"
TFA=
"${TC} filter add dev br0"
TQA=
"${TC} qdisc add dev br0"
${TQA} root handle 1: htb
${TCA} parent 1: classid 1:1 htb rate ${DNLD_BANDWIDTH}
Next, we are going to setup 2 classes. Each class will be setup with a guaranteed bandwidth and a maximum bandwidth if the other class is underutilized. The first class will have a guaranteed download bandwidth of 8Mbps. The second class will have a guaranteed download bandwidth of 4Mbps. Both classes will be able to utilize up to 12Mbps depending on how active the other class is.
{TCA} parent 1:1 classid 1:10 htb rate 8192kbit ceil ${DNLD_BANDWIDTH} prio 1
{TCA} parent 1:1 classid 1:11 htb rate 4096kbit ceil ${DNLD_BANDWIDTH} prio 2
{TQA} parent 1:10 handle 10: sfq perturb 10
{TQA} parent 1:11 handle 11: sfq perturb 10
Now we need to setup a filter for each class. This is ensure only packets marked with the filter’s tag will be restricted. The mark is denoted by the ip handle. Here we will use 10 and 11, to match the classids of the classes we just defined.
${TFA} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
${TFA} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
Now to setup the upload shaping, we have to create a imq device.
${INSMOD} imq
${INSMOD} ipt_IMQ
${IP} link
set
imq0 up
Next, we need to setup a qdisc, classes, and filters for our 2 classes. Just like we did for download, only this time using the imq0 device and the upload bandwidths. The first class will have a guaranteed upload bandwidth of ~1.3Mbps and the second class will have a guaranteed upload bandwidth of 700Kbps.
TCAU=
"${TC} class add dev imq0"
TFAU=
"${TC} filter add dev imq0"
TQAU=
"${TC} qdisc add dev imq0"
${TQAU} root handle 1: htb
${TCAU} parent 1: classid 1:1 htb rate ${UPLD_BANDWIDTH}
${TCAU} parent 1:1 classid 1:10 htb rate 1348kbit ceil ${UPLD_BANDWIDTH} prio 1
${TCAU} parent 1:1 classid 1:11 htb rate 700kbit ceil ${UPLD_BANDWIDTH} prio 2
${TQAU} parent 1:10 handle 10: sfq perturb 10
${TQAU} parent 1:11 handle 11: sfq perturb 10
${TFAU} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
${TFAU} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
Finally, now that all our shaping is setup, we need to use iptables to mark packets to indicate which packets to shape. My internal network is 192.168.1.0/24. So we only mark packets headed for the internet and leave internal traffic alone. The first class will be restricted to a single IP address. The second class will be restrict to a group of IPs using CIDR notation (32 DHCP addresses from the router).
# download
${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0
/24
-d 192.168.1.2 -j MARK --
set
-mark 10
${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0
/24
-d 192.168.1.128
/27
-j MARK --
set
-mark 11
# upload
${IPT} -t mangle -A PREROUTING -j IMQ --todev 0
${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0
/24
-s 192.168.1.2 -j MARK --
set
-mark 10
${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0
/24
-s 192.168.1.128
/27
-j MARK --
set
-mark 11
Note: I would really like to use iptables range of address notation (e.g. -m iprange –src-range 192.168.1.3-192.168.1.254), but current builds of DD-WRT do not seem to work with that notation. I posted to the DD-WRT forums and I’ll I got was IP ranges are not supported. So for my own purposes, I just have giant script with many iptables commands, one for each IP address I want to shape.
To make it easy to start, stop, restart, I wrote an init.d style script for the above. I use it as part of the DD-WRT custom firewall script.
To make it easy to start, stop, restart, I wrote an init.d style script for the above. I use it as part of the DD-WRT custom firewall script.
#!/bin/bash
TC=
"/usr/sbin/tc"
IPT=
"/usr/sbin/iptables"
IP=
"/usr/sbin/ip"
INSMOD=
"/sbin/insmod"
RMMOD=
"/sbin/rmmod"
DNLD_BANDWIDTH=
"12228kbit"
UPLD_BANDWIDTH=
"2048kbit"
DNLD_CLASS10_BANDWIDTH=
"8192kbit"
DNLD_CLASS11_BANDWIDTH=
"4096kbit"
UPLD_CLASS10_BANDWIDTH=
"1348kbit"
UPLD_CLASS11_BANDWIDTH=
"700kbit"
[ -x ${TC} ] ||
exit
1
[ -x ${IPT} ] ||
exit
1
[ -x ${IP} ] ||
exit
1
[ -x ${INSMOD} ] ||
exit
1
[ -x ${RMMOD} ] ||
exit
1
case
"${1}"
in
start)
echo
-n
"Starting bandwidth shaping service ... "
# download
TCA=
"${TC} class add dev br0"
TFA=
"${TC} filter add dev br0"
TQA=
"${TC} qdisc add dev br0"
${TQA} root handle 1: htb
${TCA} parent 1: classid 1:1 htb rate ${DNLD_BANDWIDTH}
${TCA} parent 1:1 classid 1:10 htb rate ${DNLD_CLASS10_BANDWIDTH} ceil ${DNLD_BANDWIDTH} prio 1
${TCA} parent 1:1 classid 1:11 htb rate ${DNLD_CLASS11_BANDWIDTH} ceil ${DNLD_BANDWIDTH} prio 2
${TQA} parent 1:10 handle 10: sfq perturb 10
${TQA} parent 1:11 handle 11: sfq perturb 10
${TFA} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
${TFA} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
# upload
${INSMOD} imq
${INSMOD} ipt_IMQ
${IP} link
set
imq0 up
TCAU=
"${TC} class add dev imq0"
TFAU=
"${TC} filter add dev imq0"
TQAU=
"${TC} qdisc add dev imq0"
${TQAU} root handle 1: htb
${TCAU} parent 1: classid 1:1 htb rate ${UPLD_BANDWIDTH}
${TCAU} parent 1:1 classid 1:10 htb rate ${UPLD_CLASS10_BANDWIDTH} ceil ${UPLD_BANDWIDTH} prio 1
${TCAU} parent 1:1 classid 1:11 htb rate ${UPLD_CLASS11_BANDWIDTH} ceil ${UPLD_BANDWIDTH} prio 2
${TQAU} parent 1:10 handle 10: sfq perturb 10
${TQAU} parent 1:11 handle 11: sfq perturb 10
${TFAU} parent 1:0 prio 2 protocol ip handle 10 fw flowid 1:10
${TFAU} parent 1:0 prio 2 protocol ip handle 11 fw flowid 1:11
# download
${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0
/24
-d 192.168.1.2 -j MARK --
set
-mark 10
${IPT} -t mangle -A POSTROUTING -s ! 192.168.1.0
/24
-d 192.168.1.128
/27
-j MARK --
set
-mark 11
# upload
${IPT} -t mangle -A PREROUTING -j IMQ --todev 0
${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0
/24
-s 192.168.1.2 -j MARK --
set
-mark 10
${IPT} -t mangle -A PREROUTING -d ! 192.168.1.0
/24
-s 192.168.1.128
/27
-j MARK --
set
-mark 11
echo
"done"
;;
stop)
echo
-n
"Stopping bandwidth shaping service ... "
# download
${IPT} -t mangle -D POSTROUTING -s ! 192.168.1.0
/24
-d 192.168.1.2 -j MARK --
set
-mark 10
${IPT} -t mangle -D POSTROUTING -s ! 192.168.1.0
/24
-d 192.168.1.128
/27
-j MARK --
set
-mark 11
# upload
${IPT} -t mangle -D PREROUTING -d ! 192.168.1.0
/24
-s 192.168.1.2 -j MARK --
set
-mark 10
${IPT} -t mangle -D PREROUTING -d ! 192.168.1.0
/24
-s 192.168.1.128
/27
-j MARK --
set
-mark 11
${IPT} -t mangle -D PREROUTING -j IMQ --todev 0
${TC} qdisc del dev br0 root
${TC} qdisc del dev imq0 root
${IP} link
set
imq0 down
${RMMOD} ipt_IMQ
${RMMOD} imq
echo
"done"
;;
restart)
${0} stop
sleep
1
${0} start
;;
status)
${TC} qdisc show dev br0
${TC} class show dev br0
${TC} filter show dev br0
${TC} qdisc show dev imq0
${TC} class show dev imq0
${TC} filter show dev imq0
;;
*)
echo
"Usage: ${0} {start|stop|restart|status}"
exit
1
;;
esac
exit
0
http://roback.cc/wp/2009/09/bandwidth-shaping-with-linux/#Introduction