QoS Linux with HFSC
HFSC
HFSC is a method to prioritize traffic with iptables and tc. Make sure your kernel supports HFSC.I successfully use this script, which brought me dramatically improved latency while up- and downloading simultaneously via a 1024/128 adsl line (in Germany). I tried the same with HTB before, and it didn't work so well. I use a 2.6.10 kernel image on Debian Linux.
- !/bin/sh
- SipShaper v0.01
- VoIP Traffic Shaper for 1024/128Kbit/s ADSL Line
- Written by Udo Schacht-Wiegand (2005-04-03)
- based on MYSHAPER from Dan Singletary (8/7/02)
- http://www.nslu2-linux.org/wiki/HowTo/EnableTrafficShaping
- and on phone-man's script
- http://www.ip-phone-forum.de/forum/viewtopic.php?p=100371#100371
- and on the (German) Linux Magazine 02/05 article p.28
- Please mail comments and improvements to sipshaper at udo dot comlink dot org
- Set your outgoing interface and upload rate (in kbit/s) here
RATEUP=128
RTPS=$(cat /etc/asterisk/rtp.conf|awk -F= '/rtpstart/ {print $2}')
RTPE=$(cat /etc/asterisk/rtp.conf|awk -F= '/rtpend/ {print $2}')
- Which ports should be prioritized (yes, I know that ssh is not VoIP ;-)
- Which servers should be prioritized (may be empty "")
- end of configuration options
- show status and exit
if [ "$1" = "status" ]
then
echo "[qdisc]"
tc -s qdisc show dev $DEV
echo ""
echo "[class]"
tc -s class show dev $DEV
echo ""
echo "[filter]"
tc -s filter show dev $DEV
echo ""
echo "[iptables]"
iptables -t mangle -L SIPSHAPER -v -x 2> /dev/null
exit
fi
- default: start it #
- Reset everything to a known state (cleared)
- Flush and delete tables
iptables -t mangle --flush SIPSHAPER 2> /dev/null > /dev/null
iptables -t mangle --delete-chain SIPSHAPER 2> /dev/null > /dev/null
- stop it and exit
if [ "$1" = "stop" ]
then
echo "Shaping removed on $DEV."
exit
fi
- set up shaping
- add HFSC root qdisc
- add main rate limit class
- keep it simple: two classes only
tc class add dev $DEV parent 1:1 classid 1:11 hfsc sc umax 1500b dmax 30ms rate 80kbit ul rate ${RATEUP}kbit
- add SIPSHAPER chain to the mangle table in iptables
iptables -t mangle --insert POSTROUTING -o $DEV -j SIPSHAPER
- Filter for voip packets
- VoIP ports as defined above
do
iptables -t mangle -A SIPSHAPER -p udp --sport $port -j MARK --set-mark 1
iptables -t mangle -A SIPSHAPER -p udp --dport $port -j MARK --set-mark 1
done
- VoIP IPs as defined above
do
iptables -t mangle -A SIPSHAPER -p udp --src $ip -j MARK --set-mark 1
iptables -t mangle -A SIPSHAPER -p udp --dst $ip -j MARK --set-mark 1
done
echo SipShaper started on $DEV with ${RATEUP}kbit/s upload rate.
echo -n "QoS activated for ports: "
for port in $VOIPPORTS
do
echo -n " $port"
done
echo "."
echo -n "QoS activated for ip# : "
for ip in $VOIPIPS
do
echo -n " $ip"
done
echo "."
对于复杂的流量管制方案,阶层式演算法是必要的。新近版本的linux可采用的演算法有htb和hfsc 。而htb基本上是将token bucket filter( tbf )转换成阶层式架构,保留了tbf的主要特征, 而hfsc允许按比例分配频宽并且控制及分配延迟(latency)。这能够在只有一条实体网路连线的情况下,又快又好地同时提供频宽密集的资料传输服务及互动式服务。
当网路被一个以上的实体连线连结或提供各种不同的服务时,我们需要一些合理的资源管理以保障个人服务及共享连接使用者的最低频宽。尤其是关于VOIP或串流服务,无论是单纯的频宽分配或降低延迟都变得相形重要。
在两个使用者共享一个1000kbit频宽的网际网路连线的情况下,每个使用者在任何特定的时刻都应该享有最低500kbit的保证频宽。其中User A,分配最高100kbit的频宽于网络电话其余的传输流量为一般资料传输。图1显示了相应的结构图。
1: Hierarchy of shared network access.
假设所有封包都是固定的大小1500bytes,并且所有等级都以最快速度发送。在1000kbit的频宽下,每12毫秒(8*1500 byte / 1000000 bit/s = 12ms)发送一个封包。 VOIP占用的100kbit相当于每秒8个封包。为了满足这个类别100kbit的保证速率, qdisc必须从这个类别每120ms发出一个封包,这表示每个封包最高会有132ms的queueing delay。这个例子说明了频宽与latency的关系。
hfsc演算法同时处理频宽和延迟两样资源。为了解决这个问题,演算法使用service curve模型以分配资源。 service curve S(t) 表示单位时间t内的工作成果(bits) ,斜率表示传输速率。
延迟互动的概念存在于个别等级服务曲线的结构。透过选择一个由两部分组成(每一部分都是线性)的服务曲线,VOIP的传输延迟可降到30ms。首段服务曲线在30ms的期间内提供400kbit的斜率(传输速率),而第二部分则呈现出100kbi的速率t 。虽然在任何一点上都是所有曲线加总后顶多到达服务曲线的总容量,但却从其他等级赚到了大约78ms的延迟降低。在我们的例子中,VOIP的延迟降低是以经调整至低于全域限制A群组中未指定资料的等级为成本。因此,这个等级的最高传输延迟从30 ms增加至52.5ms。至于非连续性的资料传输,如ftp
,重要的是总吞吐量,延迟的重要性较为次之,因此仍符合服务曲线的设定值。
Figure 2: Scenario with linear and multi-part linear service curves.
hfsc 演算法区分成即时(real-time)和连接共享(link-sharing)两种标准。一个叶类别可以同时指派real-tim及link-sharing曲线,而子类别只能有一个link-sharing曲线。即时(real-time)只适用于叶类别,因为实际上只有叶类别持有封包。因此即时导向的准则负责必要服务的达成。连接共享(link-sharing)的标准则只涉及本身与相邻类别的关连,负责公平分配,而不提供绝对的保证。为了在各种情况下都能够确保最低延迟时间,分离成两个标准是必要的。以结果而言,这也表示即使已经短暂超过上层子类别link-sharing曲线之限制,仍然可以根据叶类别的即时保证继续发送封包。
让我们谈谈我们例子中已经启用,并以其最高速率400 kbit发送封包的资料类别A。现在,如果VOIP类别在任何时间点启动都被允许根据其real-time的保证得以较高的速率传送(图3 )。于是,这意味着A类别在短时间内超出了link-sharing的设定参数500kbit。为了达成长期的link-sharing的保证速率。 A类别将因这短暂的超支被”惩罚”。
Figure 3: Between t1 and t2, exceeds the total maximum allowed capacity.
每个类别都会被指定一个与服务完成时间一致的”虚拟时间”。为了尽快将封包送出,会从根类别开始之阶层式架构中全面性的搜寻出提供最低达成的虚拟时间之类别。叶类别找出准则后即发送封包并且那个类别的虚拟时间,从其亲类别一路往上到根类别,将相应增加。如果一个类别在其real-time参数的基础上进行传输,其虚拟时间也会被加大。
HFSC usage on Linux
设定一个hfsc qdisc。指定qdisc的根类别到一个网络介面,并且可以自订一些规格:
tc qdisc add dev $dev root handle $ID: hfsc [default $classID ]
建立阶层式的类别
tc add class dev $dev parent parentID classid $ID hfsc [ [ rt SC ] [ ls SC ] | [ sc SC ] ] [ ul SC ]
属性是根据以下描述的服务曲线设定:
SC := [ umax bytes dmax ms ] rate BPS
我们可以如link-sharing (ls)曲线般的指定一条real-time曲线( rt )给处于最低层次的叶类别(leaf class),其上层的子类别(inner class)则只能有link-sharing曲线。透过使用ul服务曲线,可以定义每个类别实际对提供服务的上限。可以透过指定单一的SC曲线来代替指定rt曲线及ls曲线。一条服务曲线由斜率描述其传输速率。如果曲线由两部份组成,可以由在保证传输速率umax时的maximum delay – dmax指定。
名词解释:
层级:
root:根类别,制订最上层的总频宽限制
inner class:子类别,定义各主要的频宽分配
leaf class:叶类别,
# Example from Figure 1.
tc qdisc add dev eth0 root handle 1: hfsc
tc class add dev eth0 parent 1: classid 1:1 hfsc sc rate 1000kbit ul rate 1000kbit
tc class add dev eth0 parent 1:1 classid 1:10 hfsc sc rate 500kbit ul rate 1000kbit
tc class add dev eth0 parent 1:1 classid 1:20 hfsc sc rate 500kbit ul rate 1000kbit
tc class add dev eth0 parent 1:10 classid 1:11 hfsc sc umax 1500b dmax 53ms rate 400kbit ul rate 1000kbit
tc class add dev eth0 parent 1:10 classid 1:12 hfsc sc umax 1500b dmax 30ms rate 100kbit ul rate 1000kbit