November 17th 2007 Posted in
Linux
很久很久没有写什么东西了,太忙了,根本没有时间空下来写点什么。这几天算是有点空了,大家手上的事情也不多了,所以上班的时候也比较空,不少公司的人在上班时间疯狂下载。。。 搞得我连ssh都不能正常操作。。。
所以上网看了不少关于流量控制的东西,终于能在我这边应用一下了,原来我这边是用的l7-filter做的,但后来发现这东西是很好,但也有不足,从l7-filter出现以来,他的一些filter都已经失效了,象讯雷的,和verycd版的emule都不能用了。所以l7-filter的作用就不那么明显了。那怎么办呢?用ipp2p?这个更老。。。
如果你仔细想想,象讯雷、BT,和电驴都是P2P的软件,P2P的软件有一个共性,那就是需要很多个并发连接。那是不可以从这方面出发呢? 答案是肯定的。
先来看看怎么控制,很简单,还是用iproute2里面的tc来控制。上网找了很多资料,我用的是gentoo,所以这里一篇howto讲的很详细(http://forums.gentoo.org/viewtopic-t-225863-postdays-0-postorder-asc-highlight-bandwidth+control-start-0.html),这里面主要用的是HTB (Hierarchical Token Bucket) qdisc,这个比CBQ相比,更易懂,更高效,而且HTB能更精确的保证流量。
有关HTB的介绍,可以看这里 http://luxik.cdi.cz/~devik/qos/htb/manual/userg.htm
上面两个文章看过之后,那么下面就是一些简单的问题了
/sbin/tc qdisc del dev ppp0 root
/sbin/tc qdisc add dev ppp0 root handle 1: htb default 20
# Set total bandwidth to 80K, adsl has only about 60K
/sbin/tc class add dev ppp0 parent 1: classid 1:1 htb rate 80kbps
/sbin/tc class add dev ppp0 parent 1:1 classid 1:10 htb rate 80kbps prio 1
/sbin/tc class add dev ppp0 parent 1:1 classid 1:20 htb rate 30kbps ceil 60kbps prio 2
/sbin/tc class add dev ppp0 parent 1:1 classid 1:30 htb rate 10kbps ceil 20kbps prio 3
/sbin/tc qdisc add dev ppp0 parent 1:10 handle 10: sfq perturb 10
/sbin/tc qdisc add dev ppp0 parent 1:20 handle 20: sfq perturb 10
/sbin/tc qdisc add dev ppp0 parent 1:30 handle 30: sfq perturb 10
/sbin/tc filter add dev ppp0 protocol ip parent 1:0 handle 101 fw flowid 1:10
/sbin/tc filter add dev ppp0 protocol ip parent 1:0 handle 102 fw flowid 1:20
/sbin/tc filter add dev ppp0 protocol ip parent 1:0 handle 103 fw flowid 1:30
在这里,我用的if是ppp0,HTB是一个层级的,最上层的是一个总流量,然后下面的每个子类的都量都必须小于等于总流量。我把它分成三类,上面第二个文章里说到不同的class是可以借用代宽的。这也就是为什么我在1:20和1:30后面指定了ceil,这也就是说明,如果只有这一个class在使用代宽的情况下,1:20可以使用到60K,但如果1:10和1:30都在用带宽,那么1:20只能到30K。然后网卡根据每个包的mark把他们放在不同的class里。这个mark,就是iptables的工作了。 另外一个要注意的,就是速度的单位, 看看man tc可以知道,这里面的单位可以有几种方式,表示速度的单位
表示量的单位:
-
kb or k Kilobytes
-
mb or m Megabytes
-
mbit Megabits
-
kbit Kilobits
那么上面我是用的ppp0来做流量,这里就会有问题了,实际上,我们做流量的时候,我们可以控制的是从我们这里发出数据包的速度,而无法控制别人用多少的速度发给我。就如gentoo的那个howto里提到的,其实理论上也是可以控制的,因为我们都是用TCP/IP协议,在TCP/IP协议里面,用一个ACK packet 来回应发送数据的主机,也就是服务器,然后服务器确认你已经收到他上一个包的时候,才会再发送第二个包,那么理论上讲,可以控制这个ACK,但是就象那howto里说的,这个只是理论。。 那我们再换一个角度去考虑,我们能控制从我这台机器发出数据包的速度,那么对于NAT的网关和LAN来说,不也正是这样的么,上面的一堆tc能控制从我们NAT网站到Internet的数据速度,也就是上传速度。那么我们再反过来限制一下从NAT到我们LAN的速度,不就可以达到控制下载速度了么。是的,表面上看是这样,但是你还是无法控制Internet上进来的数据速度,这样做,只是白白浪费了带宽(不过,电信那么黑,反正也是浪费他的带宽)。
那么现在要看的就是如何控制下载速度。下载速度控制,还有另一个问题,就是我服务器有两个网卡,一个是接LAN,一个是接ADSL,服务器还同时充当文件服务器的作用,如果我在LAN上限制流量,那么我的文件服务器不就变成了一个废物了么? 再一想,也简单,上面不是说了么流量是根据每个包的mark来决定的,那么有iptables,可以很简单的区分什么包是从internet上来的,什么包是来自我服务器的。所以,下载速度的限制,就要做在连LAN的那个网卡上。
/sbin/tc qdisc del dev eth0 root
/sbin/tc qdisc add dev eth0 root handle 1: htb default 20
# Total traffic set to 1000M
/sbin/tc class add dev eth0 parent 1: classid 1:1 htb rate 1000mbps
/sbin/tc class add dev eth0 parent 1:1 classid 1:10 htb rate 256kbps prio 1
/sbin/tc class add dev eth0 parent 1:1 classid 1:20 htb rate 60kbps ceil 80kbps prio 2
/sbin/tc class add dev eth0 parent 1:1 classid 1:30 htb rate 30kbps ceil 60kbps prio 3
/sbin/tc class add dev eth0 parent 1:1 classid 1:40 htb rate 10kbps ceil 15kbps prio 4
# Internal traffic set to 1000M
/sbin/tc class add dev eth0 parent 1:1 classid 1:50 htb rate 1000mbps prio 5
/sbin/tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
/sbin/tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
/sbin/tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10
/sbin/tc qdisc add dev eth0 parent 1:40 handle 40: sfq perturb 10
/sbin/tc qdisc add dev eth0 parent 1:50 handle 50: sfq perturb 10
# Send packet to different queue according to it's mark number
/sbin/tc filter add dev eth0 protocol ip parent 1:0 handle 1 fw flowid 1:10
/sbin/tc filter add dev eth0 protocol ip parent 1:0 handle 2 fw flowid 1:20
/sbin/tc filter add dev eth0 protocol ip parent 1:0 handle 3 fw flowid 1:30
/sbin/tc filter add dev eth0 protocol ip parent 1:0 handle 4 fw flowid 1:40
/sbin/tc filter add dev eth0 protocol ip parent 1:0 handle 5 fw flowid 1:50
这里,我把lan的总流量设定成1000M,另外再加一个class就是1000M的流量。其它几个都是控制下载流量的。
下面就是iptables的工作了。在内核版本2.6.23以前,connlimit都是一个iptables的P-O-M,从2.6.23开始,它正始进入内核。所以我们的iptables在编译时就要使用内核的extention才行。不知道别人的系统启动好后eth0的mtu是多少,但是正常情况下,adsl的mtu是1460,而我其它的网卡的mtu是1500,这样会有一些问题,会让一些网站不能正常访问, 所以必须要在iptables里面加上-A FORWARD -p tcp -m tcp –tcp-flags SYN,RST SYN -j TCPMSS –clamp-mss-to-pmtu 这个东西是干什么用的?自已经去man吧,简单的讲,他把一个TCP SYN包的MSS值减40,所以它只能工作在mangle表中。这样就没有问题了。另外,下面的所有的东西都是在mangle表中进行的。
对于上传,很好控制,把所有来自LAN的IP包全都mark成102,也就是对应最上面的速度30K,峰值速度60K。然后可以随时进行机动处理,把它们mark成101或者最慢的103
对于下载,要区分文件服务和Internet,这个很简单,对于所有不是来自于192.168.0.1(服务器IP)的,全部mark成2(60K,峰值80K),所有来自于192.168.0.1的,全部mark成5(最大速度)。
其它的,可以用connlimit来进行限制,连接数大于20的给30K,连接数大于40的,只给10K,这样的话,只要用BT,讯雷或者什么什么P2P的软件,连接数会很容易的超过20,我前几天看到一个连接数为2000多个,其中一半是讯雷的。
另外,iptables还有一个hashlimit,这个是统计所有的包速率,也包含LAN到Server的文件服务,这个不同于connlimit,connlimit只计算tcp连接,另外,在网上能找到的文章里提到的iplimit,老早就被hashlimit代替了。
最后忘了说了,控制上传的chain是FORWARD,控制下载的是POSTROUTING。