======================================================================
== Edit: The latest version is 1.05. The description can be found here:
== http://forum.openwrt.org/viewtopic.php?pid=36509#p36509
== The restated goals are the following:
== -allow heavy p2p traffic without affecting web browsing, games or other interactive apps
== -enable VoIP calls not impacted by any other traffic
== -scalable configuration that adapts to a wide range of line speeds
== -easy configuration
======================================================================
Finally, I managed to come up with a qos script that fullfills my simple requirement:
Comfortably surf the web while running several p2p apps at unthrottled speeds
Before writing my own, I tried most every script known to Google. They all failed for several reasons:
1. p2p packet identification was poor, especially when using non-standard port. This turned out to be the case for layer7 as well is ipp2p.
2. ingress throttling was either absent or non-functional
3. configuration of the various qdisc was less than optimal
The fixes for these shortcomings in the final script are as follows:
1. Packet identification is done based on destination ports for outgoing traffic only. The classification is saved on the connection, so incoming packets are identified as well. Besides being very simple, this works without a hitch, since all p2p traffic is to high ports.
2. Included a htb qdisc to the outgoing traffic of the LAN interface. This effectively acts as an ingress discipline for the WAN port.
3. Added a hfsc discipline with balanced rates (they all add up to the parent rate) to the WAN interface. The htb discipline on the LAN port has a long time constant of 1000ms to allow for the long round trip time of internet traffic.
The results are amazing, as evidenced by this email. I am typing up in the web interface of the forum, while running 3 uTorrent downloads at unlimited rates!
Go ahead and give it a try. Let me know if it works for you!
Be sure to set the upload and download rate (slightly) lower than your ADSL or Cable rates to keep modem and ISP queues from filling up, killing interactivity. My measured download and upload rates are 900kb/s and 300kb/s respectively. Setting the speeds in the script to 800kb/s and 280kb/s did the trick.
Rudy.
#!/bin/sh
DEBUG=0
# To enable logging (requires iptables-mod-extra package)
[ $DEBUG -eq 1 ] && insmod ipt_LOG >&- 2>&-
#######################################################
DOWNLOAD=800
UPLOAD=280
D=100
BURST=1000
TCP_BULK="1024:"
UDP_BULK="1024:"
TCP_PRIO="22 23 53 80 443"
UDP_PRIO="53"
#BULK_PROTOS="edonkey bittorrent"
#######################################################
WAN=$(nvram get wan_ifname)
LAN=$(nvram get lan_ifname)
U_M1_PRIO=$(($UPLOAD*90/100))
U_M1_NORM=$(($UPLOAD*10/100))
U_M1_BULK=$(($UPLOAD* 0/100))
U_M2_PRIO=$(($UPLOAD*50/100))
U_M2_NORM=$(($UPLOAD*30/100))
U_M2_BULK=$(($UPLOAD*20/100))
D_BURST=$(($BURST*$DOWNLOAD/8))
insmod cls_fw >&- 2>&-
insmod sch_hfsc >&- 2>&-
insmod sch_htb >&- 2>&-
insmod ipt_CONNMARK >&- 2>&-
insmod ipt_length >&- 2>&-
insmod ipt_limit >&- 2>&-
insmod ipt_tos >&- 2>&-
#insmod sch_ingress >&- 2>&-
#insmod ipt_layer7 >&- 2>&-
#insmod ipt_ipp2p >&- 2>&-
#insmod ipt_multiport >&- 2>&-
#insmod cls_u32 >&- 2>&-
iptables -t mangle -F
iptables -t mangle -X
tc qdisc del dev $WAN root >&- 2>&-
tc qdisc add dev $WAN root handle 1: hfsc default 30
tc class add dev $WAN parent 1: classid 1:1 hfsc sc rate ${UPLOAD}kbit ul rate ${UPLOAD}kbit
tc class add dev $WAN parent 1:1 classid 1:10 hfsc sc m1 ${U_M1_PRIO}kbit d ${D}ms m2 ${U_M2_PRIO}kbit ul rate ${UPLOAD}kbit
tc class add dev $WAN parent 1:1 classid 1:20 hfsc sc m1 ${U_M1_NORM}kbit d ${D}ms m2 ${U_M2_NORM}kbit ul rate ${UPLOAD}kbit
tc class add dev $WAN parent 1:1 classid 1:30 hfsc sc m1 ${U_M1_BULK}kbit d ${D}ms m2 ${U_M2_BULK}kbit ul rate ${UPLOAD}kbit
tc filter add dev $WAN parent 1: prio 1 protocol ip handle 1 fw flowid 1:10
tc filter add dev $WAN parent 1: prio 2 protocol ip handle 2 fw flowid 1:20
tc filter add dev $WAN parent 1: prio 3 protocol ip handle 3 fw flowid 1:30
#tc qdisc del dev $WAN ingress >&- 2>&-
#tc qdisc add dev $WAN handle ffff: ingress
#tc filter add dev $WAN parent ffff: protocol ip prio 50 handle 3 fw police rate $(($DOWNLOAD/2))kbit burst $D_BURST drop flowid :1
#tc filter add dev $WAN parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate $(($DOWNLOAD))kbit burst $D_BURST drop flowid :1
tc qdisc del dev $LAN root >&- 2>&-
# htb qdisc without default: all unmarked (mark 0) packages pass unlimited
tc qdisc add dev $LAN root handle 1: htb
tc class add dev $LAN parent 1: classid 1:1 htb rate ${DOWNLOAD}kbit ceil ${DOWNLOAD}kbit burst $D_BURST cburst $D_BURST
tc class add dev $LAN parent 1:1 classid 1:10 htb rate $(($DOWNLOAD*8/10))kbit ceil ${DOWNLOAD}kbit burst $D_BURST cburst $D_BURST prio 0
tc class add dev $LAN parent 1:1 classid 1:20 htb rate $(($DOWNLOAD*2/10))kbit ceil $(($DOWNLOAD/2))kbit burst $D_BURST cburst $D_BURST prio 1
tc filter add dev $LAN parent 1: prio 1 protocol ip handle 1 fw flowid 1:10
tc filter add dev $LAN parent 1: prio 2 protocol ip handle 2 fw flowid 1:10
tc filter add dev $LAN parent 1: prio 3 protocol ip handle 3 fw flowid 1:20
iptables -t mangle -N mark_chain
iptables -t mangle -N ingress_chain
iptables -t mangle -A POSTROUTING -o $WAN -j mark_chain
iptables -t mangle -A PREROUTING -i $WAN -j ingress_chain
###################################### INGRESS CHAIN #################################################
# Restore any saved connection mark
iptables -t mangle -A ingress_chain -j CONNMARK --restore-mark
# Default is normal priority (to make sure every packet on wan interface gets marked)
iptables -t mangle -A ingress_chain -m mark --mark 0 -j MARK --set-mark 2
# Mark *any* p2p package (first package in connection only)
#iptables -t mangle -A ingress_chain -m mark --mark 0 -m ipp2p --ipp2p -j MARK --set-mark 1
# Mark bulk packets according to Layer 7 match. Works for first package only!
#for PROTO in $BULK_PROTOS; do
# iptables -t mangle -A ingress_chain -m mark --mark 0 -m layer7 --l7proto $PROTO -j MARK --set-mark 1
#done
# Save mark onto connection
#iptables -t mangle -A ingress_chain -j CONNMARK --save-mark
######################################################################################################
######################################## MARK CHAIN ##################################################
# Restore any saved connection mark
iptables -t mangle -A mark_chain -j CONNMARK --restore-mark
# Mark prio packets based on port numbers and protocol
for PORT in $UDP_PRIO; do
iptables -t mangle -A mark_chain -m mark --mark 0 -p udp --dport $PORT -j MARK --set-mark 1
done
for PORT in $TCP_PRIO; do
iptables -t mangle -A mark_chain -m mark --mark 0 -p tcp --dport $PORT -j MARK --set-mark 1
done
# Mark bulk packets based on port numbers and protocol
for PORT in $UDP_BULK; do
iptables -t mangle -A mark_chain -m mark --mark 0 -p udp --dport $PORT -j MARK --set-mark 3
done
for PORT in $TCP_BULK; do
iptables -t mangle -A mark_chain -m mark --mark 0 -p tcp --dport $PORT -j MARK --set-mark 3
done
# Save mark onto connection
iptables -t mangle -A mark_chain -j CONNMARK --save-mark
# Make sure ACK packets get priority
iptables -t mangle -A mark_chain -p tcp -m length --length :128 --tcp-flags SYN,RST,ACK ACK -j MARK --set-mark 1
# Default is normal priority
iptables -t mangle -A mark_chain -m mark --mark 0 -j MARK --set-mark 2
######################################################################################################
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 0 -j LOG --log-prefix mark_0::
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 0 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 1 -j LOG --log-prefix mark_1::
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 1 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 2 -j LOG --log-prefix mark_2::
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 2 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 3 -j LOG --log-prefix mark_3::
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -m mark --mark 3 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A mark_chain -j LOG --log-prefix mark_other::
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 0 -j LOG --log-prefix ingress_0::
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 0 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 1 -j LOG --log-prefix ingress_1::
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 1 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 2 -j LOG --log-prefix ingress_2::
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 2 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 3 -j LOG --log-prefix ingress_3::
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -m mark --mark 3 -j ACCEPT
[ $DEBUG -eq 1 ] && iptables -t mangle -A ingress_chain -j LOG --log-prefix ingress_other::
(Last edited by rudy on 3 Nov 2006, 16:14)