tc流量控制模型

 

linux下tc简介

Linux从kernel 2.1.105开始支持QOS,不过,需要重新编译内核。运行 'make config'时将 EXPERIMENTAL_OPTIONS 设置成 'y',并且将 Class Based Queueing (CBQ), Token Bucket Flow, Traffic Shapers 设置为 'y' ,运行 'make dep&#59; make clean&#59; make bzilo',生成新的内核。

在Linux操作系统中流量控制器(TC)主要是在输出端口处建立一个队列进行流量控制,控制的方式是基于路由,亦即基于目的IP地址或目的子网的网络号的流量控制。流量控制器TC,其基本的功能模块为队列、分类和过滤器。Linux内核中支持的队列有,Class Based Queue ,Token Bucket Flow ,CSZ ,First In First Out ,Priority ,TEQL ,SFQ ,ATM ,RED。这里我们讨论的队列与分类都是基于CBQ(Class Based Queue)的,而过滤器是基于路由(Route)的。

  配置和使用流量控制器TC,主要分以下几个方面:分别为建立队列、建立分类、建立过滤器和建立路由,另外还需要对现有的队列、分类、过滤器和路由进行监视。 
  其基本使用步骤为:
  1) 针对网络物理设备(如以太网卡eth0)绑定一个CBQ队列;
  2) 在该队列上建立分类;
  3) 为每一分类建立一个基于路由的过滤器;

4) 最后与过滤器相配合,建立特定的路由表。

先假设一个简单的环境,如下图所示:

流量控制器上的以太网卡(eth0) 的IP地址为192.168.1.66,在其上建立一个CBQ队列。假设包的平均大小为1000字节,包间隔发送单元的大小为8字节,可接收冲突的发送最长包数目为20字节。
  假如有三种类型的流量需要控制:
  1) 是发往主机1的,其IP地址为192.168.1.24。其流量带宽控制在8Mbit,优先级为2;
  2) 是发往主机2的,其IP地址为192.168.1.26。其流量带宽控制在1Mbit,优先级为1;
  3) 是发往子网1的,其子网号为192.168.1.0,子网掩码为255.255.255.0。流量带宽控制在1Mbit,优先级为6。

1. 建立队列 
  一般情况下,针对一个网卡只需建立一个队列。

  将一个cbq队列绑定到网络物理设备eth0上,其编号为1:0;网络物理设备eth0的实际带宽为10 Mbit,包的平均大小为1000字节;包间隔发送单元的大小为8字节,最小传输包大小为64字节。
  ·tc qdisc add dev eth0 root handle 1: cbq bandwidth 10Mbit avpkt 1000 cell 8 mpu 64

2. 建立分类
  分类建立在队列之上。一般情况下,针对一个队列需建立一个根分类,然后再在其上建立子分类。对于分类,按其分类的编号顺序起作用,编号小的优先;一旦符合某个分类匹配规则,通过该分类发送数据包,则其后的分类不再起作用。

1) 创建根分类1:1;分配带宽为10Mbit,优先级别为8。
·tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 10Mbit rate 10Mbit maxburst 20 allot 1514 prio 8 avpkt 1000 cell 8 weight 1Mbit

  该队列的最大可用带宽为10Mbit,实际分配的带宽为10Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为8,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为1Mbit。

2)创建分类1:2,其父分类为1:1,分配带宽为8Mbit,优先级别为2。
·tc class add dev eth0 parent 1:1 classid 1:2 cbq bandwidth 10Mbit rate 8Mbit maxburst 20 allot 1514 prio 2 avpkt 1000 cell 8 weight 800Kbit split 1:0 bounded

  该队列的最大可用带宽为10Mbit,实际分配的带宽为 8Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为1,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为800Kbit,分类的分离点为1:0,且不可借用未使用带宽。

3)创建分类1:3,其父分类为1:1,分配带宽为1Mbit,优先级别为1。
·tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 10Mbit rate 1Mbit maxburst 20 allot 1514 prio 1 avpkt 1000 cell 8 weight 100Kbit split 1:0

  该队列的最大可用带宽为10Mbit,实际分配的带宽为 1Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为2,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为100Kbit,分类的分离点为1:0。

4)创建分类1:4,其父分类为1:1,分配带宽为1Mbit,优先级别为6。
·tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 10Mbit rate 1Mbit maxburst 20 allot 1514 prio 6 avpkt 1000 cell 8 weight 100Kbit split 1:0

  该队列的最大可用带宽为10Mbit,实际分配的带宽为 64Kbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为1,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为100Kbit,分类的分离点为1:0。

3. 建立过滤器
过滤器主要服务于分类。一般只需针对根分类提供一个过滤器,然后为每个子分类提供路由映射。

1) 应用路由分类器到cbq队列的根,父分类编号为1:0;过滤协议为ip,优先级别为100,过滤器为基于路由表。
·tc filter add dev eth0 parent 1:0 protocol ip prio 100 route

2) 建立路由映射分类1:2, 1:3, 1:4
·tc filter add dev eth0 parent 1:0 protocol ip prio 100 route to 2 flowid 1:2
·tc filter add dev eth0 parent 1:0 protocol ip prio 100 route to 3 flowid 1:3
·tc filter add dev eth0 parent 1:0 protocol ip prio 100 route to 4 flowid 1:4

4.建立路由
该路由是与前面所建立的路由映射一一对应。
1) 发往主机192.168.1.24的数据包通过分类2转发(分类2的速率8Mbit)
·ip route add 192.168.1.24 dev eth0 via 192.168.1.66 realm 2

2) 发往主机192.168.1.30的数据包通过分类3转发(分类3的速率1Mbit)
·ip route add 192.168.1.30 dev eth0 via 192.168.1.66 realm 3

3)发往子网192.168.1.0/24的数据包通过分类4转发(分类4的速率1Mbit)
·ip route add 192.168.1.0/24 dev eth0 via 192.168.1.66 realm 4

  注:一般对于流量控制器所直接连接的网段建议使用IP主机地址流量控制限制,不要使用子网流量控制限制。如一定需要对直连子网使用子网流量控制限制,则在建立该子网的路由映射前,需将原先由系统建立的路由删除,才可完成相应步骤。

5. 监视
  主要包括对现有队列、分类、过滤器和路由的状况进行监视。
1)显示队列的状况

简单显示指定设备(这里为eth0)的队列状况
·tc qdisc ls dev eth0
qdisc cbq 1: rate 10Mbit (bounded,isolated) prio no-transmit

详细显示指定设备(这里为eth0)的队列状况
·tc -s qdisc ls dev eth0
qdisc cbq 1: rate 10Mbit (bounded,isolated) prio no-transmit
Sent 7646731 bytes 13232 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 31 undertime 0

  这里主要显示了通过该队列发送了13232个数据包,数据流量为7646731个字节,丢弃的包数目为0,超过速率限制的包数目为0。

2)显示分类的状况

简单显示指定设备(这里为eth0)的分类状况
·tc class ls dev eth0
class cbq 1: root rate 10Mbit (bounded,isolated) prio no-transmit
class cbq 1:1 parent 1: rate 10Mbit prio no-transmit #no-transmit表示优先级为8
class cbq 1:2 parent 1:1 rate 8Mbit prio 2
class cbq 1:3 parent 1:1 rate 1Mbit prio 1
class cbq 1:4 parent 1:1 rate 1Mbit prio 6

详细显示指定设备(这里为eth0)的分类状况
·tc -s class ls dev eth0
class cbq 1: root rate 10Mbit (bounded,isolated) prio no-transmit
Sent 17725304 bytes 32088 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 31 undertime 0
class cbq 1:1 parent 1: rate 10Mbit prio no-transmit
Sent 16627774 bytes 28884 pkts (dropped 0, overlimits 0)
borrowed 16163 overactions 0 avgidle 587 undertime 0
class cbq 1:2 parent 1:1 rate 8Mbit prio 2
Sent 628829 bytes 3130 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 4137 undertime 0
class cbq 1:3 parent 1:1 rate 1Mbit prio 1
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
borrowed 0 overactions 0 avgidle 159654 undertime 0
class cbq 1:4 parent 1:1 rate 1Mbit prio 6
Sent 5552879 bytes 8076 pkts (dropped 0, overlimits 0)
borrowed 3797 overactions 0 avgidle 159557 undertime 0

  这里主要显示了通过不同分类发送的数据包,数据流量,丢弃的包数目,超过速率限制的包数目等等。其中根分类(class cbq 1:0)的状况应与队列的状况类似。
  例如,分类class cbq 1:4发送了8076个数据包,数据流量为5552879个字节,丢弃的包数目为0,超过速率限制的包数目为0。

显示过滤器的状况
·tc -s filter ls dev eth0
filter parent 1: protocol ip pref 100 route
filter parent 1: protocol ip pref 100 route fh 0xffff0002 flowid 1:2 to 2
filter parent 1: protocol ip pref 100 route fh 0xffff0003 flowid 1:3 to 3
filter parent 1: protocol ip pref 100 route fh 0xffff0004 flowid 1:4 to 4

这里flowid 1:2代表分类class cbq 1:2,to 2代表通过路由2发送。

显示现有路由的状况
·ip route
192.168.1.66 dev eth0 scope link
192.168.1.24 via 192.168.1.66 dev eth0 realm 2
202.102.24.216 dev ppp0 proto kernel scope link src 202.102.76.5
192.168.1.30 via 192.168.1.66 dev eth0 realm 3
192.168.1.0/24 via 192.168.1.66 dev eth0 realm 4
192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.66
172.16.1.0/24 via 192.168.1.66 dev eth0 scope link
127.0.0.0/8 dev lo scope link
default via 202.102.24.216 dev ppp0
default via 192.168.1.254 dev eth0

  如上所示,结尾包含有realm的显示行是起作用的路由过滤器。

6. 维护
  主要包括对队列、分类、过滤器和路由的增添、修改和删除。
  增添动作一般依照"队列->;分类->;过滤器->;路由"的顺序进行;修改动作则没有什么要求;删除则依照"路由->;过滤器->;分类->;队列"的顺序进行。

1)队列的维护
一般对于一台流量控制器来说,出厂时针对每个以太网卡均已配置好一个队列了,通常情况下对队列无需进行增添、修改和删除动作了。

2)分类的维护

增添
增添动作通过tc class add命令实现,如前面所示。

修改
修改动作通过tc class change命令实现,如下所示:
·tc class change dev eth0 parent 1:1 classid 1:2 cbq bandwidth 10Mbit rate 7Mbit maxburst 20 allot 1514 prio 2 avpkt 1000 cell 8 weight 700Kbit split 1:0 bounded
对于bounded命令应慎用,一旦添加后就进行修改,只可通过删除后再添加来实现。

删除
删除动作只在该分类没有工作前才可进行,一旦通过该分类发送过数据,则无法删除它了。因此,需要通过shell文件方式来修改,通过重新启动来完成删除动作。

3)过滤器的维护

增添
增添动作通过tc filter add命令实现,如前面所示。

修改
修改动作通过tc filter change命令实现,如下所示:
·tc filter change dev eth0 parent 1:0 protocol ip prio 100 route to 10 flowid 1:8

删除
删除动作通过tc filter del命令实现,如下所示:
·tc filter del dev eth0 parent 1:0 protocol ip prio 100 route to 10

4)与过滤器一一映射路由的维护

增添
增添动作通过ip route add命令实现,如前面所示。

修改
修改动作通过ip route change命令实现,如下所示:
·ip route change 192.168.1.30 dev eth0 via 192.168.1.66 realm 8

删除
删除动作通过ip route del命令实现,如下所示:
·ip route del 192.168.1.30 dev eth0 via 192.168.1.66 realm 8
·ip route del 192.168.1.0/24 dev eth0 via 192.168.1.66 realm 4

linux下TC控制流量文档c

转载:自己写的流量控制档
自己写的流量控制档 tc2
欢迎转发交流,但请注明原出处信息.powered by KindGeorge.
http://kindgeorge.at.3322.org
#!/bin/bash
#
脚本文件名: tc2
#########################################################################################
#
TC(Traffic Control)解决ADSL宽带速度瓶颈技术 Ver.1.0 powered by KindGeorge
http://kindgeorge.at.3322.org#

#########################################################################################
#
此脚本经过实验通过,更多的信息请参阅http://lartc.org
#tc+iptables+HTB+SFQ
#
#
.什么是ADSL? ADSLAsymmetric Digital Subscriber Loop,非对称数字用户环路)
#用最简单的话的讲,就是采用上行和下行不对等带宽的基于ATM的技术.
#
举例,我们最快的其中一条ADSL带宽是下行3200Kbit,上行只有320Kbit.带宽通常用bit表示.
#
#1
、下行3200K 意味着什么?
#因为 1Byte=8Bit ,一个字节由8个位(bit)组成,一般用大写B表示Byte,小写b表示Bit.
#
所以 3200K=3200Kbps=3200K bits/s=400K bytes/s.
#2
上行320K 意味着什么?
# 320K=320Kbps=320K bits/s=40K bytes/s.
#
就是说,个人所能独享的最大下载和上传速度,整条线路在没任何损耗,最理想的时候,
#
下载只有400K bytes/s,上传只有最大40K bytes/s的上传网速.
#
这些都是理想值,但现实总是残酷的,永远没有理想中那么好.至少也有损耗,何况内部网有几十台
#电脑一起疯狂上网.
#
#3.ADSL
上传速度对下载的影响
#(1)TCP/IP协议规定,每一個封包,都需要有acknowledge讯息的回传,也就是说,传输的资料,
#需要有一个收到资料的讯息回复,才能决定后面的传输速度,並决定是否重新传输遗失
#的资料。上行的带宽一部分就是用來传输這些acknowledge(确认)資料模鄙闲懈涸毓?
#
大的时候,就会影响acknowledge资料的传送速度,并进而影响到下载速度。这对非对称
#数字环路也就是ADSL这种上行带宽远小于下载带宽的连接来说影响尤为明显。
#(2)试验证明,当上传满载时,下载速度变为原来速度的40%,甚至更低.因为上载文件(包括ftp
#
上传,发邮件smtp),如果较大,一个人的通讯量已经令整条adsl变得趋向饱和,那么所有的数据
#包只有按照先进先出的原则进行排队和等待.这就可以解释为什么网内其中有人用ftp上载文件,
#
或发送大邮件的时候,整个网速变得很慢的原因。
#
#
.解决ADSL速度之道
#1. 为解决这些速度问题,我们按照数据流和adsl的特点,对经过线路的数据进行了有规则的分流.
#
把本来在adsl modem上的瓶颈转移到我们linux路由器上,可以把带宽控制的比adsl modem上的小一点,
#
这样我们就可以方便的用tc技术对经过的数据进行分流和控制.
#
我们的想象就象马路上的车道一样,有高速道,还有小车道,大车道.需要高速的syn,ack,icmp等走
#高速道,需要大量传输的ftp-data,smtp等走大车道,不能让它堵塞整条马路.各行其道.
#2. linux
下的TC(Traffic Control)就有这样的作用.只要控制得当,一定会有明显的效果.
#tc
iptables结合是最好的简单运用的结合方法.
#
我们设置过滤器以便用iptables对数据包进行分类,因为iptables更灵活,而且你还可以为每个规则设
#置计数器. iptablesmangle链来mark数据包,告诉了内核,数据包会有一个特定的FWMARK标记值(hanlde x fw)
#表明它应该送给哪个类( classid x : x),prio是优先值,表明哪些重要数据应该优先通过哪个通道.
#
首先选择队列,cbqhtb是不错的选择,经过实验,htb更为好用,所以以下脚本采用htb来处理
#3. 一般系统默认的是fifo的先进先出队列,就是说数据包按照先来先处理的原则,如果有一个大的数
#据包在前面,#那么后面的包只能等前面的发完后才能接着发了,这样就算后面即使是一个小小的ack,
#
也要等待了,这样上传就影响了下载,就算你有很大的下载带宽也无能为力.
#HTB(Hierarchical Token Bucket,
分层的令牌桶)
#
更详细的htb参考
http://luxik.cdi.cz/~devik/qos/htb/

#HTB就象CBQ一样工作,但是并不靠计算闲置时间来整形。它是一个分类的令牌桶过滤器。它只有很少的参数
#他的分层(Hierarchical)能够很好地满足这样一种情况:你有一个固定速率的链路,希望分割给多种不同的
#用途使用,为每种用途做出带宽承诺并实现定量的带宽借用。
#4. 结构简图:
#~~~~~~ |
#~~~~~ __1:__
#~~~~ |~~~~~ |
#~ _ _ _1:1~~~ 1:2_ _ _ _ _ _ _ _
# | ~ ~ | ~ ~ ~ | ~ ~ | ~ ~ | ~ ~ |
#1:11~1:12~~1:21~1:22~1:23~1:24
#
优先顺序是1:11 1:12 1:21 1:22 1:23 1:24
#
#--------------------------------------------------------------------------------------------
#5.
根据上面的例子,开始脚本
#通常adslpppoe连接,的得到的是ppp0,所以公网网卡上绑了ppp0
#
关于参数的说明
#(1)rate: 是一个类保证得到的带宽值.如果有不只一个类,请保证所有子类总和是小于或等于父类.
#(2)ceil: ceil
是一个类最大能得到的带宽值.
#(3)prio:
是优先权的设置,数值越大,优先权越小.如果是分配剩余带宽,就是数值小的会最优先取得剩余
#的空闲的带宽权.
#
具体每个类要分配多少rate,要根据实际使用测试得出结果.
#
一般大数据的话,控制在50%-80%左右吧,ceil最大建议不超过85%,以免某一个会话占用过多的带宽.
#rate
可按各类所需分配,
#1:11
是很小而且最重要的数据包通道,当然要分多点.甚至必要时先全部占用,不过一般不会的.所以给全速.
#1:12
是很重要的数据道,给多点,最少给一半,但需要时可以再多一点.
#rate
规划 1:2 = 1:21 + 1:22 + 1:23 + 1:24 一般总数在50%-80%左右
#1:21 http,pop是最常用的啦,为了太多人用,而导致堵塞,我们不能给得太多,也不能太少.
#1:22
我打算给smtp,优先低于1:21 以防发大的附件大量占用带宽,
#1:23
我打算给ftp-data,1:22一样,很可能大量上传文件,所以rate不能给得太多,而当其他有剩时可以给大些,ceil设置大些
#1:24 是无所谓通道,就是一般不是我们平时工作上需要的通道了,给小点,防止这些人在妨碍有正常工作需要的人
#上行 uplink 320K,设置稍低于理论值
DEV="ppp0"
UPLINK=300
#
下行downlink 3200 k 大概一半左右,以便能够得到更多的并发连接
DOWNLINK=1500
echo "==================== Packetfilter and Traffic Control
流量控制 By 网络技术部 Ver. 1.0===================="
start_routing() {
echo -n "
队列设置开始start......"
#1.
增加一个根队列,没有进行分类的数据包都走这个1:24是缺省类:
tc qdisc add dev $DEV root handle 1: htb default 24
#1.1
增加一个根队下面主干类1: 速率为$UPLINK k
tc class add dev $DEV parent 1: classid 1:1 htb rate ${UPLINK}kbit ceil ${UPLINK}kbit prio 0
#1.1.1
在主干类1下建立第一叶子类,这是一个最高优先权的类.需要高优先和高速的包走这条通道,比如SYN,ACK,ICMP
tc class add dev $DEV parent 1:1 classid 1:11 htb rate $[$UPLINK]kbit ceil ${UPLINK}kbit prio 1
#1.1.2
在主类1下建立第二叶子类 ,这是一个次高优先权的类。比如我们重要的crm数据.
tc class add dev $DEV parent 1:1 classid 1:12 htb rate $[$UPLINK-150]kbit ceil ${UPLINK-50}kbit prio 2
#1.2
在根类下建立次干类 classid 1:2 。此次干类的下面全部优先权低于主干类,以防重要数据堵塞.
tc class add dev $DEV parent 1: classid 1:2 htb rate $[$UPLINK-150]kbit prio 3
#1.2.1
在次干类下建立第一叶子类,可以跑例如http,pop.
tc class add dev $DEV parent 1:2 classid 1:21 htb rate 100kbit ceil $[$UPLINK-150]kbit prio 4
#1.2.2
在次干类下建立第二叶子类。不要太高的速度,以防发大的附件大量占用带宽,例如smtp
tc class add dev $DEV parent 1:2 classid 1:22 htb rate 30kbit ceil $[$UPLINK-160]kbit prio 5
#1.2.3
在次干类下建立第三叶子类。不要太多的带宽,以防大量的数据堵塞网络,例如ftp-data,
tc class add dev $DEV parent 1:2 classid 1:23 htb rate 15kbit ceil $[$UPLINK-170]kbit prio 6
#1.2.4
在次干类下建立第四叶子类。无所谓的数据通道,无需要太多的带宽,以防无所谓的人在阻碍正务.
tc class add dev $DEV parent 1:2 classid 1:24 htb rate 5kbit ceil $[$UPLINK-250]kbit prio 7
#
在每个类下面再附加上另一个队列规定,随机公平队列(SFQ),不被某个连接不停占用带宽,以保证带宽的平均公平使用:
#SFQ(Stochastic Fairness Queueing,随机公平队列),SFQ的关键词是会话”(或称作”)
#主要针对一个TCP会话或者UDP流。流量被分成相当多数量的FIFO队列中,每个队列对应一个会话。
#数据按照简单轮转的方式发送, 每个会话都按顺序得到发送机会。这种方式非常公平,保证了每一
#个会话都不会没其它会话所淹没。SFQ之所以被称为随机,是因为它并不是真的为每一个会话创建
#一个队列,而是使用一个散列算法,把所有的会话映射到有限的几个队列中去。
#参数perturb是多少秒后重新配置一次散列算法。默认为10
tc qdisc add dev $DEV parent 1:11 handle 111: sfq perturb 5
tc qdisc add dev $DEV parent 1:12 handle 112: sfq perturb 5
tc qdisc add dev $DEV parent 1:21 handle 121: sfq perturb 10
tc qdisc add dev $DEV parent 1:22 handle 122: sfq perturb 10
tc qdisc add dev $DEV parent 1:23 handle 133: sfq perturb 10
tc qdisc add dev $DEV parent 1:24 handle 124: sfq perturb 10
echo "
队列设置成功.done."
echo -n "
设置包过滤 Setting up Filters......"
#
这里设置过滤器,handle iptablesmark的值,让被iptables mangle链做了mark的不同的值选择不同的通
#classid,prio 是过滤器的优先级别.
tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 1 fw classid 1:11
tc filter add dev $DEV parent 1:0 protocol ip prio 2 handle 2 fw classid 1:12
tc filter add dev $DEV parent 1:0 protocol ip prio 3 handle 3 fw classid 1:21
tc filter add dev $DEV parent 1:0 protocol ip prio 4 handle 4 fw classid 1:22
tc filter add dev $DEV parent 1:0 protocol ip prio 5 handle 5 fw classid 1:23
tc filter add dev $DEV parent 1:0 protocol ip prio 6 handle 6 fw classid 1:24
echo "
设置过滤器成功.done."
########## downlink ##########################################################################
#6.
下行的限制:
#
设置入队的规则,是因为把一些经常会造成下载大文件的端口进行控制,不让它们来得太快,导致堵塞.来得太快
#的就直接drop,就不会浪费和占用机器时间和力量去处理了.
#(1).
把下行速率控制在大概1000-1500k左右,因为这个速度已经足够用了,以便能够得到更多的并发下载连接
tc qdisc add dev $DEV handle ffff: ingress
tc filter add dev $DEV parent ffff: protocol ip prio 50 handle 8 fw police rate ${DOWNLINK}kbit burst 10k drop flowid :8
}
#(2).
如果内部网数据流不是很疯狂的话,就不用做下载的限制了,#符号屏蔽上面两行即可.
#(3).
如果要对任何进来数据的数据进行限速的话,可以用下面这句:
#tc filter add dev $DEV parent ffff: protocol ip prio 10 u32 match ip src 0.0.0.0/0 police rate ${DOWNLINK}kbit burst 10k drop flowid :1
###############################################################################################
#7.
开始给数据包打标记,往PREROUTING链中添加mangle规则:
start_mangle() {
echo -n "
开始给数据包打标记......start mangle mark......"
#(1)
把出去的不同类数据包(dport)mark上标记1--6.让它走不同的通道
#(2)把进来的数据包(sport)mark上标记8,让它受到下行的限制,以免速度太过快而影响全局.
#(3)
每条规则下根着return的意思是可以通过RETURN方法避免遍历所有的规则,加快了处理速度
##设置TOS的处理:
#iptables -t mangle -A PREROUTING -m tos --tos Minimize-Delay -j MARK --set-mark 1
#iptables -t mangle -A PREROUTING -m tos --tos Minimize-Delay -j RETURN
#iptables -t mangle -A PREROUTING -m tos --tos Minimize-Cost -j MARK --set-mark 4
#iptables -t mangle -A PREROUTING -m tos --tos Minimize-Cost -j RETURN
#iptables -t mangle -A PREROUTING -m tos --tos Maximize-Throughput -j MARK --set-mark 5
#iptables -t mangle -A PREROUTING -m tos --tos Maximize-Throughput -j RETURN
##
提高tcp初始连接(也就是带有SYN的数据包)的优先权是非常明智的:
iptables -t mangle -A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j RETURN
######icmp,
ping有良好的反应,放在第一类吧.
iptables -t mangle -A PREROUTING -p icmp -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p icmp -j RETURN
# small packets (probably just ACKs)
长度小于64的小包通常是需要快些的,一般是用来确认tcp的连接的,
#
让它跑快些的通道吧.也可以把下面两行屏蔽,因为再下面有更多更明细的端口分类.
#iptables -t mangle -A PREROUTING -p tcp -m length --length :64 -j MARK --set-mark 2
#iptables -t mangle -A PREROUTING -p tcp -m length --length :64 -j RETURN
#ftp
放第2,因为一般是小包, ftp-data放在第5,因为一般是大量数据的传送.
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport ftp -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport ftp -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport ftp-data -j MARK --set-mark 5
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport ftp-data -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp -j MARK --set-mark 8
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp-data -j MARK --set-mark 8
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp-data -j RETURN
##
提高ssh数据包的优先权:放在第1,要知道ssh是交互式的和重要的,不容待慢哦
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 22 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 22 -j RETURN
#
##smtp
邮件:放在第4,因为有时有人发送很大的邮件,为避免它堵塞,让它跑4道吧
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 25 -j MARK --set-mark 4
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 25 -j RETURN
#iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 25 -j MARK --set-mark 8
#iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 25 -j RETURN
## name-domain server
:放在第1,这样连接带有域名的连接才能快速找到对应的地址,提高速度的一法
iptables -t mangle -A PREROUTING -p udp -m udp --dport 53 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p udp -m udp --dport 53 -j RETURN
#
## http
:放在第3,是最常用的,最多人用的,
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 80 -j MARK --set-mark 3
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 80 -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 80 -j MARK --set-mark 8
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 80 -j RETURN
##pop
邮件:放在第3
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 110 -j MARK --set-mark 3
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 110 -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 110 -j MARK --set-mark 8
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 110 -j RETURN
## https
:放在第3
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 443 -j MARK --set-mark 3
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 443 -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 443 -j MARK --set-mark 8
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 443 -j RETURN
## Microsoft-SQL-Server
:放在第2,我这里认为较重要,一定要保证速度的和优先的.
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1433 -j MARK --set-mark 2
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1433 -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 1433 -j MARK --set-mark 8
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 1433 -j RETURN
## voip
, 提高,语音通道要保持高速,才不会断续.
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1720 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1720 -j RETURN
iptables -t mangle -A PREROUTING -p udp -m udp --dport 1720 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p udp -m udp --dport 1720 -j RETURN
## vpn ,
用作voip,也要走高速路,才不会断续.
iptables -t mangle -A PREROUTING -p udp -m udp --dport 7707 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p udp -m udp --dport 7707 -j RETURN
##
放在第1,因为我觉得它在我心中很重要,优先.
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 7070 -j MARK --set-mark 1
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 7070 -j RETURN
## WWW caching service
:放在第3
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 8080 -j MARK --set-mark 3
iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 8080 -j RETURN
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 8080 -j MARK --set-mark 8
iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 8080 -j RETURN
##
提高本地数据包的优先权:放在第1
iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 22 -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 22 -j RETURN
iptables -t mangle -A OUTPUT -p icmp -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -p icmp -j RETURN
#
本地small packets (probably just ACKs)
iptables -t mangle -A OUTPUT -p tcp -m length --length :64 -j MARK --set-mark 2
iptables -t mangle -A OUTPUT -p tcp -m length --length :64 -j RETURN
#(4).
PREROUTING中添加完mangle规则后,用这条规则结束PREROUTING表:
##也就是说前面没有打过标记的数据包将交给1:24处理。
##实际上是不必要的,因为1:24是缺省类,但仍然打上标记是为了保持整个设置的协调一致,而且这样
#还能看到规则的包计数。
iptables -t mangle -A PREROUTING -i $DEV -j MARK --set-mark 6
echo "
标记完毕! mangle mark done!"
}
#-----------------------------------------------------------------------------------------------------
#8.
取消mangle标记用的自定义函数
stop_mangle() {
echo -n "
停止数据标记 stop mangle table......"
( iptables -t mangle -F && echo "ok." ) || echo "error."
}
#9.
取消队列用的
stop_routing() {
echo -n "(
删除所有队列......)"
( tc qdisc del dev $DEV root && tc qdisc del dev $DEV ingress && echo "ok.
删除成功!" ) || echo "error."
}
#10.
显示状态
status() {
echo "1.show qdisc $DEV (
显示上行队列):----------------------------------------------"
tc -s qdisc show dev $DEV
echo "2.show class $DEV (
显示上行分类):----------------------------------------------"
tc class show dev $DEV
echo "3. tc -s class show dev $DEV (
显示上行队列和分类流量详细信息):------------------"
tc -s class show dev $DEV
echo "
说明:设置总队列上行带宽 $UPLINK k."
echo "1. classid 1:11 ssh
dns、和带有SYN标记的数据包。这是最高优先权的类包并最先类 "
echo "2. classid 1:12
重要数据,这是较高优先权的类。"
echo "3. classid 1:21 web,pop
服务 "
echo "4. classid 1:22 smtp
服务 "
echo "5. classid 1:23 ftp-data
服务 "
echo "6. classid 1:24
其他服务 "
}
#11.
显示帮助
usage() {
echo "
使用方法(usage): `basename $0` [start | stop | restart | status | mangle ]"
echo "
参数作用:"
echo "start
开始流量控制"
echo "stop
停止流量控制"
echo "restart
重启流量控制"
echo "status
显示队列流量"
echo "mangle
显示mark标记"
}
#----------------------------------------------------------------------------------------------
#12.
下面是脚本运行参数的选择的控制
#
kernel=`eval kernelversion`
case "$kernel" in
2.2)
echo " (!) Error: won't do anything with 2.2.x
不支持内核2.2.x"
exit 1
;;
2.4|2.6)
case "$1" in
start)
( start_routing && start_mangle && echo "
开始流量控制! TC started!" ) || echo "error."
exit 0
;;
stop)
( stop_routing && stop_mangle && echo "
停止流量控制! TC stopped!" ) || echo "error."
exit 0
;;
restart)
stop_routing
stop_mangle
start_routing
start_mangle
echo "
流量控制规则重新装载!"
;;
status)
status
;;
mangle)
echo "iptables -t mangle -L (
显示目前mangle表表标记详细):"
iptables -t mangle -nL
;;
*) usage
exit 1
;;
esac
;;
*)
echo " (!) Error: Unknown kernel version.
check it !"
exit 1
;;
esac
#
.结束语
#1. 如果要支持htb,请到相关网站下载有关补丁.
#
此脚本是参考http://lartc.org
http://luxik.cdi.cz/~devik/qos/htb/
http://www.docum.org/docum.org
#
和听取chinaunix.netC++版主JohnBull"Linux的高级路由和流量控制北京沙龙讲座录音
#及关于,经过不断调试得出的总结结果,在此感谢所有作出贡献的人.
#2. iptables,
http://www.iptables.org/ .iptables v1.2.7a tcRed hat linux 9.0下自带的版本.
#3.
此脚本已经在Red Hat Linux 9.0内核2.4.20,内网约70台频繁上网机器的环境下运行数月,事实证明良好.
#4.
如果ADSL带宽不同或有变,调节相关rate参数及ceil参数即可.
#5.
还有,如果结合IMQ,IMQ(Intermediate queueing device,中介队列设备)把上行和下行都进行分类控制
#就更理想了,但要支持IMQ,就要重新编译内核.关于补丁和更多的文档请参阅imq网站http://www.linuximq.net/
#6.
欢迎转载,但请保留原出处 powered by KindGeorge.
http://kindgeorge.at.3322.org
#7. 除了ADSL,还可以进行其他宽带的控制.
#8.
如果看谁老是在网内搞鬼,经常占满带宽,就把它列为黑名单,并派到"无所谓的数据通道",以防无所谓的人
#在阻碍正务: iptables -t mangle -I PREROUTING 1 -s 192.168.xxx.xxx -j MARK --set-mark 6
# iptables -t mangle -I PREROUTING 2 -s 192.168.xxx.xxx -j RETURN
#9.
使用方法: 整篇文档拷贝后,chmod +x tc2 ,
#
执行脚本: ./tc2 start (或其他参数start | stop | restart | status | mangle )即可
#如果想每次在ppp启动时就启动,则在/etc/ppp/ip-up 文件里面加上一句: /路径/tc2 restart
#10.
结合web界面的流量监测就更完美了,以下汇总
#用免费流量监控进行流量监测相关例子可以参阅:http://blog.chinaunix.net/article.php?articleId=15921&blogId=4543
echo "script done!"
exit 1
#end----------------------------------------------------------------------------------------

linux tc实现ip流量限制

安装系统:redhat linux as 4  2.6.9

转载文档1:

  摘要

  tc是个配置Linux内核流量控制的工具

  名字

    tc - 显示/维护流量控制配置

  摘要

  tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ]

  tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ]

  tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flowid flow-id

  tc [-s | -d ] qdisc show [ dev DEV ]

  tc [-s | -d ] class show dev DEV tc filter show dev DEV

  简介

  Tc用于Linux内核的流量控制。流量控制包括以下几种方式:

SHAPING(限制)

  当流量被限制,他的传输速率就被控制在某个值以下。限制值能够大大小于有效带宽,这样能够平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量。

SCHEDULING(调度) bitsCN.Com

  通过调度数据包的传输,能够在带宽范围内,按照优先级分配带宽。SCHEDULING(调度)也只适于向外的流量。

POLICING(策略)

SHAPING用于处理向外的流量,而POLICIING(策略)用于处理接收到的数据。

DROPPING(丢弃)

假如流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。

流量的处理由三种对象控制,他们是:qdisc(排队规则)、class(类别)和filter(过滤器)。

QDISC(排队规则)
  QDisc(排队规则)是queueing discipline的简写,他是理解流量控制(traffic control)的基础。无论何时,内核假如需要通过某个网络接口发送数据包,他都需要按照为这个接口配置的qdisc(排队规则)把数据包加入队列。然后,内核会尽可能多地从qdisc里面取出数据包,把他们交给网络适配器驱动模块。

最简单的QDisc是pfifo他不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。但是,他会保存网络接口一时无法处理的数据包。

CLASS(类)
  某些QDisc(排队规则)能够包含一些类别,不同的类别中能够包含更深入的QDisc(排队规则),通过这些细分的QDisc还能够为进入的队列的数据包排队。通过配置各种类别数据包的离队次序,QDisc能够为配置网络数据流量的优先级。

FILTER(过滤器)
  filter(过滤器)用于为数据包分类,决定他们按照何种QDisc进入队列。无论何时数据包进入一个划分子类的类别中,都需要进行分类。分类的方法能够有多种,使用fileter(过滤器)就是其中之一。使用filter(过滤器)分类时,内核会调用附属于这个类(class)的任何过滤器,直到返回一个判决。假如没有判决返回,就作进一步的处理,而处理方式和QDISC有关。   需要注意的是,filter(过滤器)是在QDisc内部,他们不能作为主体。

CLASSLESS QDisc(不可分类QDisc)
  无类别QDISC包括:

[p|b]fifo

 使用最简单的qdisc,纯粹的先进先出。只有一个参数:limit,用来配置队列的长度,pfifo是以数据包的个数为单位;bfifo是以字节数为单位。

   pfifo_fast

在编译内核时,假如打开了高级路由器(Advanced Router)编译选项,pfifo_fast就是系统的标准QDISC。他的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。而三个波段(band)的优先级也不相同,band 0的优先级最高,band 2的最低。假如band 0里面有数据包,系统就不会处理band 1里面的数据包,band 1和band 2之间也是相同。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。 [url]www.bitsCN.com[/url]

Red

red是Random Early Detection(随机早期探测)的简写。假如使用这种QDISC,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。他很适合高带宽应用。

Sfq

sfq是Stochastic Fairness Queueing的简写。他按照会话(session--对应于每个TCP连接或UDP流)为流量进行排序,然后循环发送每个会话的数据包。

Tbf

tbf是Token Bucket Filter的简写,适合于把流速降低到某个值。

不可分类QDisc的配置

假如没有可分类QDisc,不可分类QDisc只能附属于设备的根。他们的用法如下:

tc qdisc add dev DEV root QDISC QDISC-PARAMETERS

要删除一个不可分类QDisc,需要使用如下命令:

tc qdisc del dev DEV root

一个网络接口上假如没有配置QDisc,pfifo_fast就作为缺省的QDisc。

CLASSFUL QDISC(分类QDisc)

  可分类的QDisc包括:

CBQ

  CBQ是Class Based Queueing(基于类别排队)的缩写。他实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具备带宽优先级管理的能力。带宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。

[url]www.bitsCN.com[/url]

HTB

HTB是Hierarchy Token Bucket的缩写。通过在实践基础上的改进,他实现了一个丰富的连接共享类别体系。使用HTB能够很容易地确保每个类别的带宽,虽然他也允许特定的类能够突破带宽上限,占用别的类的带宽。HTB能够通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。

PRIO

PRIO QDisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用PRIO QDisc能够很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。为了方便管理,需要使用iptables或ipchains处理数据包的服务类型(Type Of Service,ToS)。

操作原理

类(Class)组成一个树,每个类都只有一个父类,而一个类能够有多个子类。某些QDisc(例如:CBQ和HTB)允许在运行时动态添加类,而其他的QDisc(例如:PRIO)不允许动态建立类。

允许动态添加类的QDisc能够有零个或多个子类,由他们为数据包排队。

此外,每个类都有一个叶子QDisc,默认情况下,这个叶子QDisc使用pfifo的方式排队,我们也能够使用其他类型的QDisc代替这个默认的QDisc。而且,这个叶子QDisc有能够分类,但是每个子类只能有一个叶子QDisc。 bitsCN_com

当一个数据包进入一个分类QDisc,他会被归入某个子类。我们能够使用以下三种方式为数据包归类,但是不是任何的QDisc都能够使用这三种方式。

tc过滤器(tc filter)

  假如过滤器附属于一个类,相关的指令就会对他们进行查询。过滤器能够匹配数据包头任何的域,也能够匹配由ipchains或iptables做的标记。

服务类型(Type of Service)

某些QDisc有基于服务类型(Type of Service,ToS)的内置的规则为数据包分类。

skb->priority

  用户空间的应用程式能够使用SO_PRIORITY选项在skb->priority域配置一个类的ID。
  树的每个节点都能够有自己的过滤器,但是高层的过滤器也能够直接用于其子类。
  假如数据包没有被成功归类,就会被排到这个类的叶子QDisc的队中。相关细节在各个QDisc的手册页中。

命名规则
  任何的QDisc、类和过滤器都有ID。ID能够手工配置,也能够有内核自动分配。

  ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。

QDISC

  一个QDisc会被分配一个主序列号,叫做句柄(handle),然后把从序列号作为类的命名空间。句柄采用象10:相同的表达方式。习惯上,需要为有子类的QDisc显式地分配一个句柄。

www_bitscn_com

类(CLASS)

在同一个QDisc里面的类分享这个QDisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只和父QDisc有关,和父类无关。类的命名习惯和QDisc的相同。

过滤器(FILTER)
  过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。详情请参考tc-filters手册页。

  单位

tc命令的任何参数都能够使用浮点数,可能会涉及到以下计数单位。

带宽或流速单位:

Kbps

千字节/秒
  mbps
  兆字节/秒
  kbit
  KBits/秒
  mbit
  MBits/秒
  bps或一个无单位数字
  字节数/秒
  数据的数量单位:

  kb或k
  千字节
  mb或m
  兆字节
  mbit
  兆bit
  kbit
  千bit
  b或一个无单位数字
  字节数
  时间的计量单位:
  s、sec或secs
  秒
  ms、msec或msecs
  分钟
  us、usec、usecs或一个无单位数字
  微秒
  
  TC命令
  tc能够使用以下命令对QDisc、类和过滤器进行操作:
  add

bitsCN_com

在一个节点里加入一个QDisc、类或过滤器。添加时,需要传递一个祖先作为参数,传递参数时既能够使用ID也能够直接传递设备的根。假如要建立一个QDisc或过滤器,能够使用句柄(handle)来命名;假如要建立一个类,能够使用类识别符(classid)来命名。

remove
  删除有某个句柄(handle)指定的QDisc,根QDisc(root)也能够删除。被删除QDisc上的任何子类连同附属于各个类的过滤器都会被自动删除。

Change

  以替代的方式修改某些条目。除了句柄(handle)和祖先不能修改以外,change命令的语法和add命令相同。换句话说,change命令不能一

 转载tc文档2-CBQ

CBQ 

名字

  CBQ - 基于类别排队(Class Based Queueing)  

摘要

tc qdisc ... dev dev (parent classid | root) [ handle major: ] cbq [ allot bytes] avpkt bytes bandwidth rate [ cell bytes] [ ewmalog ] [ mpu bytes ]

tc class ... dev dev parent major:[minor] [ classid major:minor] cbq allot bytes [ bandwidth rate ] [ rate rate] prio priority [ weight weight] [ minburst packets] [ maxburst packets ] [ ewma log] [ cell bytes] avpkt bytes[ mpu bytes] [ bounded isolated ] [ split handle& defmapdefmap ] [ estimator interval timeconstant]

简介

CBQ实现了一个丰富的共享连接的类别层次,既有固定(shaping)带宽的能力,也具有带宽优先级管理的能力。带宽固定是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件发生的频率和下层连接(数据链路层)的带宽。

 

带宽固定算法

当把一条10mbit/s的连接限制为1mbit/s时,这条连接将有90%的时间是空闲的。如果不是,它就会调低带宽以满足90%空闲时间的限制。

在操作过程中,空闲时间还要进行指数平滑移动平均(exponential weighted moving average,EWMA)计算,在这种计算方法中最近经过的数据包权重是前面数据包权重的指数。UNIX系统的平均负载就是使用这种算法计算的。

最后,由EWMA计算的值减去空闲时间,所得结果叫做avgidle。最好的情况是avgidle等于0,也就是数据包是严格地按照计算的时间间隔到达。

而过载连接的avgidle值是负数,如果这个负数太大,CBQ就会调低带宽,这就造成了过度限制(overlimit)的情况。

相反,一个空闲的连接会积累下一个很大的正数avgidle,这样可能造成经过一段空闲后,使带宽失控。为了防止出现这种情况的出现,可以使用maxidle参数限制avgidle的值。

如果处于过度限制(overlimit)的情况,CBQ会限制数据包通过的时间间隔严格按照计算的值。不过,由于时钟解析度的原因,这样可能不太合适。见minburst参数。

类别划分

在一个CBQ实例中,可以存在很多分类。每个类有可以包括其它的QDisc,默认情况下,是pfifo

在为数据包排队时,CBQ作为根,使用不同的方法确定那个类接收数据包。

如果没有一些不常见的配置选项,这个过程非常简单。我们在每个节点上查询一个指令,接着按照指令的指示让数据包进入某个类。如果这个类是一个叶子节点,我们就把数据包排到这里;如果这个类还有子节点,我们就重复以上过程。

我们在每个节点上重复以下操作,直到数据包被发送到其它节点,或者这个过程由于其它原因中止。

  • 查询附属于类上的过滤器,如果过滤器把数据包发到某个叶子节点,处理完毕;否则,开始下一个查询。
  • defmap中查询这个数据包的优先级,优先级倚赖于TCP头的TOS域。检查这个类是否还继续分类,如果是重新开始下一个查询。
  • defmap要求获得best effort优先级的指令,检查应答是否还存在分类,如果不是则重新开始下一个查询。
  • 如果上述操作都没有返回一个指令,就在这个节点把数据包排队

这个算法可以保证数据包最终会有归宿,即使你正在建立流量控制的配置。

连接共享算法

在向网络设备发送数据包时,CBQ首先要决定发出哪个类的数据包。它对所有的类采用加权轮转(Weighted Round Robin)的方式处理,使每个类的数据包都有机会被送出。WRR处理首先从优先级最高(数字最小的优先级)的类开始处理,直到处理完类中所有的数据包,再接着处理优先级次之的类。

每个类可以从其兄弟类借带宽。一个类可以使用bounded声明其带宽不可外借;也可以使用isolated声明不原意外借带宽。  

QDISC

一个CBQ QDisc类的根有如下参数:

parent major:minor | root

这个命令的参数决定这个CBQ实例所在的位置,或者是在一个网络接口的(root),或者位于一个现有的类里面。

handle major:

和其它的QDisc一样,CBQ QDisc也可以指定一个句柄。句柄只能包含主识别号(major number)和一个冒号。数字的选择是随意的,不过如果在这个QDisc里面会继续分类,这个数字非常有用。

allot bytes

这个参数用于分配的带宽,决定数据包传输的时间表。QDiscallot参数和类的allot参数略有不同。数字bytes是任意的。缺省是一个根据avpkt得到的数字。

avpkt bytes

数据包的平均大小,它用于计算最大空闲时间(maxidle),也用于确认allot参数的值是安全的。

bandwidth rate

为了决定空闲时间(idle time)CBQ必须知道底层物理接口的带宽,或者父QDisc的带宽。这是一个极为重要的参数,下面会继续讨论。

cell time

time的值决定进行数据包传输时间计算的时间间隔。使用缺省值是比较明智的。

mpu bytes

一个大小为0的数据包仍然会消耗时间来传输。用这个参数设置小于bytes个字节的数据包在进行传输时间的计算忽略不计。缺省值是0

ewma log

CBQ需要测量平均空闲时间时,它会使用加权指数移动平均算法来平滑测量的值,得到一个移动平均值。log决定平滑因子的大小。这个数值介于031之间,数值越小敏感度越大。默认值是5

一个CBQ QDisc只需要知道底层连接的大小。实际的带宽限制由其子类完成。

分类

有很多参数可以用于分类的配置操作:

parent major:minor

确定父QDisc的位置,把这个类加入到树状结构中。如果它是直接附属于一个QDisc,而且这个QDisc没有其它的类,minor可以被忽略。这个参数是必须的。

classid major:minor

QDisc一样,类也可以命名。主识别号(major number)必须等于其父QDisc的主识别号。这个参数是可选的,只有它还需要再细分才需要。

weight weight

在从队列中取出数据包通过网络接口向外发送时,CBQ会采用轮转的方式轮流从队列中取出属于不同分类的数据包。weight设置每个类的权重。权重越高,在每个循环CBQ取出的数据包也就越多。一个类中所有的权重都会被换算成与rate参数设定值的百分比。

allot bytes

这个参数设置每个循环可以有多少个字节出队。这个值最小为avpkt2/3。这个参数是必须的。

prio priority

设置类的优先级,在轮转过程中,priority数字较小(优先级高)的类的数据包优先出队。这个参数也是必须的。

avpkt bytes

参见QDisc中的相关介绍。

rate rate

设置这个类可以达到的最大速率,以及所有子类速率总和可以达到的值。这个参数是必需的。

bandwidth rate

这个参数不同于建立CBQ时的bandwidth参数。只有在决定maxidleofftime时才有用,在设置maxburst或者minburst时,CBQ会使用maxidleofftime进行计算。如果需要设置最大突发(006Daxburst)或者最小突发(miniburst),这个参数是必需的。

maxburst

这个参数设置的数字用于计算maxidle,以便avgidle的值等于maxidle时,在avgidle达到0之前,允许设定的数据包突发性地通过。这个数字越大,对于突发流量的适应性越好。你不能直接设置maxidle,只能通过这个参数来设置。

minburst

上面讲过,在过度限制(overlimit)情况下,CBQ需要调低带宽。为了避免这种情况的出现,比较理想的解决方案是精确地空闲某个时间,然后放行一个数据包。然而,对于UNIX内核来说,很难对时间间隔小于10ms的事件进行调度,因此只好把等待时间放长,接着突发性地放行多个数据包。

上面所说的等待时间叫做offtimeminburst的值越高,在一个较长时间内进行的带宽限制越准确,但是也会导致更大的突发流量。这个参数是可选的。

minidle

如果avgidle小于0,需要等待avgidle增加到一个足够大的值才能发送一个数据包。为了避免在一个长期处于关闭状态下的连接出现突发流量,如果avgidle太低就会被复位为minidle参数设置的数值。

minidle的单位是负微秒,10表示avgidle不能低于-10微秒。这个参数是可选的。

bounded

表示这个类的带宽概不外借。

isolated

表示这个类的带宽不原意外借。

split major:minor & defmap bitmap[/bitmap]

如果附属于这个类的过滤器不能判断数据包所属类别,CBQ也可以根据数据包的优先级为它们分类。优先级共有8个,范围是07

defmap设置这个类接受具备哪些优先级的数据包,接受的优先级使用bitmap来计算,CBQbitmap和数据包的优先级域进行and计算。最低有效位(Least Significant Bit)对应优先级0split告诉CBQ需要做出决定的类,参数应该是其父类。

例如:tc class add ... classid 10:1 cbq .. split 10:0 defmap c0,这条命令告诉类10:0把优先级为67的数据包都送到子类10:1

然后最好使用tc class add ... classid 10:2 cbq ... split 10:0 defmap 3f命令决定其它优先级数据包的流向,把优先级为012345的数据包都送给10:2

C0的二进制是110000003F的二进制是001111111,因此这两个defmap可以匹配数据包优先级域的所有位。C0匹配67,对应的是interactivecontrol位;而3F匹配余下的位。

estimator interval timeconstant

CBQ能够计量每个类使用了多少带宽,tc过滤器能够把数据包分类。CBQ使用一种简单的估算方式计算每interval微秒通过多少流量,判断自己使用的带宽。另外,还需要进行指数平滑移动平均的计算,时间常数由timeconstant设置。它决定对短期突发流量平均值的敏感程度,这个值越高敏感度越低。

BUGS

底层链路的带宽可能是无法预知的。例如,PPoE或者PPTP连接实际上是一个逻辑的通道,而不是一个物理设备。CBQ对于主要的带宽配置错误有很大的弹性,代价可能就是带宽固定(shaping)精度降低。

默认情况下,内核依靠粗糙的计时信息进行带宽固定。在一个较长的时间段内,可以维持很好的精度,但是在以秒为单位进行计量的时间段内,其结果就不准确了。

参考tc-cbq-details(8)(这个文档至今尚未完成)改进这个问题。

 

我经过测试后,以下代码完全可以限制下载速度,如下:

由于tc对发出包限制,我这里是 LAN:eth0 INT:eth1,限制网内下载速度

# tc qdisc add dev eth0 root handle 10:0 cbq bandwidth 5Mbit avpkt 1000

创建队列规则,添加设备eth0root表示这是根(root)规定,其句柄 handle)设定为 10:0' 其类型为 CBQ。公司带宽为 5 M,平均包大小为 1000 字节。

下面生成根类(root class):

# tc class add dev eth0 parent 10:0 classid 10:1 cbq bandwidth 5Mbit rate 5Mbit allot 1500 weight 1M prio 8 maxburst 20 avpkt 1000

各参数见前文档,allot 1500 我的网卡MTU

下面生成支类

# tc class add dev eth0 parent 10:1 classid 10:10 cbq bandwidth 5Mbit rate 1Mbit allot 1500 weight 5Kbit prio 5 maxburst 20 avpkt 1000 bounded

# tc class add dev eth0 parent 10:1 classid 10:20 cbq bandwidth 5Mbit rate 1Mbit allot 1500 weight 100Kbit prio 5 maxburst 20 avpkt 1000 bounded

# tc class add dev eth0 parent 10:1 classid 10:30 cbq bandwidth 5Mbit rate 3Mbit allot 1500 weight 900Kbit prio 5 maxburst 20 avpkt 1000 bounded

我们已经向内核通知了我们的类,我们还需要告诉内核如何管理队列

# tc qdisc add dev eth0 parent 10:10 sfq quantum 1500b perturb 15

# tc qdisc add dev eth0 parent 10:20 sfq quantum 1500b perturb 15

# tc qdisc add dev eth0 parent 10:30 sfq quantum 1500b perturb 15

perturb:表示时间15sec

告诉内核网络包和类的映射关系

# tc filter add dev eth0 parent 10:0 protocol ip prio 10 u32 match ip dst 192.168.1.226 flowid 10:10

# tc filter add dev eth0 parent 10:0 protocol ip prio 10 u32 match ip dst 192.168.1.227 flowid 10:20

# tc filter add dev eth0 parent 10:0 protocol ip prio 10 u32 match ip dst 192.168.1.228 flowid 10:30

 

上传速度限制类似与下载

不同处是 下载使用内网接口,上传使用外网接口,上传对源地址使用src参数。

linux tc 限速脚本

#!/bin/bash

#configure for $DEV

DEV=eth0

#set Total BW

BW_TOTAL=10mbit

#Set The IP POOL,only support C ip class

IP_POOL_CUS=()

IP_POOL_CUS[0]=192.168.1.2-10\|100kbit

#IP_POOL_CUS[1]=192.168.2.1-253\|200kbit

 

stop_tc(){

    tc qdisc del dev $DEV root > /dev/null 2>&1

}

 

add_rule(){

    if [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ];then

       echo "add_rule() run Error"

       exit

    fi

    ID=$1

    SPEED=$2

    IP=$3

    tc class add dev $DEV parent 1:1 classid 1:$ID htb rate $SPEED ceil $SPEED

    tc qdisc add dev $DEV parent 1:$ID handle ${ID}: sfq perturb 10

    tc filter add dev $DEV protocol ip parent 1: prio 8 u32 match ip dst $IP flowid 1:$ID

}

 

start_tc(){

    tc qdisc del dev $DEV root > /dev/null 2>&1

    tc qdisc add dev $DEV root handle 1: htb default 40

    tc class add dev $DEV parent 1: classid 1:1 htb rate $BW_TOTAL

    tc class add dev $DEV parent 1:1 classid 1:10 htb rate 1mbit ceil 1mbit

    tc class add dev $DEV parent 1:1 classid 1:40 htb rate 5mbit ceil 5mbit

    tc qdisc add dev $DEV parent 1:10 handle 10: sfq perturb 10

    tc qdisc add dev $DEV parent 1:40 handle 40: sfq perturb 10

    for ((i=0;i<${#IP_POOL_CUS[@]};i++));do

       IP=$(echo ${IP_POOL_CUS[$i]}|awk -F"|" '{print $1}')

       IP1=$(echo $IP|awk -F"." '{print $1"."$2"."$3}')

       IP2=$(echo $IP|awk -F"." '{print substr($NF,0,index($NF,"-")-1)}')

       IP3=$(echo $IP|awk -F"." '{print substr($NF,index($NF,"-")+1)}')

       SPEED=$(echo ${IP_POOL_CUS[$i]}|awk -F"|" '{print $2}')

       #echo IP:$IP,IP1:$IP1,IP2:$IP2,IP3:$IP3

       for ((j=IP2;j<=IP3;j++));do

           ID_BASE=$[i+1]

           ID=$[ID_BASE * 1000 + j]

           #echo j:$j,ID:$ID

           add_rule $ID $SPEED ${IP1}.$j

       done

       #add_rule $ID $SPEED $IP

    done

    #tc filter add dev $DEV protocol ip parent 1: prio 10 u32 match ip dst 192.168.1.0/24 flowid 1:10

    #icmp

    tc filter add dev $DEV protocol ip parent 1: prio 10 u32 match ip protocol 1 0xff

}

 

status_tc(){

    tc -s qdisc show dev $DEV

    echo ""

    tc class show dev $DEV

    echo ""

    tc -s class show dev $DEV

    echo ""

    tc filter ls dev $DEV parent ffff:

}

 

case $1 in

  restart | start)

    start_tc

    echo -e "bwctl start [ \033[1;32m"Success!"\033[0m ]"

    ;;

  stop)

    stop_tc

    echo "bwctl stop [ \033[1;32m"Success!"\033[0m ]"

    ;;

  status)

    status_tc

    ;;

  *)

   echo  Usage:' bwctl.sh start | stop | restart |status'

esac

Linux TC设置

同一个机器两个网卡使用SNAT进行转发,设置如下:

一、        下载设置

1    规则  eth0 为内网卡,可以限制下载流量)

tc qdisc add dev eth0 root handle 2:0 htb default 30

          tc class add dev eth0 parent 2:0 classid 2:1 htb rate 4Mbit burst 15k

          tc class add dev eth0 parent 2:1 classid 2:10 htb rate 4Mbit burst 15k 最大流量4 M

          tc class add dev eth0 parent 2:1 classid 2:20 htb rate 2000kbit ceil 2Mbit burst 15k 最大流量 2M

          tc class add dev eth0 parent 2:1 classid 2:30 htb rate 1000kbit ceil 1000kbit burst 15k 最大流量 1M

tc qdisc add dev eth0 parent 2:10 handle 10: sfq perturb 10

          tc qdisc add dev eth0 parent 2:20 handle 20: sfq perturb 10

          tc qdisc add dev eth0 parent 2:30 handle 30: sfq perturb 10

          U32_1="tc filter add dev eth0 protocol ip parent 2:0 prio 1 u32"

          $U32_1 match ip src 192.168.9.0/24 flowid 2:10  192.168.9.0/24 总公司 ERP 服务器所在网络)

使访问 ERP 服务器可用最大带宽 4M ,优先级为 1

U32_2="tc filter add dev eth0 protocol ip parent 2:0 prio 2 u32"

          $U32_2 match ip dst 192.168.1.172/32 flowid 2:20

          $U32_2 match ip dst 192.168.1.82/32 flowid 2:20

          $U32_2 match ip dst 192.168.1.200/32 flowid 2:20

                              以上 3  IP 为总经办人员,限制他们下载流量为 2M ,优先级为 2

          tc filter add dev eth0 protocol ip parent 2:0 prio 3 u32 match ip dst 192.168.1.0/24 flowid 2:30 (因为有默认,此行可以省略,为了规则更清晰,还是设置为好)

                              以上只是设置默认情况下下载带宽只有 1000K ,即将近 1M 优先级为 3

2    注意事项:

优先级不要相同

二、        上传设置

1    规则 (eth1 为连接专线的网卡,可限制上传带宽 )

        iptables -F -t mangle

         iptables -X -t mangle

          iptables -Z -t mangle

         iptables -A PREROUTING -t mangle -i eth0 -s 192.168.1.200/32 -j MARK --set-mark 1

         iptables -A PREROUTING -t mangle -i eth0 -s 192.168.1.172/32 -j MARK --set-mark 1

         iptables -A PREROUTING -t mangle -i eth0 -s 192.168.1.82/32 -j MARK --set-mark 1

#iptables -A PREROUTING -t mangle -i eth0 -s 192.168.1.0/24 -j MARK --set-mark 2 ( 可以不用此条 )

          tc qdisc add dev eth1 root handle 1:0 htb default 30

          tc class add dev eth1 parent 1:0 classid 1:1 htb rate 4Mbit burst 15k

          tc class add dev eth1 parent 1:1 classid 1:10 htb rate 4Mbit burst 15k 最大上传流量为 4M

          tc class add dev eth1 parent 1:1 classid 1:20 htb rate 1000kbit ceil 2Mbit burst 15k 最大流量为 2M

          tc class add dev eth1 parent 1:1 classid 1:30 htb rate 400kbit ceil 400kbit burst 15k 最大流量为 400K

          tc qdisc add dev eth1 parent 1:10 handle 10: sfq perturb 10

          tc qdisc add dev eth1 parent 1:20 handle 20: sfq perturb 10

          tc qdisc add dev eth1 parent 1:30 handle 30: sfq perturb 10

          U32="tc filter add dev eth1 protocol ip parent 1:0 prio 1 u32"

          tc filter add dev eth1 protocol ip parent 1:0 prio 1 u32 match ip dst 192.168.9.0/24 flowid 1:10

以上规则使用达到 ERP 服务器的流量不受限制,也即最大可为 4M

          tc filter add dev eth1 parent 1:0 protocol ip prio 3 handle 1 fw classid   1:20

                             以上规则使总经办 3  IP 地址的上传流量为 2M

          #tc filter add dev eth1 parent 1:0 protocol ip prio 4 handle 2 fw classid   1:30 (因为默认下使用此规则,所以可以省略)

 默认下不符合以上两规则的全部使用此规则,上传带宽最大为 400K (不要说我苛刻哟)

2    注意事项

1)          因为内部 IP 地址在经过外网卡时会进行 NAT ,所以不能用源地址进行 U32 匹配,只能是 FW 规则进行流量标识

2)          优先级一定不能相同,否则 fw 规则将失效

3)          以上规则可以放到一个文件内运行

linux tc 对本机网卡限速

今天由于项目要测试在网络环境不好的情况下,会不会对平台有所影响,要求测试限制服务器流量,我想到了TC,我对TC不是很了解, google了一下,看到了不少文章都是做路由用的,对我来说不是很实用,因为我是对单机测试。先看看TC命令在说,没想到报错,错误如下:
shell$> tc -s qdisc
RTNETLINK answers: Invalid argument
看到这个错误很迷茫,命令是支持的啊,在网上查询了很久,发现是内核不支持,不支持QOS,不支持正常,因为我的内部测试服务器用XEN,虚拟的系统,所以我重新编译DomU内核,添加 QOS,CBQ等

环境:
xen domU : ubuntu-server 8.0.4  IP:192.168.6.101
kernel : linux-2.6.18-xen
xen dom0 : ubuntu-server 8.0.4  IP:192.168.6.209
操作:

DomU $> tc -s qdisc
RTNETLINK answers: Invalid argument

进入父系统:
Dom0 $> cd xen-3.4.2
编译xen DomU 内核
Dom0 $> make linux-2.6-xenU-config CONFIGMODE=menuconfig
选择 Networking  —>
          Networking options  —>
                QoS and/or fair queueing  —>
                      [*] QoS and/or fair queueing
把下面的最好都选上吧 * 是打入内核,M 是以模块方式。我全选择 *
选择好,保存退出

Dom0 $> make linux-2.6-xenU-build        

Dom0 $> cd xen-3.4.2/dist/install/boot

Dom0 $> scp vmlinuz-2.6.18.8-xenU [email protected]:~

好,然后进入 DomU

DomU $> ls
vmlinuz-2.6.18.8-xenU
覆盖 以前的vmlinuz-2.6.18.8-xenU
DomU $> mv vmlinuz-2.6.18.8-xenU /boot/
DomU $> reboot

重启后,在进入系统,看是否还报错:

DomU $> tc -s qdisc
好没有报错“下来我们对 服务器 1935 端口进行限速,限制为 上传下载都为50Kbit

CBQ 算法:

DomU $> tc qdisc del dev eth0 root
DomU $> tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8
DomU $> tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit rate 50Kbit weight 50Kbit prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded
DomU $> tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit rate 50Kbit weight 50Kbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000
DomU $> tc qdisc add dev eth0 parent 1:4 handle 40: sfq
DomU $> tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip sport 1935 0xffff flowid 1:4

好了 连接 1935 试试吧`

Linux下利用TC工具控制网络流量

众所周知,在互联网诞生之初都是各个高校和科研机构相互通讯,并没有网络流量控制方面的考虑和设计,IP协议的原则是尽可能好地为所有数据流服务,不同的数据流之间是平等的。然而多年的实践表明,这种原则并不是最理想的,有些数据流应该得到特别的照顾, 比如,远程登录的交互数据流应该比数据下载有更高的优先级。

  针对不同的数据流采取不同的策略,这种可能性是存在的。并且,随着研究的发展和深入, 人们已经提出了各种不同的管理模式。IETF已经发布了几个标准, 如综合服务(Integrated Services)、区分服务(Diferentiated Services)等。其实,Linux内核从2 2开始,就已经实现了相关的流量控制功能。本文将介绍Linux中有关流量控制的相关概念, 用于流量控制的工具TC的使用方法,并给出几个有代表性实例。

  一、相关概念

  由此可以看出, 报文分组从输入网卡(入口)接收进来,经过路由的查找, 以确定是发给本机的,还是需要转发的。如果是发给本机的,就直接向上递交给上层的协议,比如TCP,如果是转发的, 则会从输出网卡(出口)发出。网络流量的控制通常发生在输出网卡处。虽然在路由器的入口处也可以进行流量控制,Linux也具有相关的功能, 但一般说来, 由于我们无法控制自己网络之外的设备, 入口处的流量控制相对较难。本文将集中介绍出口处的流量控制。流量控制的一个基本概念是队列(Qdisc),每个网卡都与一个队列(Qdisc)相联系, 每当内核需要将报文分组从网卡发送出去, 都会首先将该报文分组添加到该网卡所配置的队列中, 由该队列决定报文分组的发送顺序。因此可以说,所有的流量控制都发生在队列中,详细流程图见图1。

图1报文在Linux内部流程图

  有些队列的功能是非常简单的, 它们对报文分组实行先来先走的策略。有些队列则功能复杂,会将不同的报文分组进行排队、分类,并根据不同的原则, 以不同的顺序发送队列中的报文分组。为实现这样的功能,这些复杂的队列需要使用不同的过滤器(Filter)来把报文分组分成不同的类别(Class)。这里把这些复杂的队列称为可分类(ClassfuI)的队列。通常, 要实现功能强大的流量控制, 可分类的队列是必不可少的。因此,类别(class)和过滤器(Filter)也是流量控制的另外两个重要的基本概念。图2所示的是一个可分类队列的例子。

图2多类别队列

  由图2可以看出,类别(CIass)和过滤器(Filter)都是队列的内部结构, 并且可分类的队列可以包含多个类别,同时,一个类别又可以进一步包含有子队列,或者子类别。所有进入该类别的报文分组可以依据不同的原则放入不同的子队列或子类别中,以此类推。而过滤器(Filter)是队列用来对数据报文进行分类的工具, 它决定一个数据报文将被分配到哪个类别中。

二、使用TC

  在Linux中,流量控制都是通过TC这个工具来完成的。通常, 要对网卡进行流量控制的配置,需要进行如下的步骤:

  ◆ 为网卡配置一个队列;
  ◆ 在该队列上建立分类;
  ◆ 根据需要建立子队列和子分类;
  ◆ 为每个分类建立过滤器。

  在Linux中,可以配置很多类型的队列,比如CBQ、HTB等,其中CBQ 比较复杂,不容易理解。HTB(HierarchicaIToken Bucket)是一个可分类的队列, 与其他复杂的队列类型相比,HTB具有功能强大、配置简单及容易上手等优点。在TC 中, 使用"major:minor"这样的句柄来标识队列和类别,其中major和minor都是数字。

  对于队列来说,minor总是为0,即"major:0"这样的形式,也可以简写为“major: 比如,队列1:0可以简写为1:。需要注意的是,major在一个网卡的所有队列中必须是惟一的。对于类别来说,其major必须和它的父类别或父队列的major相同,而minor在一个队列内部则必须是惟一的(因为类别肯定是包含在某个队列中的)。举个例子,如果队列2:包含两个类别,则这两个类别的句柄必须是2:x这样的形式,并且它们的x不能相同,比如2:1和2:2。

  下面,将以HTB队列为主,结合需求来讲述TC的使用。假设eth0出口有100mbit/s的带宽, 分配给WWW 、E-mail和Telnet三种数据流量, 其中分配给WWW的带宽为40Mbit/s,分配给Email的带宽为40Mbit/s, 分配给Telnet的带宽为20Mbit/S。如图3所示。

  需要注意的是, 在TC 中使用下列的缩写表示相应的带宽:

  ◆ Kbps kiIobytes per second, 即"千字节每秒 ;
  ◆ Mbps megabytes per second, 即"兆字节每秒 ,
  ◆ Kbit kilobits per second,即"千比特每秒 ;
  ◆ Mbit megabits per second, 即"兆比特每秒 。

  三、创建HTB队列

  有关队列的TC命令的一般形式为:

  #tc qdisc [add|change|replace|link] dev DEV [parent qdisk-id|root][handle qdisc-id] qdisc[qdisc specific parameters]

  首先,需要为网卡eth0配置一个HTB队列,使用下列命令:

  #tc qdisc add dev eth0 root handle 1:htb default 11

  这里,命令中的"add 表示要添加,"dev eth0 表示要操作的网卡为eth0。"root 表示为网卡eth0添加的是一个根队列。"handle 1: 表示队列的句柄为1:。"htb 表示要添加的队列为HTB队列。命令最后的"default 11 是htb特有的队列参数,意思是所有未分类的流量都将分配给类别1:11。

  四、为根队列创建相应的类别

  有关类别的TC 命令的一般形式为:

  #tc class [add|change|replace] dev DEV parent qdisc-id [classid class-id] qdisc [qdisc specific parameters]

  可以利用下面这三个命令为根队列1创建三个类别,分别是1:1 1、1:12和1:13,它们分别占用40、40和20mb[t的带宽。

  #tc class add dev eth0 parent 1: classid 1:1 htb rate 40mbit ceil 40mbit
  #tc class add dev eth0 parent 1: classid 1:12 htb rate 40mbit ceil 40mbit
  #tc class add dev eth0 parent 1: cllassid 1:13 htb rate 20mbit ceil 20mbit

  命令中,"parent 1:"表示类别的父亲为根队列1:。"classid1:11"表示创建一个标识为1:11的类别,"rate 40mbit"表示系统

  将为该类别确保带宽40mbit,"ceil 40mbit",表示该类别的最高可占用带宽为40mbit。

五、为各个类别设置过滤器

  有关过滤器的TC 命令的一般形式为:

  #tc filter [add|change|replace] dev DEV [parent qdisc-id|root] protocol protocol prio priority filtertype [filtertype specific parameters] flowid flow-id

  由于需要将WWW、E-mail、Telnet三种流量分配到三个类别,即上述1:11、1:12和1:13,因此,需要创建三个过滤器,如下面的三个命令:

  #tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 80 0xffff flowid 1:11
  #tc filter add dev eth0 prtocol ip parent 1:0 prio 1 u32 match ip dport 25 0xffff flowid 1:12
  #tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dport 23 oxffff flowid 1:13

  这里,"protocol ip"表示该过滤器应该检查报文分组的协议字段。"pr[o 1"表示它们对报文处理的优先级是相同的,对于不同优先级的过滤器, 系统将按照从小到大的优先级。

  顺序来执行过滤器, 对于相同的优先级,系统将按照命令的先后顺序执行。这几个过滤器还用到了u32选择器(命令中u32后面的部分)来匹配不同的数据流。以第一个命令为例,判断的是dport字段,如果该字段与Oxffff进行与操作的结果是8O,则"flowid 1:11" 表示将把该数据流分配给类别1:11。更加详细的有关TC的用法可以参考TC 的手册页。

  六、复杂的实例

  在上面的例子中, 三种数据流(www、Email、Telnet)之间是互相排斥的。当某个数据流的流量没有达到配额时,其剩余的带宽并不能被其他两个数据流所借用。在这里将涉及如何使不同的数据流可以共享一定的带宽。

  首先需要用到HTB的一个特性, 即对于一个类别中的所有子类别,它们将共享该父类别所拥有的带宽,同时,又可以使得各个子类别申请的各自带宽得到保证。这也就是说,当某个数据流的实际使用带宽没有达到其配额时, 其剩余的带宽可以借给其他的数据流。而在借出的过程中,如果本数据流的数据量增大,则借出的带宽部分将收回, 以保证本数据流的带宽配额。

  下面考虑这样的需求, 同样是三个数据流WWW、E-mail和Telnet, 其中的Telnet独立分配20Mbit/s的带宽。另一方面,VWVW 和SMTP各自分配40Mbit/s。同时,它们又是共享的关系, 即它们可以互相借用带宽。如图3所示。

  需要的TC命令如下:

  #tc qdisc add dev eth0 root handle 1: htb default 21
  #tc class add dev eth0 partent 1: classid 1:1 htb rate 20mbit ceil 20mbit
  #tc class add dev eth0 parent 1: classid 1:2 htb rate 80mbit ceil 80mbit
  #tc class add dev eth0 parent 1:2 classid 1:21 htb rate 40mbit ceil 20mbit
  #tc class add dev eth0 parent 1:2 classid 1:22 htb rate 40mbit ceil 80mbit
  #tc filter add dev eth0 protocol parent 10 prio 1 u32 match ip dport 80 0xffff flowid 1:21
  #tc filter add dev eth0 protocol parent 1:0 prio 1 u32 match ip dport 25 0xffff flowid 1:22
  #tc filter add dev eth0 protocol parent 1:0 prio 1 u32 match ip dport 23 0xffff flowid 1:1

  这里为根队列1创建两个根类别,即1:1和1:2,其中1:1对应Telnet数据流,1:2对应80Mbit的数据流。然后,在1:2中,创建两个子类别1:21和1:22,分别对应WWW和E-mail数据流。由于类别1:21和1:22是类别1:2的子类别,因此他们可以共享分配的80Mbit带宽。同时,又确保当需要时,自己的带宽至少有40Mbit。

  从这个例子可以看出,利用HTB中类别和子类别的包含关系,可以构建更加复杂的多层次类别树,从而实现的更加灵活的带宽共享和独占模式,达到企业级的带宽管理目的。

linux下TC+HTB流量控制

TC规则涉及到 队列(QUEUE) 分类器(CLASS) 过滤器(FILTER),filter划分的标志位可用U32或iptables的set-mark来实现 ) 一般是"控发"不控收 linux下有两块网卡,一个eth1是外网,另一块eth0是内网.在eth0上做HTB。(注 意:filter划分标志位可用u32打标功能或iptables的set-mark功能,如果用iptables来打标记的话,下行速LV在eth0处 控制,但打标应在进入eth0之前进行,所以,“-i eth1";例子:

  主要命令就下面三句:创建一个HTB的根

  1.tc qdisc add dev eth0 root handle 1: htb default 20

创建一个HTB的类,流量的限制就是在这里限制的,并设置突发.

  2.tc class add dev eth0 parent 1: classid 1:1 htb rate 200kbit(速率) ceil 200kbit burst 20k(突发流量)

创建一个过滤规则把要限制流量的数据过滤出来,并发给上面的类来限制速度

3.tc filter add dev eth0 parent 1: prio 1(优先级) protocol ip u32 match ip sport 80 0xfff flowid 1:1

  说明:让交互数据包保持较低的延迟时间,并最先取得空闲带宽,比如:

  ssh telnet dns quake3 irc ftp控制 smtp命令和带有SYN标记的数据包,都应属于这一类。为了保证上行数据流不会伤害下行流,还要把ACK数据包排在队列前面,因为下行数据的ACK必须同上行流进行竟争。

  TC+IPTABLES+HTB+SFQ

  1 tcp/ip 协议规定,每个封包,都需要有ACKNOWLEDGE讯息的回传,也就是说,传输的资料需要有一个收到资料的讯息回复,才能决定后面的传输速度,并决定是 否重新传输遗失的资料,上行的带宽一部分就是用来传输这些ACK资料的.上行带宽点用大的时候,就会影响ACK资料的传送速度,并进而影响到下载速度,

  2 试验证明,当上传满载时,下载速度变为原来速度的40%,甚至更低,,因为上载文件(包括ftp上传,发邮件SMTP),如果较大,一个的通讯量令带宽超 向包和,那么所有的数据包按照先进先出的原则进行排队和等待,这就可以解释为什么网内其中有人用ftp上载文件或发送大邮件的时候,整个网速变得很慢的原 因.

  解决速度之道:

  1 为了解决这些速度问题,对经过线路的数据进行了有规则的分流.把本来在宽带上的瓶颈转移到我们的LINUX路由器上,可以把带宽控制的比我们购买的带宽小一点. 这样,我们就可以方便的用tc技术对经过的数据进行分流与控制.

  我们的想像就像马路上的车道一样,有高速道,还有小车道,大车道,需要高速的syn ack icmp ssh等走高速道,需要大量传输的ftp-data,smtp等走大车道,不能让它堵塞整条马路,各行其道.

  linux下的TC(traffic control)就有这样的作用,只要控制得当,一定会有明显的效果.tc 和iptables结合是最好的简单运用的结合方法.

  我 们设置过滤器以便用iptables对数据包进行分类,因为iptables更灵活,而且还可以为每个规则设置计数器,iptables用mangle链 来mark数据包,告诉了内核,数据包会有一个特定的FWMARK标记值(handle x fw) 表明它应该送给那个类(classid x:x),而prio是优先值,表明那些重要数据应该优先通过那个通道,首先选择队列(选择htb),

  一般系统默认的是fifo的先进先出队列,就是说包是按照先来先处理的原则,如果有一个大的数据包在前面,那么后面的包只能等前面的发完后才能接着发了,这样就算后面既使是一个小小的ack包,也要等待了,这样上传就影响了下载,就算你有很大的下载带宽也无能为力.

  HTB(Hierarchical token bucket,分层的令牌桶),就像CBQ一样工作,但是并不靠计算闲置时间来整形,它是一个分类的令牌桶过滤器.,它只有很少的参数.

  结构简图:             1:

  ~~~~~~~~~~~~~~~~`~~~~~

  ~~~~~~~_________1:1~~~~~~~~~1:2________

  |~~~|~~~~|~~~~|~~~~~|~~~~~~~~|~~~~~~~~|~~~~~~~|

  1:11~~~1:12~~~~~~~~~~~~1:21~~~1:22~~~1:23~~1:24

  优先顺序: 1:11 1:12 1:21 1:22 1:23 1:24

  根据上面的例子,开始脚本:

  关于参数的说明:

  rate:是一个类保证得到的带宽值,如果有不只一个类,请保证所有子类总和是小于或等于父类,

  ceil: ceil是一个类最大能得到带宽值.

  prio: 是优先权的设置,数值越大,优先权越小,如果是分配剩余带宽,就是数值小的会最优先取得剩余的空闲的带宽权.

  一般大数据的话,控制在50%-80%左右吧,而ceil最大建议不超过85%,以免某一个会话占用过多的带宽.

  rate可按各类所需要分配:

  1:11是很小而且最重要的数据包通道,当然要多分点,甚至必要时先全部占用,不过一般不会的,所以给全速.

  1:12是很重要的数据道,给多点,最少给一半,但需要时可以再多一点

  rate规划 1:2=1:21 +1:22 +1:23 +1:24 一般总在50%-80%左右.

  1:21 http,pop是最常用的啦,为了太多人用,而导致堵塞,我们不能给得太多,也不能太少.

  1:22 我打算给smtp用,优先低于1:21,以防发大的附件大量占用带宽.

  1:23 我打算给ftp-data,和1:22一样,很可能大量上传文件,所以,rate不能给的太多,而当其他有剩时可以给大些,ceil设置大些.

  1:24 是无所谓通道,就是一般不是我们平时工作上需要的通道,给小点防止这些人妨碍有正常工作需要的人.

  上行uplink 320K,设置销低于理论值.

  DEV="PPP0"

  UPLINK=300

  下行downlink 3200K大概一半左右,以便能够得到更多的关发连接.

  DOWNLINK=1500

  1 曾加一个根队列,没有进行分类的数据包都走这个1:24是缺省类:

  tc qdisc add dev $DEV parent 1: htb default 24

  1.1 增加一个根队下面主干类1: 速率为$UPLINK k

  tc class add dev $DEV parent 1: classid 1:1 htb rate ${UPLINK}kbit ceil ${UPLINK}kbit prio 0

  1.1.1 在主干类1下建立第一叶子类,这是一个最高优先权的类,需要高优先和高速的包走这条通道,比如SYN ACK ICMP等.

  tc class add dev $DEV parent 1:1 classid 1:11 htb rate ${$uplink}kbit ceil ${uplink}kbit prio 1

  1.1.2 在主类1下建立第二叶子类,这是一个次高优先权的类,比如我们重要的CRM数据。

  tc class add dev $DEV parent 1:1 classid 1:12 htb rate ${$uplink-150}kbit ceil ${uplink-50}kbit prio 2

  1.2 在根类下建立次干类 classid 1:2 ,此次干类的下面全部优先权低于主干类,以防重要数据堵塞。

  tc class add dev $DEV parent 1: classid 1:2 htb rate ${$UPLINK -150]kbit prio 3

1.2.1 在次干类下建立第一叶子类,可以跑例如http ,pop等。

  tc class add dev $DEV parent 1:2 classid 1:21 htb rate 100kbit ceil ${$uplink -150}kbit prio 4

  1.2.2 在次干类下建立第二叶子类,不要太高的速度,以防发大的附件大量占用带宽,便如smtp等。

  tc class add dev $DEV parent 1:2 classid 1:22 htb rate 30kbit ceil ${uplink-160}kbit prio 5

  1.2.3 在次干类下建立第三叶子类,不要太高的带宽,以防大量的数据堵塞网络,例如:ftp-data.

  tc class add dev $DEV parent 1:2 classid 1:23 htb rate 15kbit ceil ${UPLINK-170}kbit prio 6

  1.2.4 在次干类下建立第四叶子类。无所谓的数据通道,无需要太多的带宽,以防无所谓的人在阻碍正务。

  tc class add dev $DEV parent 1:2 classid 1:24 htb rate 5kbit ceil ${UPLINK -250}kbit prio 7

  在每个类下面再附加上另一个队列规定,随机公平队列(SFQ),不被某个连接不停占用带宽,以保证带宽的平均公平使用。

  #SFQ(stochastic fairness queueing 随机公平队列),SFQ的关键词是“会话”(或称作流),主要针对一个TCP会话或者UDP流,流量被分成相当多数量的FIFO队列中,每个队列对应一个会话。

  数据按照简单轮转的方式发送,每个会话都按顺序得到发送机会。这种方式非常公平,保证了每个会话都不会被其它会话所淹没,SFQ之所以被称为“随机”,是因为它并不是真的为每个会话创建一个队列,而是使用一个散列算法,把所有的会话映射到有限的几个队列中去。

  #参数perturb是多少秒后重新配置一次散列算法,默认为10秒.

  tc qdisc add dev $DEV parent 1:11 handle 111: sfq perturb 5

  tc qidsc add dev $DEV parent 1:12 handle 112: sfq perturb 5

  tc qdisc add dev $DEV parent 1:21 handle 121: sfq perturb 10

  tc qidsc add dev $DEV parent 1:22 handle 122: sfq perturb 10

  tc qidsc add dev $DEV parent 1:23 handle 123: sfq perturb 10

  tc qidsc add dev $DEV parent 1:24 handle 124: sfq perturb 10

  设置过滤器,handle是iptables作mark的值,让被iptables在mangle链做了mark的不同的值选择不同的通道classid,而prio是过滤器的优先级别

  tc filter add dev $DEV parent 1:0 protocol ip prio 1 handle 1 fw classid 1:11

  tc filter add dev $DEV parent 1:0 protocol ip prio 2 handle 2 fw classid 1:12

  tc filter add dev $DEV parent 1:0 protocol ip prio 3 handle 3 fw classid 1:21

  tc filter add dev $DEV parent 1:0 protocol ip prio 4 handle 4 fw classid 1:22

  tc filter add dev $DEV parent 1:0 protocol ip prio 5 handle 5 fw classid 1:23

  tc filter add dev $DEV parent 1:0 protocol ip prio 6 handle 6 fw classid 1:24

  ##################################################

  ##################################

  下行的限制:

  # 设置入队的规则,是因为把一些经常会造成下载大文件的端口进行控制,不让他们来得太快,导致堵塞,来得太快,就直接drop,就不会浪费和占用机器时间和力量去处理了.

  1 把下行速率控制在大概1000-1500K(大约为带宽的50%),因为这个速度已经够用了,以便能够得到更多的并发下载连接.

  tc qdisc add dev $DEV handle ffff: ingress

  tc filter add dev $DEV parent ffff: protocol ip prio 50 handle 8 fw police rate ${downlink}kbit burst 10k drop flowid :8

  如果内部网数据流不是很疯狂的话,就不用做下载的限制了,用#符号屏蔽上面两行既可.

  如果要对任何进来的数据进行限速的话,可以用下面这句.

  tc filter add dev $DEV parent ffff : protocol ip prio 10 u32 match ip src 0.0.0.0/0 police rate ${downlink}kbit burst 10k drop flowid :1

  ################################

  开始给数据包打标记

  把出去的不同类数据包(为dport)给mark上标记1---6,让它走不同的通道.

  把进来的数据包(为sport)给mark上标记8,让它受到下行的限制,以免速度太快而影响全局.

  每条规则下跟着return的意思是可以通过RETURN方法避免遍历所有的规则,加快了处理速度.

  设置TOS的处理:

  iptables -t mangle -A PREROUTING -m tos --tos Minimize-Delay -j MARK --set-mark 1

  iptables -t mangle -A PREROUTING -m tos --tos Minimize-Delay -j RETURN

  iptables -t mangle -A PREROUTING -m tos --tos Minimize-Cost -j MARK --set-mark 4

  iptables -t mangle -A PREROUTING --m tos --tos Minimize-Cost -j RETURN

  iptables -t mangle -A PREROUTING -m tos --tos Maximize-Throughput -j MARK --set-mark 5

  iptables -t mangle -A PREROUTING -m tos --tos Maximize-Througput -j RETURN

  ##提高TCP初始连接(也就是带有SYN的数据包)的优先权是非常明智的.

  iptables -t mangle -A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j MARK --set-mark 1

  iptables -t mangle -A PREROUTING -p tcp -m tcp --tcp-flags SYN,RST,ACK SYN -j RETURN

  #想ICMP 想ping有良好的反应,放在第一类。

  iptables -t mangle -A PREROUTING -p icmp -j MARK --set-mark 1

  iptables -t mangle -A PREROUTING -P icmp -j RETURN

  #small packets (probably just ACKS)长度小于64的小包通常是需要快些的,一般是用来确认tcp的连接的,让它跟快些的通道吧。

  iptables -t mangle -A PREROUTING -p tcp -m length --length :64 -j MARK --set-mark 2

  iptables -t mangle -A PREROUTING -p tcp -m length --length:64 -j RETURN

  #ftp放第二类,因为一般是小包,ftp-data放在第5类,因为一般是大时数据的传送。

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport ftp -j MARK --set-mark 2

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport ftp -j RETURN

  iptables -t mangle -A PRETOUTING -p tcp -m tcp --dport ftp-data -j MARK --set-mark 5

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp -j MARK --set-mark 8

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp-data -j MARK --set-mark 8

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport ftp-data -j RETURN

  ###提高SSH数据包的优先权:放在第1类,要知道SSH是交互式的和重要的,不容待慢:

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 22 -j MARK --set-mark 1

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport -j RETURN

  ##SMTP邮件,放在第4类,因为有时有人发送很大的邮件,为避免它堵塞,让它跑第4道吧

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 25 -j MARK --st-mark 4

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 25 -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 25 -j MARK --set-mark 8

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 25 -j RETURN

##name-domain server:放在第1类,这样连接带有域名的连接才能快速找到对应有的地址,提高速度

  iptables -t mangle -A PREROUTING -p udp -m udp --dport 53 -j MARK --set-mark 1

  iptables -t mangle -A PREROUTING -P udp -m udp --dport 53 -j RETURN

  ###HTTP: 放在第3类,是最常用的,最多人用的

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 80 -j MARK --set-mark 3

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 80 -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 80 -j MARK --set-mark 8

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 80 -j RETURN

  ###pop邮件放在第3类:

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 110 -j MARK --set-mark 3

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dprot 110 -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 110 -j MARK --set-mark 8

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 110 -j RETURN

  ###MICSOSOFT-SQL-SERVE:放在第2类,我这里认为较重要,一定保证速度和优先的

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1433 -j MARK --set-mark 3

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1433 -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 1433 -j MARK --set-mark 8

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 1433 -j RETURN

  ##https:放在第3类

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 443 -j MARK --set-mark 3

  iptables -t mangle -A PREROUTING -p tcpm -m tcp --dport 443 -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 443 -j MAKR --set-mark 8

  iptables -t mangle -A PREROUTING -P tcp -m tcp --sport 443 -j RETURN

  ###voip用,提高,语音要保持高速才不会断续

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1720 -j MARK--SET-MARK 1

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 1720 -j RETURN

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 1720 -j MAKR --set-mark 8

  iptables -t mangle -A PREROUTING -p tcp -m tcp --sport 1720 -j RETURN

  ###VPN 用作voip的,也要走高速路,才不会断续

  iptables -t mangle -A PREROUTING -p udp -m udp --dport 7707 -j MARK --set-mark 1

  iptables -t mangle -A PREROUTING -p udp -m udp --dport 7707 -j RETURN

  ###放在第1类,因为我觉得客观存在要我心中很重要,优行:

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport 7070 -j MARK --set-mark 1

  iptables -t mangle -A PREROUTING -p tcp -m tcp --dport -j RETURN

  ##提高本地数据包的优先权:放在第1类

  iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 22 -j MARK --set-mark 1

  iptables -t mangle -A OUTPUT -p tcp -m tcp --dport 22 -j RETURN

  iptables -t mangle -A OUTPUT -p icmp -j MARK --set-mark 1

  iptables -t mangle -A OUTPUT -p icmp -j RETURN

  ###本地small packet (probably just ACKS)

  iptables -t mangle -A OUTPUT -p tcp -m length --length :64 --set-mark 2

  iptables -t mangle -A OUTPUT -p tcp -m length --length :64 -j RETURN

  #################################################

  ## 向PRETOUTRIN中添加完mangle规则后,用这条规则结束prerouting表:也就是说前面没有打过标记的数据包就交给1:24来处理实际 上是不必要的,因为1:24是缺省类,但仍然打上标记是为了保持整个设置 的协调一致,而且这样,还能看到规则的数据包计数:

  iptables -t mangle -A PREROUTING -i $DEV -j MARK --set-mark 6

  ###对某人限制:iptables -t mangle -I PREROUTING 1 -s 192.168.xx.xx -j MAKR --set-mark 6

  ###iptables -t mangle -I PREROUTING 2 -s 192.168.xx.xx -j RETURN

  ###################################################

  u32的应用:

  tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 ...... 这就是所谓的u32匹配,可以匹配数据包的任意部分.

  根据源/目的地址: match ip src 0.0.0.0/0

  match ip dst 1.2.3.0/24

  单个IP地址可以用/32来表示

  根据源/目的端口可以这样表示: match ip sport 80 0xffff

  match ip dport 80 0xffff

  根据IP协议: match ip protocol (udp tcp icmp gre ipsec)

  比如icmp协议是1 match ip protocol 1 0xff

  举例:

  tc filter add dev $DEV parent 1:0 protocol ip prio 1 u32 match ip dst 4.3.2.1/32 flowid 10:1

  tc filter add dev $DEV parent 1:0 protocol ip prio 1

  u32 match ip src 4.3.2.1/32 match ip sport 80 0xffff flowid 10:1

 Linux 内核流量控制 TC 详解

量控制设置 
摘要 
tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ] 

tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ] 

tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flowid flow-id 

tc [-s | -d ] qdisc show [ dev DEV ] 

tc [-s | -d ] class show dev DEV tc filter show dev DEV 


简介 
Tc用于Linux内核的流量控制。流量控制包括以下几种方式: 

SHAPING(限制) 
当流量被限制,它的传输速率就被控制在某个值以下。限制值可以大大小于有效带宽,这样可以平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量。 

SCHEDULING(调度) 
通过调度数据包的传输,可以在带宽范围内,按照优先级分配带宽。SCHEDULING(调度)也只适于向外的流量。 

POLICING(策略) 
SHAPING用于处理向外的流量,而POLICIING(策略)用于处理接收到的数据。 

DROPPING(丢弃) 
如果流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。 

流量的处理由三种对象控制,它们是:qdisc(排队规则)、class(类别)和filter(过滤器)。 

QDISC(排队规则) 
QDisc(排 队规则)是queueing discipline的简写,它是理解流量控制(traffic control)的基础。无论何时,内核如果需要通过某个网络接口发送数据包,它都需要按照为这个接口配置的qdisc(排队规则)把数据包加入队列。然 后,内核会尽可能多地从qdisc里面取出数据包,把它们交给网络适配器驱动模块。 
最简单的QDisc是pfifo它不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。不过,它会保存网络接口一时无法处理的数据包。 


CLASS(类) 
某些QDisc(排队规则)可以包含一些类别,不同的类别中可以包含更深入的QDisc(排队规则),通过这些细分的QDisc还可以为进入的队列的数据包排队。通过设置各种类别数据包的离队次序,QDisc可以为设置网络数据流量的优先级。 

FILTER(过滤器) 
filter(过 滤器)用于为数据包分类,决定它们按照何种QDisc进入队列。无论何时数据包进入一个划分子类的类别中,都需要进行分类。分类的方法可以有多种,使用 fileter(过滤器)就是其中之一。使用filter(过滤器)分类时,内核会调用附属于这个类(class)的所有过滤器,直到返回一个判决。如果 没有判决返回,就作进一步的处理,而处理方式和QDISC有关。 
需要注意的是,filter(过滤器)是在QDisc内部,它们不能作为主体。 


CLASSLESS QDisc(不可分类QDisc) 
无类别QDISC包括: 
[p|b]fifo 
使用最简单的qdisc,纯粹的先进先出。只有一个参数:limit,用来设置队列的长度,pfifo是以数据包的个数为单位;bfifo是以字节数为单位。 
pfifo_fast 
在 编译内核时,如果打开了高级路由器(Advanced Router)编译选项,pfifo_fast就是系统的标准QDISC。它的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。而三个 波段(band)的优先级也不相同,band 0的优先级最高,band 2的最低。如果band里面有数据包,系统就不会处理band 1里面的数据包,band 1和band 2之间也是一样。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。 
red 
red是Random Early Detection(随机早期探测)的简写。如果使用这种QDISC,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。它非常适合高带宽应用。 
sfq 
sfq是Stochastic Fairness Queueing的简写。它按照会话(session--对应于每个TCP连接或者UDP流)为流量进行排序,然后循环发送每个会话的数据包。 
tbf 
tbf是Token Bucket Filter的简写,适合于把流速降低到某个值。 
不可分类QDisc的配置 
如果没有可分类QDisc,不可分类QDisc只能附属于设备的根。它们的用法如下: 
tc qdisc add dev DEV root QDISC QDISC-PARAMETERS 

要删除一个不可分类QDisc,需要使用如下命令: 

tc qdisc del dev DEV root 

一个网络接口上如果没有设置QDisc,pfifo_fast就作为缺省的QDisc。 


CLASSFUL QDISC(分类QDisc) 
可分类的QDisc包括: 
CBQ 
CBQ 是Class Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具有带宽优先级管理的能力。带 宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。 
HTB 
HTB 是 Hierarchy Token Bucket的缩写。通过在实践基础上的改进,它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽,虽然它也允许特定的类可 以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。 
PRIO 
PRIO QDisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用PRIO QDisc可以很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。为了方便管理,需要使用 iptables或者ipchains处理数据包的服务类型(Type Of Service,ToS)。 
操作原理 
类(Class)组成一个树,每个类都只有一个父类,而一个类可以有多个子类。某些QDisc(例如:CBQ和HTB)允许在运行时动态添加类,而其它的QDisc(例如:PRIO)不允许动态建立类。 
允许动态添加类的QDisc可以有零个或者多个子类,由它们为数据包排队。 

此外,每个类都有一个叶子QDisc,默认情况下,这个叶子QDisc使用pfifo的方式排队,我们也可以使用其它类型的QDisc代替这个默认的QDisc。而且,这个叶子叶子QDisc有可以分类,不过每个子类只能有一个叶子QDisc。 

当一个数据包进入一个分类QDisc,它会被归入某个子类。我们可以使用以下三种方式为数据包归类,不过不是所有的QDisc都能够使用这三种方式。 

tc过滤器(tc filter) 
如果过滤器附属于一个类,相关的指令就会对它们进行查询。过滤器能够匹配数据包头所有的域,也可以匹配由ipchains或者iptables做的标记。 
服务类型(Type of Service) 
某些QDisc有基于服务类型(Type of Service,ToS)的内置的规则为数据包分类。 
skb->priority 
序可以使用SO_PRIORITY选项在skb->priority域设置一个类的ID 
树的每个节点都可以有自己的过滤器,但是高层的过滤器也可以直接用于其子类。 
如果数据包没有被成功归类,就会被排到这个类的叶子QDisc的队中。相关细节在各个QDisc的手册页中。 


命名规则 
所有的QDisc、类和过滤器都有ID。ID可以手工设置,也可以有内核自动分配。 
ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。 


QDISC 
一个QDisc会被分配一个主序列号,叫做句柄(handle),然后把从序列号作为类的命名空间。句柄采用象10:一样的表达方式。习惯上,需要为有子类的QDisc显式地分配一个句柄。 

类(CLASS) 
在同一个QDisc里面的类分享这个QDisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只与父QDisc有关,和父类无关。类的命名习惯和QDisc的相同。 

过滤器(FILTER) 
过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。详情请参考tc-filters手册页。 
单位 
tc命令的所有参数都可以使用浮点数,可能会涉及到以下计数单位。 
带宽或者流速单位: 

kbps 
千字节/秒 
mbps 
兆字节/秒 
kbit 
KBits/秒 
mbit 
MBits/秒 
bps或者一个无单位数字 
字节数/秒 
数据的数量单位: 

kb或者k 
千字节 
mb或者m 
兆字节 
mbit 
兆bit 
kbit 
千bit 
b或者一个无单位数字 
字节数 
时间的计量单位: 
s、sec或者secs 
 
ms、msec或者msecs 
分钟 
us、usec、usecs或者一个无单位数字 
微秒 

TC命令 
tc可以使用以下命令对QDisc、类和过滤器进行操作: 
add 
在 一个节点里加入一个QDisc、类或者过滤器。添加时,需要传递一个祖先作为参数,传递参数时既可以使用ID也可以直接传递设备的根。如果要建立一个 QDisc或者过滤器,可以使用句柄(handle)来命名;如果要建立一个类,可以使用类识别符(classid)来命名。 

remove 
删除有某个句柄(handle)指定的QDisc,根QDisc(root)也可以删除。被删除QDisc上的所有子类以及附属于各个类的过滤器都会被自动删除。 

change 
以替代的方式修改某些条目。除了句柄(handle)和祖先不能修改以外,change命令的语法和add命令相同。换句话说,change命令不能一定节点的位置。 

replace 
对一个现有节点进行近于原子操作的删除/添加。如果节点不存在,这个命令就会建立节点。 

link 
只适用于DQisc,替代一个现有的节点。 

历史 
tc由Alexey N. Kuznetsov编写,从Linux 2.2版开始并入Linux内核。 
SEE ALSO 
tc-cbq(8)、tc-htb(8)、tc-sfq(8)、tc-red(8)、tc-tbf(8)、tc-pfifo(8)、tc-bfifo(8)、tc-pfifo_fast(8)、tc-filters(8) 

TC(Linux下流量控制工具)详细说明及应用实例

一、TC的安装 ....................................................................................................................................1 二、TC原理介绍.................................................................................................................................1 三、TC规则........................................................................................................................................2  3.1、流量控制方式 .....................................................................................................................2 3.2、流量控制处理对象 ..............................................................................................................2 3.3、操作原理 ............................................................................................................................3 3.4、命名规则 ............................................................................................................................4 3.5、单位 ...................................................................................................................................4 四、TC命令........................................................................................................................................5 五、具体操作 ......................................................................................................................................5  5.1、基本实现步骤 .....................................................................................................................6 5.2、环境模拟实例 .....................................................................................................................6  5.2.1. 建立队列 ...................................................................................................................6  5.2.2. 建立分类 ...................................................................................................................6 5.2.3. 建立过滤器 ...............................................................................................................7  5.2.4.建立路由.....................................................................................................................7 5.2.5. 监视 ..........................................................................................................................8 5.2.6. 维护 ........................................................................................................................ 10  六、dms小组应用场景一个实例 ....................................................................................................... 11 参考资料 ........................................................................................................................................... 1

 

一、TC的安装 

TClinux自带的模块,一般情况下不需要另行安装,可以用man tc查看tc相关命令细节,tc 要求内核2.4.18以上。   

 二、TC原理介绍

        Linux操作系统中的流量控制器TCTraffic Control)用于Linux内核的流量控制,它利用队列规定建立处理数据包的队列,并定义队列中的数据包被发送的方式, 从而实现对流量的控制。

TC模块实现流量控制功能使用的队列规定分为两类,一类是无类队列规定, 另一类是分类队列规定。 无类队列规定相对简单,而分类队列规定则引出了分类和过滤器等概念,使其流量控制功能增强。

无类队列规定是对进入网络设备(网卡) 的数据流不加区分统一对待的队列规定。使用无类队列规定形成的队列能够接受数据包以及重新编排、延迟或丢弃数据包。这类队列规定形成的队列可以对整个网络设备( 网卡) 的流量进行整形, 但不能细分各种情况„ 。常用的无类队列规定主要有pfifo _fast (先进现出) TBF ( 令牌桶过滤器) SFQ(随机公平队列) ID (前向随机丢包)等等。这类队列规定使用的流量整形手段主要是排序、 限速和丢包。

分类队列规定是对进入网络设备的数据包根据不同的需求以分类的方式区分对待的队列规定。 数据包进入一个分类的队列后, 它就需要被送到某一个类中, 也就是说需要对数据包做分类处理。对数据包进行分类的工具是过滤器,过滤器会返回一个决定,队列规定就根据这个决定把数据包送入相应的类进行排队。每个子类都可以再次使用它们的过滤器进行进一步的分类。直到不需要进一步分类时, 数据包才进入该类包含的队列排队。 除了能够包含其它队列规定之外, 绝大多数分类的队列规定还能够对流量进行整形。 这对于需要同时进行调度( 如使用 S F Q ) 和流量控制的场合非常有用。 

Linux流量控制的基本原理如下图所示。   

接收包从输入接口(Input Interface)进来后,经过流量限制(Ingress Policing)丢弃不符合规定的数据包,由输入多路分配器(Input De-Multiplexing)进行判断选择:如果接收包的目的是本主机,那么将该包送给上层处理;否则需要进行转发,将接收包交到转发块(Forwarding Block)处理。转发块同时也接收本主机上层(TCPUDP等)产生的包。转发块通过查看路由表,决定所处理包的下一跳。然后,对包进行排列以便将它们传送到输出接口(Output Interface)。一般我们只能限制网卡发送的数据包,不能限制网卡接收的数据包,所以我们可以通过改变发送次序来控制传输速率。Linux流量控制主要是在输出接口排列时进行处理和实现的。

三、TC规则

3.1、流量控制方式 

流量控制包括以下几种方式:

SHAPING(限制

当流量被限制,它的传输速率就被控制在某个值以下。限制值可以大大小于有效带宽,这样可以平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量。     SCHEDULING(调度

通过调度数据包的传输,可以在带宽范围内,按照优先级分配带宽。SCHEDULING(调度)也只适于向外的流量。 

POLICING(策略)      

 SHAPING用于处理向外的流量,而POLICIING(策略)用于处理接收到的数据。  DROPPING(丢弃)      

  如果流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。

3.2、流量控制处理对象 

流量的处理由三种对象控制,它们是:qdisc(排队规则)class(类别)filter(过滤器)  QDisc(排队规则)queueing discipline的简写,它是理解流量控制(traffic control)的基础。无论何时,内核如果需要通过某个网络接口发送数据包,它都需要按照为这个接口配置的qdisc(排队规则)把数据包加入队列。然后,内核会尽可能多地从qdisc里面取出数据包,把它们交给网络适配器驱动模块。最简单的QDiscpfifo它不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。不过,它会保存网络接口一时无法处理的数据包。

QDISC的分为CLASSLESS QDiscCLASSFUL QDISC类别如下:

 

1)、CLASSLESS QDisc(不可分类QDisc) 1>无类别QDISC包括:  [p|b]fifo,使用最简单的qdisc,纯粹的先进先出。只有一个参数:limit,用来设置队列的长度,pfifo是以数据包的个数为单位;bfifo是以字节数为单位。  pfifo_fast,在编译内核时,如果打开了高级路由器(Advanced Router)编译选项,pfifo_fast就是系统的标准QDISC。它的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。而三个波段(band)的优先级也不相同,band 0的优先级最高,band 2的最低。如果band里面有数据包,系统就不会处理band 1里面的数据包,band 1band 2之间也是一样。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。

redredRandom Early Detection(随机早期探测)的简写。如果使用这种QDISC,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。它非常适合高带宽应用。

sfqsfqStochastic Fairness Queueing的简写。它按照会话(session--对应于每个TCP连接或者UDP)为流量进行排序,然后循环发送每个会话的数据包。 

tbftbfToken Bucket Filter的简写,适合于把流速降低到某个值。

2>无类别QDisc的配置  如果没有可分类QDisc,不可分类QDisc只能附属于设备的根。它们的用法如下:          

要删除一个不可分类QDisc,需要使用如下命令:          

一个网络接口上如果没有设置QDiscpfifo_fast就作为缺省的QDisc 

2)、CLASSFUL QDISC(分类QDisc) 可分类QDISC包括:

CBQCBQClass Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具有带宽优先级管理的能力。带宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。

 HTBHTBHierarchy Token Bucket的缩写。通过在实践基础上的改进,它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽,虽然它也允许特定的类可以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。  PRIOPRIO QDisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用PRIO QDisc可以很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。为了方便管理,需要使用iptables或者ipchains处理数据包的服务类型(Type Of Service,ToS)

 3.3、操作原理

(Class)组成一个树,每个类都只有一个父类,而一个类可以有多个子类。某些QDisc(例如:CBQHTB)允许在运行时动态添加类,而其它的QDisc(例如:PRIO)不允许动态建立类。允许动态添加类的QDisc可以有零个或者多个子类,由它们为数据包排队。此外,每个类都有一个叶子QDisc,默认情况下,这个叶子QDisc使用pfifo的方式排队,我们也可以使用其它类型的QDisc代替这个默认的QDisc。而且,这个叶子叶子QDisc有可以分类,不过每个子类只能有一个叶子QDisc。当一个数据包进入一个分类QDisc,它会被归入某个子类。我们可以使用以下三种方式为数据包归类,不过不是所有的QDisc都能够使用这三种方式。

 tc qdisc add dev DEV root QDISC QDISC-PARAMETERS tc qdisc del dev DEV root     如果过滤器附属于一个类,相关的指令就会对它们进行查询。过滤器能够匹配数据包头所有的域,也可以匹配由ipchains或者iptables做的标记。  树的每个节点都可以有自己的过滤器,但是高层的过滤器也可以直接用于其子类。如果数据包没有被成功归类,就会被排到这个类的叶子QDisc的队中。相关细节在各个QDisc的手册页中。

3.4、命名规则  所有的QDisc、类和过滤器都有ID。ID可以手工设置,也可以有内核自动分配。ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。  QDISC,一个QDisc会被分配一个主序列号,叫做句柄(handle),然后把从序列号作为类的命名空间。句柄采用象10:一样的表达方式。习惯上,需要为有子类的QDisc显式地分配一个句柄。  类(CLASS),在同一个QDisc里面的类分享这个QDisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只与父QDisc有关,和父类无关。类的命名习惯和QDisc的相同。  过滤器(FILTER),过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。详情请参考tc-filters手册页。

 3.5、单位  tc命令的所有参数都可以使用浮点数,可能会涉及到以下计数单位。

 1)、带宽或者流速单位:

2)、数据的数量单位:

3)、时间的计量单位:

四、TC命令

 tc可以使用以下命令对QDisc、类和过滤器进行操作:

 add,在一个节点里加入一个QDisc、类或者过滤器。添加时,需要传递一个祖先作为参数,传递参数时既可以使用ID也可以直接传递设备的根。如果要建立一个QDisc或者过滤器,可以使用句柄(handle)来命名;如果要建立一个类,可以使用类识别符(classid)来命名。  remove,删除有某个句柄(handle)指定的QDisc,根QDisc(root)也可以删除。被删除QDisc上的所有子类以及附属于各个类的过滤器都会被自动删除。 

change,以替代的方式修改某些条目。除了句柄(handle)和祖先不能修改以外,change命令的语法和add命令相同。换句话说,change命令不能一定节点的位置。

 replace,对一个现有节点进行近于原子操作的删除/添加。如果节点不存在,这个命令就会建立节点。

link,只适用于DQisc,替代一个现有的节点。 例:

五、具体操作

  Linux流量控制主要分为建立队列、建立分类和建立过滤器三个方面。 s、sec或者secs                              秒 ms、msec或者msecs                       分钟 us、usec、usecs或者一个无单位数字    微秒  tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ]  tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ]  tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flowid flow-id tc [-s | -d ] qdisc show [ dev DEV ]  tc [-s | -d ] class show dev DEV tc filter show dev DEV    

5.1、基本实现步骤

 (1) 针对网络物理设备(如以太网卡eth0)绑定一个队列QDisc;

(2) 在该队列上建立分类class; 

(3) 为每一分类建立一个基于路由的过滤器filter;

(4) 最后与过滤器相配合,建立特定的路由表。

5.2、环境模拟实例

流量控制器上的以太网卡(eth0) 的IP地址为192.168.1.66,在其上建立一个CBQ队列。假设包的平均大小为1000字节,包间隔发送单元的大小为8字节,可接收冲突的发送最长包数目为20字节。 

假如有三种类型的流量需要控制:      

 1) 是发往主机1的,其IP地址为192.168.1.24。其流量带宽控制在8Mbit,优先级为2;       2) 是发往主机2的,其IP地址为192.168.1.30。其流量带宽控制在1Mbit,优先级为1;         3) 是发往子网1的,其子网号为192.168.1.0,子网掩码为255.255.255.0。流量带宽控制在1Mbit,优先级为6。

 5.2.1. 建立队列  一般情况下,针对一个网卡只需建立一个队列。  将一个cbq队列绑定到网络物理设备eth0上,其编号为1:0;网络物理设备eth0的实际带宽为10 Mbit,包的平均大小为1000字节;包间隔发送单元的大小为8字节,最小传输包大小为64字节。   5.2.2. 建立分类 分类建立在队列之上。

一般情况下,针对一个队列需建立一个根分类,然后再在其上建立子分类。对于分类,按其分类的编号顺序起作用,编号小的优先;一旦符合某个分类匹配规则,通过该分类发送数据包,则其后的分类不再起作用。

 1) 创建根分类1:1;分配带宽为10Mbit,优先级别为8。

该队列的最大可用带宽为10Mbit,实际分配的带宽为10Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为8,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为1Mbit。

 2)创建分类1:2,其父分类为1:1,分配带宽为8Mbit,优先级别为2。

该队列的最大可用带宽为10Mbit,实际分配的带宽为 8Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为2,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为800Kbit,分类的分离点为1:0,且不可借用未使用带宽。 

3)创建分类1:3,其父分类为1:1,分配带宽为1Mbit,优先级别为1。

该队列的最大可用带宽为10Mbit,实际分配的带宽为 1Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为1,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为100Kbit,分类的分离点为1:0。

 4)创建分类1:4,其父分类为1:1,分配带宽为1Mbit,优先级别为6。

该队列的最大可用带宽为10Mbit,实际分配的带宽为1Mbit,可接收冲突的发送最长包数目为20字节;最大传输单元加MAC头的大小为1514字节,优先级别为6,包的平均大小为1000字节,包间隔发送单元的大小为8字节,相应于实际带宽的加权速率为100Kbit,分类的分离点为1:0。  5.2.3. 建立过滤器 过滤器主要服务于分类。  一般只需针对根分类提供一个过滤器,然后为每个子分类提供路由映射。  1) 应用路由分类器到cbq队列的根,父分类编号为1:0;过滤协议为ip,优先级别为100,过滤器为基于路由表。

2) 建立路由映射分类1:2, 1:3, 1:4

5.2.4.建立路由  该路由是与前面所建立的路由映射一一对应。

1) 发往主机192.168.1.24的数据包通过分类2转发(分类2的速率8Mbit)

2) 发往主机192.168.1.30的数据包通过分类3转发(分类3的速率1Mbit)

3)发往子网192.168.1.0/24的数据包通过分类4转发(分类4的速率1Mbit)

注:一般对于流量控制器所直接连接的网段建议使用IP主机地址流量控制限制,不要使用子网流量控制限制。如一定需要对直连子网使用子网流量控制限制,则在建立该子网的路由映射前,需将原先由系统建立的路由删除,才可完成相应步骤。  5.2.5. 监视  主要包括对现有队列、分类、过滤器和路由的状况进行监视。 1)显示队列的状况  简单显示指定设备(这里为eth0)的队列状况

详细显示指定设备(这里为eth0)的队列状况

这里主要显示了通过该队列发送了13232个数据包,数据流量为7646731个字节,丢弃的包数目为0,超过速率限制的包数目为0。 2)显示分类的状况  简单显示指定设备(这里为eth0)的分类状况

详细显示指定设备(这里为eth0)的分类状况

这里主要显示了通过不同分类发送的数据包,数据流量,丢弃的包数目,超过速率限制的包数目等等。其中根分类(class cbq 1:0)的状况应与队列的状况类似。  例如,分类class cbq 1:4发送了8076个数据包,数据流量为5552879个字节,丢弃的包数目为0,超过速率限制的包数目为0。 显示过滤器的状况

这里flowid 1:2代表分类class cbq 1:2,to 2代表通过路由2发送。 显示现有路由的状况

如上所示,结尾包含有realm的显示行是起作用的路由过滤器。 5.2.6. 维护  主要包括对队列、分类、过滤器和路由的增添、修改和删除。  增添动作一般依照"队列->分类->过滤器->路由"的顺序进行;修改动作则没有什么要求;删除则依照"路由->过滤器->分类->队列"的顺序进行。  1)队列的维护  一般对于一台流量控制器来说,出厂时针对每个以太网卡均已配置好一个队列了,通常情况下对队列无需进行增添、修改和删除动作了。 2)分类的维护  增添,增添动作通过tc class add命令实现,如前面所示。 修改,修改动作通过tc class change命令实现,如下所示:

对于bounded命令应慎用,一旦添加后就进行修改,只可通过删除后再添加来实现。  删除,删除动作只在该分类没有工作前才可进行,一旦通过该分类发送过数据,则无法删除它了。因此,需要通过shell文件方式来修改,通过重新启动来完成删除动作。 3)过滤器的维护  增添,增添动作通过tc filter add命令实现,如前面所示。 修改,修改动作通过tc filter change命令实现,如下所示:

删除,删除动作通过tc filter del命令实现,如下所示:

4)与过滤器一一映射路由的维护  增添,增添动作通过ip route add命令实现,如前面所示。 修改,修改动作通过ip route change命令实现,如下所示:

删除,删除动作通过ip route del命令实现,如下所示:

六、dms小组应用场景一个实例   前面的内容大多是查找的一些资料,下面将介绍一下dms曾经用到的一个脚本实例,脚本如下:

说明:  tc qdisc add dev eth1 root handle 1: prio用以建立一个root(注,这里的root不是指linux下root用户,仅仅单纯指“根”这一概念)优先级队列,句柄为1(对于tc队列的构成及原理请详见参考资料[1],上面讲得非常透彻),此队列所作用的网卡接口为eth1  tc qdisc add dev eth1 parent 1:1 handle 10: netem delay `expr $randdelay`ms distribution normal loss $randloss% 用以在根队列下建立一个子队列,子队列的句柄为10(当然也可以指定为其他,一般为了方便查看,根队列为1位数,子队列为两位„„),这个子队列的作用是调用netem模块让通过的网络流量延迟,并按一定的丢包率丢包。(注:netem是linux中的另一个模块,并不是内嵌于tc工具中,tc仅仅是调用这模块,所以man tc是看不到相关于netem的信息的,关于netem的使用,详见参考资料[5])  需要再说明一点是,为什么这里要建一个子队列。可以看到,我们的目标是针对相关的端口进行流量控制,但子队列现在的功能是对所有的流量都起作用,因此,需要挂载一个过滤器(filter),对流量进行一个过滤,但在tc中,filter是不能直接挂在根队列上的。  tc filter add dev eth1 protocol ip parent 1:0 prio 1 u32 match ip dport 32123 0xffff flowid 1:1在子队列上挂载一个filter,所有通过子队列1:1的流量,都会被过滤,只有满足filter条件的流量才会从该子队列中通过,这个条件为“目的地址为32123,IP地址无限制”(注,tc默认只对出流量有效,因此在构建规则时要仔细考虑进这个因素)。  如果不想tc中应用的规则再起作用,执行下以脚本删除它:

参考资料   [1]高旸、聂永峰,一种基于Linux TC的流量控制管理架构,计算机工程与设计,2006.10   [2]网络文章,tc,学习  http://blog.csdn.net/tqyou85/archive/2008/11/06/3226773.aspx   [3] Linux下TC使用说明,百度文库   [4]网络文章,linux tc实现ip流量限制,  http://blog.csdn.net/wind0513/archive/2010/03/02/5339127.aspx   [5]官方说明,netem       netem  The Linux Foundation.mht

 

tc学习

上网环境如下:
    eth0 外网ip :a.b.c.d
    eth1 内网ip1:192.168.0.0/24  给老板和bt
    eth2 内网ip2:192.168.1.0/24  给我和csfans
linux nat 命令如下:
echo 1 >; /proc/sys/net/ipv4/ip_forward
iptables -F
iptables -t nat -F    ----
清除旧规则
iptables -t nat -A POSTROUTING -s 192.168.0.0/24 -o eth0 -j SNAT --to a.b.c.d   ---为内网ip1 nat
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT -- to a.b.c.d   ---为内网ip2 nat
------------为流量控制做基于fw过滤器的标记
iptables -I PREROUTING -t mangle -p tcp -s 192.168.0.0/24 -j MARK --set-mark 1
iptables -I PREROUTING -t mangle -p tcp -s 192.168.1.0/24 -j MARK --set-mark 2
------------
为上传速率做流量控制
tc 要求内核2.4.18以上,所以不够的要升级
tc 只能控制网卡发送包的速率,所以上传速率的限制要在eth0上做
----删除旧有队列
tc qdisc del dev eth0 root
----
加一个根队列,速率用网卡的速率10Mbit,也可用上传的速率
tc qdisc add dev eth0 root handle 100: cbq bandwidth 10Mbit avpkt 1000
----
加一个根类
tc class add dev eth0 parent 100:0 classid 100:1 cbq bandwidth 10Mbit rate 10Mbit allot 1514 weight 1Mbit prio 8 maxburst 8 avpkt 1000 bounded
----
加一个子类用于内网1速率限制为300Kbit
tc class add dev eth0 parent 100:1 classid 100:2 cbq bandwidth 10Mbit rate 300Kbit allot 1513 weight 30Kbit prio 5 maxburst 8 avpkt 1000 bounded
----
加一个子类用于内网2速率限制为320Kbit
tc class add dev eth0 parent 100:1 classid 100:3 cbq bandwidth 10Mbit rate 320Kbit allot 1513 weight 32Kbit prio 6 maxburst 8 avpkt 1000 bounded
----
设置队列规则
tc qdisc add dev eth0 parent 100:2 sfq quantum 1514b perturb 15
tc qdisc add dev eth0 parent 100:3 sfq quantum 1514b perturb 15
------
将队列和fw过滤器映射起来 其中hand 1 1是开始用iptables 做的标记,hand 2 2也是开始用iptables 做的标记
tc filter add dev eth0 parent 100:0 protocol ip prio 1 handle 1 fw classid 100:2
tc filter add dev eth0 parent 100:0 protocol ip prio 2 handle 2 fw classid 100:3
-----------------------
再做下载限制我只限制了老板和bt的下载速率,过滤器是用u32
tc qdisc del dev eth1 root
tc qdisc add dev eth1 root handle 200: cbq bandwidth 10Mbit avpkt 1000
tc class add dev eth1 parent 200:0 classid 200:1 cbq bandwidth 10Mbit rate 10Mbit allot 1514 weight 2Kbit prio 8 maxburst 8 avpkt 1000 bounded
tc class add dev eth1 parent 200:1 classid 200:2 cbq bandwidth 10Mbit rate 1000Kbit allot 1513 weight 1Mbit prio 5 maxburst 8 avpkt 1000 bounded
tc qdisc add dev eth1 parent 200:2 sfq quantum 1514b perturb 15
tc filter add dev eth1 parent 200:0 protocol ip prio 25 u32 match ip dst 192.168.0.0/24 flowid 200:2


----------------------

现在可以用tc -s qdisc ls dev eth0
            tc -s qdisc ls dev eth1
          tc -s class ls dev eth0
          tc -s class ls dev eth1
监视流量 

tc命令man整理

语法: 

tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ] 

tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ]

 tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flow flow-id  

tc [ FORMAT ] qdisc show [ dev DEV ] 

tc [ FORMAT ] class show dev DEV

 tc filter show dev DEV 

 FORMAT := { -s[tatistics] | -d[etails] | -r[aw] | -p[retty] | i[ec] } 

 DESCRIPTION  SHAPING  

 当流量被限制,它的传输速率就被控制到某个值以下。限制值可以远小于有效带宽,这样可以平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量(读)。  SCHEDULING  

通过调度数据包的传输,可以在带宽范围内,按照优先级分配带宽。scheduling(调度)也只适用于向外的流量。

 POLICING   SHAPING用于处理向外的流量,而POLICING(策略)用于处理接收到的数据。  DROPPING    如果流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。       流量的处理由三种对象控制,是:qdisc(排队规则)、class(类别)和filter(过滤器):

QDISC 

qdisc(排队规则)是queueing discipline的简写,它是理解流量控制(traffic control)的基础。无论何时,内核如果需要通过某个网络接口发送数据包, 它都需要按照为这个接口配置的qdisc把数据包加入队列。然后,内核会尽可能多的从qdisc里面取出数据包,把它们交给网络适配器驱动模块。   

最简单的qdisc是pfifo,它不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。不过,它会保存网络接口一时无法处理的数据包。 

CLASS

  某些qdisc可以包含一些类别,不同的类别中可以包含更深入的qdisc,通过这些细分的qdisc还可以为进入的队列的数据包排队。通过设置各种类别 数据包的离队次序,qdisc可以为设置网络数据流量的优先级。

 FILTER

   filter(过滤器)用于为数据包分类,决定它们按照何种qdisc进入队列。无论何时数据包进入一个划分子类的类别中,都需要进行分类。分类的方法 可以有多种,使用filter就是其中之一。使用filter分类时,内核会调用附属于这个类(class)的所有过滤器,直到返回一个判决。如果没有判决返回, 就作进一步的处理,而处理方式和qdisc有关。  需要注意的是,filter是在qdisc内部,它们不能作为主体。   

CLASSLESS QDISCS

  无类别的qdisc包括:   [p|b]fifo:使用最简单的qdisc,纯粹的先进先出。只有一个参数:limit,用来设置队列的长度,pfifo是以数据包的个数为单位;bfifo是以字节数    为单位。   pfifo_fast:在编译内核时,如果打开了高级路由器(Advanced Router)编译选项,pfifo_fast就是系统的标准qdisc。它的队列包括三个波段(band)。

在每个波段里面,使用先进先出规则。而三个波段(band)的优先级也不相同,band 0优先级最高,band 2的最低。如果band 0里面有数据包,系统就不会处理band 1里面的数据包,band 1和band 2之间也是一样。数据包是按照TOS被分配到三个波段里面的。

  red:是Random Early Detection(随机早期探测)的简写。如果使用这种qdisc,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。它非常适合高宽带应用。 

sfq:是Stochastic Fairness Queueing(随机公平队列)的简写。它按照会话(session--对应于每个TCP连接或者UDP流)为流量进行排序,然后循环发送每个会话的数据包。

tbf:是Token Bucket Filter(令牌桶过滤器)的简写,适合于把流速降低到某个值。    CONFIGURING CLASSLESS QDISCS(不可分类qdisc的配置)  如果没有可分类qdisc,不可分类qdisc只能附属于设备的根。

用法如下: 

tc qdisc add dev DEV root QDISC QDISC-PARAMETERS 

tc qdisc del dev DEV root

 一个网络接口上如果没有设置qdisc,pfifo_fast就作为缺省的qdisc。 

 CLASSFUL QDISCS(分类qdisc) 

可分类的qdisc包括: 

 CBQ:是Class Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具有带宽优先级管理的能力。带宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队时间的频率和下层连接(数据链路层)的带宽。

HTB:是Hierarchy Token Bucket(层次令牌桶)的缩写。通过在实践基础上的改进,它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽,虽然它也允许特定的类可以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。

 PRIO:qdisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用prio qdisc可以很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。为了方便管理,需要使用iptables或者ipchains处理数据包的服务类型(TOS)。   THEORY OF OPERATION(操作原理)  类(class)组成一个树,每个类只有一个父类,而一个类可以有多个子类。某些qdisc(例如:CBQ和HTB)允许在运行时动态添加类,而其它的qdisc (例如:PRIO)不允许动态建立类。    允许动态添加类的qdisc可以有零个或者多个子类,由它们为数据包排队。

此外每个类都有一个叶子qdisc,默认情况下,这个叶子qdisc使用pfifo的方式排队,我们也可以使用其它类型的qdisc代替这个默认的qdisc。而且, 这个叶子qdisc又可以分类,不过每个子类只能有一个叶子qdisc。    当一个数据包进入一个分类qdisc,它会被归入某个子类。我们可以使用以下三种方式为数据包归类,不过不是所有的qdisc都能够使用这三种方式。  

tc过滤器(tc filter)    如果过滤器附属于一个类,相关的指令就会对它们进行查询。过滤器能够匹配数据包头所有的域,也可以匹配由iptables或者ipchains做的   标记。   服务类型(type of service)    某些qdisc有基于服务类型的内置的规则为数据包分类。   skb->priority    用户空间的应用程序可以使用SO_PRIORITY选项在skb->priority域设置一个类的ID。   树的每个节点都可以有自己的过滤器,但是高层的过滤器也可以直接用于其子类。     如果数据包没有被成功归类,就会被排到这个类的叶子qdisc的队中。   NAMING(命名规则)  所有的qidsc、class、filter都有ID。ID可以手工设置,也可以由内核自动分配。  ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。   QDISC   一个qdisc会被分配一个主序列号,叫做句柄(handle),然后把从序列号作为类的命名空间句柄采用像10:一样的表达方式。习惯上,需要为   有子类的qdisc显示地分配一个句柄。  类(CLASS)   在同一个qdisc里面的类分享这个qdisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只于父qdisc有关,和  父类无关。类的命名习惯和qdisc的相同。

过滤器(FILTER)   过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。   UNIT(单位)  tc命令的所有参数都可以使用浮点数,可能会涉及到以下计数单位。   带宽或者流速单位:   kbps     mbps    kbit             kilobits per second   mbit            megabits per second    bps or a bare number(bps或者一个无单位数字)   bytes per second    数据的数量单位:   kb or k            kilobytes   mb or m           megabytes   mbit            megabits   kbit            kilobits   b or a bare number          bytes    时间的计量单位:   s, sec or secs           whole seconds  秒   ms, msec or msecs         milliseconds  毫秒   us, usec, usecs or a bare number       microseconds  微秒 

TC命令

 tc可以使用以下命令对qdisc、类和过滤器进行操作:    add   在一个节点里加入一个qdisc、类或者过滤器。添加时,需要传递一个parent作为参数,传递参数时既可以使用ID也可以直接传递设备的根。如  果要建立一个qdisc或者过滤器,可以使用句柄(handle)来命名;如果要建立一个类,可以使用类识别符(classid)来命名。  remove   删除有某个句柄(handle)指定的qdisc,根qdisc(root)也可以删除。被删除qdisc上的所有子类以及附属于各个类的过滤器都会被自动删除。  change    以替代的方式修改某些条目。除了句柄(handle)和parent不能修改以外,change命令的语法和add命令相同。换句话说,change命令不能改   变节点的位置。  replace    对一个现有节点进行近于atomic remove/add的操作。如果节点不存在,这个命令就会建立节点。   link    只是用于qdisc,替代一个现有的节点。   FORMAT  the show command had additional formatting options:  -s, -stats, -statistics   output more statistics about packet usage.  -d, -details   output more detailed information about rates and cell sizes.  -r, -raw   output raw hex values for handles.  -p, -pretty   decode filter offset and mask values to equivalent filter commands based on TCP/IP 

 

 

-iec   print rates in IEC units (ie. 1K=1024).    

TC命令参数 

一个CBQ qdisc类的根有如下参数:  

parent major:minor | root    这个命令的参数决定这个CBQ实例所在的位置,或者是在一个网络接口的根(root),或者位于一个现有的类里面。  

handle major:    和其他的qdisc一样,CBQ qdisc也可以指定一个句柄。句柄只能包含主识别号(major number)和一个冒号。数字的选择是随意的,不过如果在这个qdisc里面会继续分类,这个数字非常有用。 

 allot bytes     这个参数用于分配的带宽,决定数据包传输的时间表。qdisc的allot参数和类的allot参数略有不同。数字bytes是任意的。缺省是一个根据avpkt得到的数字。   avpkt bytes    数据包的平均大小,它用于计算最大空闲时间(maxidle),也用于确认allot参数的值是安全的。 

 bandwidth rate    为了决定空闲时间(idle time),CBQ必须知道底层物理接口的带宽,或者父qdisc的带宽。这是一个极为重要的参数。  

 cell time     time的值决定进行数据包传输时间计算的时间间隔。使用缺省值是比较明智的。  

mpu bytes    一个大小为0的数据包仍然会消耗时间来传输。用这个参数设置小于bytes个字节的数据包在进行传输时间的计算忽略不计,缺省值是0。  

 ewma log    在CBQ需要测量平均空闲使劲啊,它会使用加权指数移动平均算法来平滑测量的值,得到一个移动平均值。log决定平滑印子的大小。这个   数值介于0到31之间,数字越小敏感度越大。默认值是5。    一个CBQ qdisc只需要知道底层连接的大小,实际的带宽限制由其子类完成。 

CLASS的参数:   parent major:minor    确定父qidsc的位置,把这个类加入到树状结构中。如果它是直接附属于一个qdisc,而且这个qdisc没有其他的类,minor可以被忽略。   classid major:minor     和qdisc一样,类也可以命名。。这个参数是可选的,只有它还需要细分才需要。  

weight weight     在从队列中取出数据包通过网络接口向外发送时,CBQ会采用轮转的方式轮流从队列中取出属于不同分类的数据包。weight设置每个类的权重。权重越高,在每个循环CBQ取出的数据包也就越多。一个类中所有的权重都会被换算成与rate参数设定值的百分比。  

allot bytes     这个参数设置每个循环可以有多少个字节出队。这个值最小为avpkt的2/3。这个参数是必须的。  

avpkt bytes   rate rate     设置这个类可以达到的最大速率,以及所有子类速率总和可以达到的值。这个参数是必须的。 

 bandwidth rate     这个参数不同于建立CBQ时的bandwidth参数。只有在决定maxidle和offtime时才有用,在设置maxburst或者minburst时,CBQ会使用    maxidle和offtime进行计算。如果需要设置最大突发(maxburst)或者最小突发(minburst),这个参数是必须的。   maxburst    这个参数设置的数字用于计算maxidle,以便avgidle的值等于maxidle时,在avgidle达到0之前,允许设定的数据包突发性地通过。这个数字越大,对于突发流量的适应性越好。你不能直接设置maxidle,只能通过这个参数来设置。   minburst    在限制溢出(overlimit)情况下,CBQ需要调低带宽。为了避免这种情况的出现,比较理想的解决方案是精确地空闲某个时间,然后放行一个数据包。然而,对于UNIX内核来说,很难对时间间隔小于10ms的时间进行调度,因此只好把等待时间放长,接着突发性地放行多个数据包。    等待时间叫做offtime。minburst的值越高,在一个较长时间内进行的带宽限制越准确,但是也会导致更大的突发流量。

可选参数。   minidle       如果avgidle小于0,需要等待avgidle增加到一个足够大的值才能发送一个数据包。为了避免在一个长期处于关闭状态下的连接出现突发流

量,如果avgidle太低就会被复位为minidle参数设置的数值。    minidle的单位是负微秒,10表示avgidle不能低于-10微秒。

可选参数。   bounded    这个类的带宽不外借。  

isolated    这个类的带宽不愿意外借。    

split major:minor & defmap bitmap[/bitmap]    如果附属于这个类的过滤器不能判断数据包所属类别,CBQ也可以根据数据包的优先级为它们分类。优先级共有8个,范围是0到7。    defmap设置这个类接受具备哪些优先级的数据包,接受的优先级使用bitmap来计算,CBQ用bitmap和数据包的优先级域进行and运算。    最低有效位(least significant bit)对应优先级0。split告诉CBQ需要做出决定的类,参数应该是其父类。   BUGS    底层链路的带宽可能是无法预知的。CBQ对于主要的带宽配置错误有很大的弹性,代价可能就是带宽固定(shaping)精度降低。     默认情况下,内核依靠粗糙的计时信息进行带宽固定。在一个较长的时间段内,可以维持很好的精度,但是在以秒为单位进行计量的时间段内,其结果就不准确了。 

 

 

Linux TC 流量限速

 

 # !/bin/sh  touch  /var/lock/subsys/local  echo  1  > /proc/sys/net/ipv4/ip_forward   route add default  gw  10.0.0.0  (这是加入电信网关,如果你已设了不用这条)   DOWNLOAD=640Kbit    (640/8 =80K ,我这里限制下载最高速度只能80K) UPLOAD=640Kbit          (640/8 =80K,上传速度也限制在80K) INET=192.168.0.          (设置网段,根据你的情况填)  IPS=1                          (这个意思是从192.168.0.1开始)  IPE=200                        (我这设置是从IP为192.168.0.1-200这个网段限速,根据自已的需要改)  ServerIP=253                (网关IP) IDEV=eth0 ODEV=eth1   /sbin/tc  qdisc  del  dev  $IDEV root handle 10: /sbin/tc  qdisc  del  dev  $ODEV  root handle  20: /sbin/tc  qdisc  add  dev $IDEV  root  handle  10: cbq  bandwidth  100Mbit avpkt  1000  /sbin/tc  qdisc  add  dev  $ODEV  root  handle  20: cbq bandwidth  1Mbit  avpkt  1000  /sbin/tc  class  add  dev $IDEV  parent  10:0  classid  10:1  cbq  bandwidth  100Mbit  rate 100Mbit  allot 1514  weight  1Mbit  prio  8  maxburst  20  avpkt  1000  /sbin/tc  class  add  dev  $ODEV  parent  20:0  classid  20:1  cbq  bandwidth  1Mbit  rate  1Mbit  allot  1514  weitht  10Kbit  prio  8  maxburst  20  avpkt  1000

COUNTER=$IPS  while  [  $COUNTER  -le  $IPE  ]     do  /sbin/tc  class  add  dev  $IDEV  parent  10:1  classid  10:1$COUNTER  cbq  banwidth  100Mbit  rate    $DOWNLOAD  allot  1514  weight  20Kbit  prio  5  maxburst  20  avpkt  1000  bounded  /sbin/tc  qdisc  add  dev  $IDEV  parent  10:1$COUNTER  sfq  quantum  1514b  perturb15   /sbin/tc  filter  add  dev  $IDEV  parent  10:0  protocol  ip  prio  100  u32  match  ipdst  $INET$COUNTER  flowid  10:1$COUNTER 

COUNTER=` expr  $COUNTER  +  1  ` done   iptables  -t  nat  -A  POSTROUTING  -o  eth1  -s  192.168.0.0/24  -J  MASQUERADE   HTB官方网站:http://luxik.cdi.cz/~devik/qos/htb/   LINUX HTB队列规定用户指南   HTB Linux queuing discipline manual - user guide Martin Devera aka devik ([email protected]) Manual: devik and Don Cohen Last updated: 5.5.2002   译者:龚关 [email protected] 1. Introduction 介绍  2. Link sharing 链路共享   3. Sharing hierarchy 共享层次  4. Rate ceiling 速率限度  5. Burst 突发   6. Priorizing bandwidth share 带宽分配优先  7. Understanding statistics 查看统计   8. Making, debugging and sending error reports 开发,调试和错误报告    

 1. Introduction 介绍

HTB 意味着是一个更好理解更容易掌握的可以快速替换LINUX CBQ 队列规定的队列, CBQ和HTB都可以帮助你限制你的链路上的出口带宽;他们允许你把一条物理链路模拟成几条更慢的链路或者是把发出的不同类型的流量模拟成不同的连接,在 他们的实际应用中, 你必须指定怎么分配物理链路给各种不同的带宽应用并且如何判断每种不同的应用的数据包是怎么样被发送的;    这篇文章将告诉你怎么使用 HTB . 这里有很多的例子和分析图以及一些特殊问题的讨论.  这个HTB的发布版本已经有更多的升级, 详细情况请看HTB 的主页.  请先查阅: TC 工具 (不仅仅是HTB ) 有关速率的单位换算: kbps = kilo bytes kbit = kilo bits    

2. Link sharing 链路共享  

案例: 我们有两不同的用户A和B, 都通过网卡 eth0 连接到 internet ,我们想分配 60 kbps的带宽给B 和 40 kbps的带宽给A, 接下来我们想对A用户的带宽再做一个分配, 给30 kbps的带宽给WWW服务, 10 kbps的带宽给其他用途; 任何没有用的带宽可以分配和其他需要带宽类 (在分配的总带宽允许的范围内的部分)    HTB 可以保障提供给每个类带宽的数量是它所需求的最小需求或者等于分配给它的数量.当一个类需要的带宽少于分配的带宽时,剩余的带宽被分配给其他需要服务的类.   注: 这里这种情况被称为”借用”剩余带宽, 我们以后将用这个术语, 但无论如何,好像很不好因为这个”借用”是没有义务偿还的.       上面所提到的不同类型的流量在HTB里表现为类, 上面是一个简单的分布图.   我们来看看所用到的命令:   tc qdisc add dev eth0 root handle 1: htb default 12  这条命令分配了HTB队列规定给 eth0 并且指定了一个名称为(handle" 1 句柄 1: , 这个名称用于标识它下面的子类, default 12 的意思是没有被分类的流量被分配到类 1:12   注: 一般 (不仅仅是HTB其他所有TC的队列和类),句柄都被写成 X:Y 这里X是队列规定的整数型的标识符,Y是这个队列规定的类的整数型标识符,队列规定的句柄标识符的Y必须是0,而句柄的类的标识符的数值必须是一个非零的 整数. "1:" 等同于 "1:0".

tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps  tc class add dev eth0 parent 1:1 classid 1:10 htb rate 30kbps ceil 100kbps tc class add dev eth0 parent 1:1 classid 1:11 htb rate 10kbps ceil 100kbps tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps   第一行在队列1:下创建了一个根类1:1,并且定义了HTB队列规定作为这个根类的父类,一个根类可以像队列规定下其他类一样允许它的子类相互借用带宽, 但是根类之间不能相互借用带宽,我们可以在HTB队列下直接创建三个类,但是其中一个类的剩余带宽不能够借用给其他需要的类,在这种情况下我们想允许带宽 借用,所以我们为根类创建扩展类并且让这些类在根类的范围内发送数据,我们定义了下面的三行, ceil参数我们在以后将讲述.   注: 有时候人们会问我为什么他们必须重复dev eth0 描述在他们已经定义并使用了handle 或者parent ,原因是本地接口比如eth0 和eth1他们各自都可能会有类的句柄表示为1:1.

我们还必须描述那些数据包属于那个类, 有关详细内容请查看有关TC 过虑器的相关文档. 命令看起来像下面这样:   tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 match ip dport 80 0xffff flowid 1:10  tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip src 1.2.3.4 flowid 1:11  (We identify A by its IP address which we imagine here to be 1.2.3.4.)    (我们根据它的IP地址进行分类识别,这里我们假设为1.2.3.4)   注:U32过虑器有一个非文档化的设计会导致在你使用U32分类器”tc filter show”命令时会显示出不同的prio的值.    你可能会注意到我们没有为类1:12创建过虑, 很明显,这个例子中被用作缺省, 就是没有被上面两条分类规则定义的任何数据包 (任何原地址非1.2.3.4)将被发送到类1:12   现在我们可以很方便的为队列规定分配子类, 如果没有指定缺省是pfifo   tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 5 tc qdisc add dev eth0 parent 1:11 handle 30: pfifo limit 5 tc qdisc add dev eth0 parent 1:12 handle 40: sfq perturb 10

这是我们所需要的全部命令, 让我们来看看有什么事情发如果我们给每个类发送90kbps的数据然后停止发送其中一个类在某一时刻.在图的底部标有"0:90k". 标签中央水平位置 (在9附近.同时标有红色1)现实了数据流量随时间的变化情况.冒号之前是类的标识符;(0表示类1:10, 1 表示类 1:11, 2 表示类 1:12)冒号之后是新的速率在那个时间有标注. 比如类0在时间0的时候速率改变为90K 在时间3为0K (0= 0k) ,在时间6时返回90K;   最初所有的类共同流量为90kb. 以后以被指定更高的速度传输, 每一个类都被限制在其被指定的速率, 在时间3的时候我们停止传送类0的数据, 分配给类0的速率被分配给其他两个类.如图所示1至6内的类1和类2 (很难看出类1的增长因为它只有4kbps.) 同样在时间9时类1流量停止它的带宽被分配到另外两个类(类0的增长同样很难看出), 在时间15类2被分配给类0和类1, 在时间18 类1和类2 同时停止,所以类0得到它所需要的所有90 kbps.带宽.   现在是个接触quantums概念的很好的时机.实际上当一些想借用带宽的类服务

 

于其他竞争的类之前相互给定的一定数量的字节, 这个数量被称为quantums . 你应该明白如果一些竞争的类是可以从它的父类那里得到所需的quantums; 精确的指定quantums的数量尽可能的小并其大于MTU是很重要的.   一般你不需要手工指定一个quantums因为HTB会根据计算选择数值.计算类的quantum相对于用r2q参数分配; 它的缺省的值是10因为典型的MTU是1500,缺省值很适合速率为15 kBps (120 kbit).当你创建队列最小的速率指定r2q 1, 比较适合速率为12 kbit;如果你需要手工指定quantum 当你添加或者更改类,如果预想计算的值是不适合的你可以清除日志里的警告. 当你用命令行指定了quantum 类的r2q将被忽略.   如果A和B是不同的客户这个解决方案看起来很好, 但是如果A 付了40kbps 他可能更希望他不用的WWW的带宽可以用在自己的其他服务上而并不想分享个B. 这种需求是可以通过HTB的类的层次得到解决的.  

 3. Sharing hierarchy 共享层次   前面章节的问题在这一节里通过类层次结构来得到解决, 用户A 可以很清楚的表达自己的类; 回到前面我们说过提供给每个类带宽的数量是它所需求的最小需求或者等于分配给它的数量. 这样可以用在其他非父类的HTB类里. 我们叫他们为子类, 对于HTB的父类来说我们称为内部类, 规则是使用服务的总量最小而且总量等于他的子类所请求的总和.这里我们分配40kbps给用户A ,这就意味着如果A的需求少于分配的WWW带宽, 那么剩下的将被用来服务于A的其他应用.(如果有需要), 至少总和为40kbps.

 

注:数据包的分类规则可以分配给内部节点, 也可以有分配其他的过虑器给内部节点,最终应该到达子类或者是特定的类class 1:0 父类提供的速率应该是它所有子类的总和.   现在的命令如下: 

tc class add dev eth0 parent 1: classid 1:1 htb rate 100kbps ceil 100kbps

tc class add dev eth0 parent 1:1 classid 1:2 htb rate 40kbps ceil 100kbps

tc class add dev eth0 parent 1:2 classid 1:10 htb rate 30kbps ceil 100kbps

tc class add dev eth0 parent 1:2 classid 1:11 htb rate 10kbps ceil 100kbps

tc class add dev eth0 parent 1:1 classid 1:12 htb rate 60kbps ceil 100kbps  

我们现在来看看流量图显示的我们用层次结构的解决方案. 当A的WWW流量停止, 它所分配的带宽被二次分配到它的其他流量上, 所以A的总带宽仍然为40kbps.如果A的总请求带宽小于40kbps.那么剩余的流量将被分配给B.  

4. Rate ceiling 速率限度  

参数ceil指定了一个类可以用的最大带宽, 用来限制类可以借用多少带宽.缺省的ceil是和速率一样.(也是我们为什么必须在上面的例子里指定它用来显示借用带宽的上限)我们改变前面例子里的类 1:2 (A) 和1:11 (A's other) ceil 100kbps 分别为ceil 60kbps 和ceil 20kbps.       和前面的图显示不同, 在时间3 (WWW 流量停止) 因为A 的其他流量限制在20kbps. 所以用户A得到仅仅总带宽20kbps没有用的20kbps被分配给了B .   第二个不同是在时间15时B停止, 因为没有ceil, 所有它的带宽被给了A , 但是现在A 仅仅允许使用60kbps,所以剩余的40kbps 闲置.   这个特性对于ISP是很有用的, 因为他们一般限制被服务的用户的总量即使其他用户没有请求服务.(ISPS 很想用户付更多的钱得到更好的服务) ,注根类是不允许被借用的, 所以没有指定ceil   注: ceil的数值应该至少和它所在的类的速率一样高, 也就是说ceil应该至少和它的任何一个子类一样高   

 5. Burst 突发

网络硬件只能在一个时间发送一个包这仅仅取决于一个硬件的速率. 链路共享软件可以利用这个能力动态产生多个连接运行在不同的速度. 所以速率和ceil不是一个即时度量只是一个在一个时间里发送包的平均值. 实际的情况是怎样使一个流量很小的类在某个时间类以最大的速率提供给其他类. burst 和 cburst 参数控制多少数据可以以硬件最大的速度不费力的发送给需要的其他类.   如果cburst 小于一个理论上的数据包他形成的突发不会超过ceil 速率, 同样的方法TBF的最高速率也是这样.   你可能会问, 为什么需要bursts . 因为它可以很容易的提高向应速度在一个很拥挤的链路上. 比如WWW 流量是突发的. 你访问主页. 突发的获得并阅读. 在空闲的时间burst将再"charge"一次.

注: burst 和cburst至少要和其子类的值一样大.         如图, 接着前一章的例子,我改变burst给红和黄(agency A)类20 kb但cburst仍然为缺省(cca 2 kb).绿色的峰出现在时间13由于在SMTP类设置了burst;A类在限度下自从时间9并且聚集了20 kb的突发流量,峰高于20 kbps(被ceil参数限制因为它的cburst接近包的尺寸),聪明的读者可能会问为什么在时间7处没有红色和黄色的峰;因为黄色已经接近ceil所 以没有空间用于突发;有一个不必要的人为的低谷在时间4, 那是因为我忘记添加burst 给根连接到(1:1)类;峰从时间1并且当时间4蓝色的类想借用黄色的速率被拒绝并且自己补偿;    局限性: 当你在计算机上用一个小的时间片操作一个高速链路 你需要为所有的类设置很小的burst 和cburst . 在i386系统上是10ms 在Alphas.系统是1ms ;最小的burst可以max_rate*timer 被估算出来; 所以10Mbit的速率在i386 系统上 burst为 12kb   如果你设置太小的burst 你可能会得到比你设置更小的速率, 后来TC 工具在你没有指定burst.时将估计并且设置一个最小且可能的burst.   

6. Priorizing bandwidth share 带宽分配优先  

带宽分配的优先级包括两个方面, 首先它影响到子类剩余带宽的分配, 到现在我们已经知道剩余带宽按照速率比例来分配, 我以第三节的配置为例(没有设置ceiling 和 bursts的层次结构 )除了SMTP (green)的优先权改为0(更高) 其他所以类都改为1       从视图我们可以看到类得到了所有剩余带宽, 规则是优先权越高的类越优先得到剩余带宽., 但必须是在rate 和 ceil得到保障的前提下.   另一个方面的问题,包的延时, 在以太网里的延时度量是很困难的,但有一个简单的办法.我们添加一个带宽小于100 kbps的HTB类.第二个类(我们测量的)作为一个子类,然后我们模仿成更慢并且延时比较大的链路.    出于简单的原因, 我们用两个有关联的类;  

# qdisc for delay simulation  tc qdisc add dev eth0 root handle 100: htb

tc class add dev eth0 parent 100: classid 100:1 htb rate 90kbps 

 # real measured qdisc 

tc qdisc add dev eth0 parent 100:1 handle 1: htb AC="tc class add dev eth0 parent" $AC 1: classid 1:1 htb rate 100kbps  $AC 1:2 classid 1:10 htb rate 50kbps ceil 100kbps prio 1 $AC 1:2 classid 1:11 htb rate 50kbps ceil 100kbps prio 1 tc qdisc add dev eth0 parent 1:10 handle 20: pfifo limit 2 tc qdisc add dev eth0 parent 1:11 handle 21: pfifo limit 2 

注: 另一个HTB的子类和同一个HTB内的子类是不一样的, 因为HTB的类发送数据和硬件发送能力一样的, 所以在限度以内的数据发送仅仅取决于设备速度而不是上级类; HTB下的HTB类输出是模拟一个逻辑硬件; (大的延时)   假定速率同为50 kbps的两个类在时间3S 时执行命令如下: 

 tc class change dev eth0 parent 1:2 classid 1:10 htb rate 50kbps ceil 100kbps burst 2k prio 0      

你可以看到WWW的延时趋近于0而SMTP的延时增大. 当你的优先级别更高而其他类的延时就更大.稍后在7S 时,模仿WWW以60 kbps和SMTP 以40 kbps.发送数据.你可以看到另一个有趣的现象.当WWW越限之后HTB首先是限制带宽.   什么样的类需要优先权? 一般需要延时低的类; 比如视频和音频流; (你必须使用正确的流量速率防止流量相互淹没. ) 或者是交互性(TELNET .SSH )流量正常突发并且不影响其他的流量. 

提高ICMP的优先权可以得到一个很好的PING的延时返回, 但这是一个假相, 因为从技术角度来说在测试联通性时这种情况并不是你想要的.   

 7. Understanding statistics 查看统计  

TC 工具允许你对LINUX队列规定进行统计; 不幸的是统计结果作者没有解释所以你不能经常用到他们; 这里我尽力解释来帮助理解HTB的状态; 首先是HTB的整体状态.

下面是第三节里的一个片段;  

# tc -s -d qdisc show dev eth0 qdisc pfifo 22: limit 5p 

Sent 0 bytes 0 pkts (dropped 0, overlimits 0)  

 qdisc pfifo 21: limit 5p  Sent 2891500 bytes 5783 pkts (dropped 820, overlimits 0)   

qdisc pfifo 20: limit 5p  Sent 1760000 bytes 3520 pkts (dropped 3320, overlimits 0)  

 qdisc htb 1: r2q 10 default 1 direct_packets_stat 0  Sent 4651500 bytes 9303 pkts (dropped 4140, overlimits 34251)  

 前三个规定是HTB的子队列, 我们跳过他们因为PFIFO的状态是自我解释的. Overlimit告诉你有多少次队列延时了数据包; direct_packets_stat 告诉你有多少包直接通过队列被送出; 其他的解释是自我解释型的, 让我们看看类的状态;   tc -s -d class show dev eth0  class htb 1:1 root prio 0 rate 800Kbit ceil 800Kbit burst 2Kb/8 mpu 0b  cburst 2Kb/8 mpu 0b quantum 10240 level 3   Sent 5914000 bytes 11828 pkts (dropped 0, overlimits 0)  rate 70196bps 141pps   lended: 6872 borrowed: 0 giants: 0   class htb 1:2 parent 1:1 prio 0 rate 320Kbit ceil 4000Kbit burst 2Kb/8 mpu 0b   cburst 2Kb/8 mpu 0b quantum 4096 level 2   Sent 5914000 bytes 11828 pkts (dropped 0, overlimits 0) 

rate 70196bps 141pps   lended: 1017 borrowed: 6872 giants: 0   class htb 1:10 parent 1:2 leaf 20: prio 1 rate 224Kbit ceil 800Kbit burst 2Kb/8 mpu 0b   cburst 2Kb/8 mpu 0b quantum 2867 level 0   Sent 2269000 bytes 4538 pkts (dropped 4400, overlimits 3635  rate 14635bps 29pps   lended: 2939 borrowed: 1599 giants: 0    我删除了类1:11 和 1:12 以便输出更简单扼要; 可以看到有我们设置的参数, 还有level 和 DRR quantum 信息;    overlimits 显示了有多少次类要求被发送数据而被rate/ceil 限制不能发送;(现在显示的仅仅是子类)

rate, pps 告诉你通过类实际的速率(10秒的平均值) 他和你选择的速率是一样的.   Lended 这个类借出的包  borrowed 则是被借入的数据包从父类;   Giants 显示了大于TC命令设置的MTU的数据包的数量;HTB和其协调工作,否则将会影响速率的精确性,, 添加 MTU 到你的TC命令里 (缺省是1600 bytes)  

8. Making, debugging and sending error reports 开发, 调试和发送错误报告  如果你拥有kernel 2.4.20或者更新的内核你就不必要打补丁, 但你需要更新TC 工具从HTB 3.6 包里得到并且使用它;   为了和老内核工作协调, 下载内核源码, 用patch -p1 -i htb3_2.X.X.diff装载补丁程序, 然后用 make menuconfig;make bzImage; 编译内核时不要忘了选中QoS 和 HTB.   我将非常感激如果你认为在使用发现了HTB错误. 我需要详细的输出; 在队列规定出现异常行为时请在tc qdisc add .... htb.后面加上参数debug 3333333 ; 它将会在系统日志里记录一些调试记录,为此你可能需要在你的 /etc/syslog.conf. 文件里加上kern.debug -/var/log/debug这一行. 通过压缩包电邮给我,并且付上问题描述和时间.  名称:tc - 显示/维护流量控制设置  命令格式:  

tc qdisc [ add | change | replace | link ] dev DEV [ parent qdisc-id | root ] [ handle qdisc-id ] qdisc [ qdisc specific parameters ]    tc class [ add | change | replace ] dev DEV parent qdisc-id [ classid class-id ] qdisc [ qdisc specific parameters ]    tc filter [ add | change | replace ] dev DEV [ parent qdisc-id | root ] protocol protocol prio priority filtertype [ filtertype specific parameters ] flowid flow-id    tc [-s | -d ] qdisc show [ dev DEV ]    tc [-s | -d ] class show dev DEV tc filter show dev DEV     TC用途简介:     Tc用于Linux内核的流量控制。

 

流量控制包括以下几种方式:    SHAPING(限制)  当流量被限制,它的传输速率就被控制在某个值以下。限制值可以大大小于有效带宽,这样可以平滑突发数据流量,使网络更为稳定。shaping(限制)只适用于向外的流量。    SCHEDULING(调度)   通过调度数据包的传输,可以在带宽范围内,按照优先级分配带宽。SCHEDULING(调度)也只适于向外的流量。    POLICING(策略)   SHAPING用于处理向外的流量,而POLICIING(策略)用于处理接收到的数据。    DROPPING(丢弃)   如果流量超过某个设定的带宽,就丢弃数据包,不管是向内还是向外。    流量的处理由三种对象控制,它们是:qdisc(排队规则)、class(类别)和filter(过滤器)。    QDISC(排队规则)   QDisc(排队规则)是queueing discipline的简写,它是理解流量控制(traffic control)的基础。无论何时,内核如果需要通过某个网络接口发送数据包,它都需要按照为这个接口配置的qdisc(排队规则)把数据包加入队列。然 后,内核会尽可能多地从qdisc里面取出数据包,把它们交给网络适配器驱动模块。  最简单的QDisc是pfifo它不对进入的数据包做任何的处理,数据包采用先入先出的方式通过队列。不过,它会保存网络接口一时无法处理的数据包。 

CLASS(类)   某些QDisc(排队规则)可以包含一些类别,不同的类别中可以包含更深入的QDisc(排队规则),通过这些细分的QDisc还可以为进入的队列的数据包排队。通过设置各种类别数据包的离队次序,QDisc可以为设置网络数据流量的优先级。    FILTER(过滤器)   filter(过滤器)用于为数据包分类,决定它们按照何种QDisc进入队列。无论何时数据包进入一个划分子类的类别中,都需要进行分类。分类的方法可 以有多种,使用fileter(过滤器)就是其中之一。使用filter(过滤器)分类时,内核会调用附属于这个类(class)的所有过滤器,直到返回 一个判决。如果没有判决返回,就作进一步的处理,而处理方式和QDISC有关。   需要注意的是,filter(过滤器)是在QDisc内部,它们不能作为主体。  

CLASSLESS QDisc(不可分类QDisc)  无类别QDISC包括:  [p|b]fifo   使用最简单的qdisc,纯粹的先进先出。只有一个参数:limit,用来设置队列的长度,pfifo是以数据包的个数为单位;bfifo是以字节数为单位。  pfifo_fast  在编译内核时,如果打开了高级路由器(Advanced Router)编译选项,pfifo_fast就是系统的标准QDISC。它的队列包括三个波段(band)。在每个波段里面,使用先进先出规则。而三个 波段(band)的优先级也不相同,band 0的优先级最高,band 2的最低。如果band里面有数据包,系统就不会处理band 1里面的数据包,band 1和band 2之间也是一样。数据包是按照服务类型(Type of Service,TOS)被分配多三个波段(band)里面的。  red   red是Random Early Detection(随机早期探测)的简写。如果使用这种QDISC,当带宽的占用接近于规定的带宽时,系统会随机地丢弃一些数据包。它非常适合高带宽应用。  sfq   sfq是Stochastic Fairness Queueing(随机公平队列)的简写。是公平队列算法家族中的一个简单实现.它的精确性不如其它的方法,但是它在实现高度公平的同时,需要的计算量却很少.   它按照会话(session--对应于每个TCP连接或者UDP流)为流量进行排序,然后循环发送每个会话的数据包。  SFQ的关键词是"会话"(或称作"流") ,主要针对一个TCP会话或者UDP流.流量被分成相当多数量的FIFO队列中,每个队列对应一个会话.数据按照简单轮转的方式发送, 每个会话都按顺序得到发送机会.   这种方式非常公平,保证了每一个会话都不会没其它会话所淹没.SFQ之所以被称为"随机",是因为它并不是真的为每一个会话创建一个队列,而是使用一个散列算法,把所有的会话映射到有限的几个队列中去.  

因为使用了散列,所以可能多个会话分配在同一个队列里,从而需要共享发包的机会,也就是共享带宽.为了不让这种效应太明显,SFQ会频繁地改变散列算法,以便把这种效应控制在几秒钟之内.   有很重要的一点需要声明:只有当你的出口网卡确实已经挤满了的时候,SFQ才会起作用!否则在你的Linux机器中根本就不会有队列,SFQ也就不会起作用. 稍后我们会描述如何把SFQ与其它的队列规定结合在一起,以保证两种情况下都比较好的结果.   特别地,在你使用DSL modem或者cable modem的以太网卡上设置SFQ而不进行任何进一步地流量整形是无谋的!  参数与使用   SFQ基本上不需要手工调整:  perturb   多少秒后重新配置一次散列算法.如果取消设置,散列算法将永远不会重新配置(不建议这样做).10秒应该是一个合适的值.  quantum   一个流至少要传输多少字节后才切换到下一个队列.却省设置为一个最大包的长度(MTU的大小).不要设置这个数值低于MTU!   配置范例   如果你有一个网卡,它的链路速度与实际可用速率一致——比如一个电话MODEM——如下配置可以提高公平性:   # tc qdisc add dev ppp0 root sfq perturb 10  # tc -s -d qdisc ls   qdisc sfq 800c: dev ppp0 quantum 1514b limit 128p flows 128/1024 perturb 10sec   Sent 4812 bytes 62 pkts (dropped 0, overlimits 0)   "800c:"这个号码是系统自动分配的一个句柄号,"limit"意思是这个队列中可以有128个数据包排队等待.一共可以有1024个散列目标可以用于速率审计, 而其中128个可以同时激活.(no more packets fit in the queue!)每隔10秒种散列算法更换一次.   tbf   tbf是Token Bucket Filter(令牌桶过滤器)的简写,适合于把流速降低到某个值。令牌桶过滤器(TBF)是一个简单的队列规定:只允许以不超过事先设定的速率到来的数据包通过,但可能允许短暂突发流量朝过设定值.   TBF很精确,对于网络和处理器的影响都很小.所以如果您想对一个网卡限速,它应该成为您的第一选择!   TBF的实现在于一个缓冲器(桶),不断地被一些叫做"令牌"的虚拟数据以特定速率填充着. (token rate).桶最重要的参数就是它的大小,也就是它能够存储令牌的数量.   每个到来的令牌从数据队列中收集一个数据包,然后从桶中被删除.这个算法关联到两个流上——令牌流和数据流,于是我们得到3种情景:   数据流以等于令牌流的速率到达TBF.这种情况下,每个到来的数据包都能对应一个令牌,然后无延迟地通过队列.   数据流以小于令牌流的速度到达TBF.通过队列的数据包只消耗了一部分令牌,剩下的令牌会在桶里积累下来,直到桶被装满.剩下的令牌可以在需要以高于令牌流速率发送数据流的时候消耗掉,这种情况下会发生突发传输.  

数据流以大于令牌流的速率到达TBF.这意味着桶里的令牌很快就会被耗尽.导致TBF中断一段时间,称为"越限".如果数据包持续到来,将发生丢包.   最后一种情景非常重要,因为它可以用来对数据通过过滤器的速率进行整形. 令牌的积累可以导致越限的数据进行短时间的突发传输而不必丢包,但是持续越限的话会导致传输延迟直至丢包.   请注意,实际的实现是针对数据的字节数进行的,而不是针对数据包进行的.  参数与使用   即使如此,你还是可能需要进行修改,TBF提供了一些可调控的参数.第一个参数永远可用:   limit/latency   limit确定最多有多少数据(字节数)在队列中等待可用令牌.你也可以通过设置latency参数来指定这个参数,latency参数确定了一个包在TBF中等待传输的最长等待时间.后者计算决定桶的大小,速率和峰值速率. 

burst/buffer/maxburst   桶的大小,以字节计.这个参数指定了最多可以有多少个令牌能够即刻被使用.通常,管理的带宽越大,需要的缓冲器就越大.在Intel体系上,10兆bit/s的速率需要至少10k字节的缓冲区才能达到期望的速率.   如果你的缓冲区太小,就会导致到达的令牌没有地方放(桶满了),这会导致潜在的丢包.  mpu   一个零长度的包并不是不耗费带宽.比如以太网,数据帧不会小于64字节.Mpu(Minimum Packet Unit,最小分组单位)决定了令牌的最低消耗.  rate   速度操纵杆.参见上面的limits!   如果桶里存在令牌而且允许没有令牌,相当于不限制速率(缺省情况).If the bucket contains tokens and is allowed to empty, by default it does so at infinite speed.   如果不希望这样,可以调整入下参数:  peakrate   如果有可用的令牌,数据包一旦到来就会立刻被发送出去,就象光速一样.那可能并不是你希望的,特别是你有一个比较大的桶的时候.   峰值速率可以用来指定令牌以多块的速度被删除.用书面语言来说,就是:释放一个数据包,但后等待足够的时间后再释放下一个.我们通过计算等待时间来控制峰 值速率然而,由于UNIX定时器的分辨率是10毫秒,如果平均包长10k bit,我们的峰值速率被限制在了1Mbps.  mtu/minburst   但是如果你的常规速率比较高,1Mbps的峰值速率对我们就没有什么价值.要实现更高的峰值速率,可以在一个时钟周期内发送多个数据包.最有效的办法就是:再创建一个令牌桶!  

这第二个令牌桶缺省情况下为一个单个的数据包,并非一个真正的桶.要计算峰值速率,用mtu乘以100就行了. (应该说是乘以HZ数,Intel体系上是100,Alpha体系上是1024)  配置范例   这是一个非常简单而实用的例子:   # tc qdisc add dev ppp0 root tbf rate 220kbit latency 50ms burst 1540  为什么它很实用呢?如果你有一个队列较长的网络设备,比如DSL modem或者cable modem什么的,并通过一个快速设备(如以太网卡)与之相连,你会发现上载数据绝对会破坏交互性.   这是因为上载数据会充满modem的队列,而这个队列为了改善上载数据的吞吐量而设置的特别大.但这并不是你需要的,你可能为了提高交互性而需要一个不太大的队列.也就是说你希望在发送数据的时候干点别的事情.   上面的一行命令并非直接影响了modem中的队列,而是通过控制Linux中的队列而放慢了发送数据的速度.   把220kbit修改为你实际的上载速度再减去几个百分点.如果你的modem确实很快,就把"burst"值提高一点.  

关于什么时候用哪种队列的建议   总之,我们有几种简单的队列,分别使用排序,限速和丢包等手段来进行流量整形.  下列提示可以帮你决定使用哪一种队列.涉及到了第14章 所描述的的一些队列规定:   如果想单纯地降低出口速率,使用令牌桶过滤器.调整桶的配置后可用于控制很高的带宽.   如果你的链路已经塞满了,而你想保证不会有某一个会话独占出口带宽,使用随机公平队列.   如果你有一个很大的骨干带宽,并且了解了相关技术后,可以考虑前向随机丢包(参见"高级"那一章).   如果希望对入口流量进行"整形"(不是转发流量),可使用入口流量策略,注意,这不是真正的"整形".   如果你正在转发数据包,在数据流出的网卡上应用TBF.除非你希望让数据包从多个网卡流出,也就是说入口网卡起决定性作用的时候,还是使用入口策略.  如果你并不希望进行流量整形,只是想看看你的网卡是否有比较高的负载而需要使用队列,使用pfifo队列(不是pfifo_fast).它缺乏内部频道但是可以统计backlog.   最后,你可以进行所谓的"社交整形".你不能通过技术手段解决一切问题.用户的经验技巧永远是不友善的.正确而友好的措辞可能帮助你的正确地分配带宽!   不可分类QDisc的配置  如果没有可分类QDisc,不可分类QDisc只能附属于设备的根。它们的用法如下:  tc qdisc add dev DEV root QDISC QDISC-PARAMETERS    要删除一个不可分类QDisc,需要使用如下命令:    tc qdisc del dev DEV root    一个网络接口上如果没有设置QDisc,pfifo_fast就作为缺省的QDisc。

CLASSFUL QDISC(分类QDisc)  可分类的QDisc包括:  CBQ   CBQ是Class Based Queueing(基于类别排队)的缩写。它实现了一个丰富的连接共享类别结构,既有限制(shaping)带宽的能力,也具有带宽优先级管理的能力。带 宽限制是通过计算连接的空闲时间完成的。空闲时间的计算标准是数据包离队事件的频率和下层连接(数据链路层)的带宽。  HTB   HTB是Hierarchy Token Bucket的缩写。通过在实践基础上的改进,它实现了一个丰富的连接共享类别体系。使用HTB可以很容易地保证每个类别的带宽,虽然它也允许特定的类可 以突破带宽上限,占用别的类的带宽。HTB可以通过TBF(Token Bucket Filter)实现带宽限制,也能够划分类别的优先级。  PRIO  

PRIO QDisc不能限制带宽,因为属于不同类别的数据包是顺序离队的。使用PRIO QDisc可以很容易对流量进行优先级管理,只有属于高优先级类别的数据包全部发送完毕,才会发送属于低优先级类别的数据包。为了方便管理,需要使用 iptables或者ipchains处理数据包的服务类型(Type Of Service,ToS)。  操作原理   类(Class)组成一个树,每个类都只有一个父类,而一个类可以有多个子类。某些QDisc(例如:CBQ和HTB)允许在运行时动态添加类,而其它的QDisc(例如:PRIO)不允许动态建立类。   允许动态添加类的QDisc可以有零个或者多个子类,由它们为数据包排队。    此外,每个类都有一个叶子QDisc,默认情况下,这个叶子QDisc使用pfifo的方式排队,我们也可以使用其它类型的QDisc代替这个默认的QDisc。而且,这个叶子叶子QDisc有可以分类,不过每个子类只能有一个叶子QDisc。    当一个数据包进入一个分类QDisc,它会被归入某个子类。我们可以使用以下三种方式为数据包归类,不过不是所有的QDisc都能够使用这三种方式。    tc过滤器(tc filter)  如果过滤器附属于一个类,相关的指令就会对它们进行查询。过滤器能够匹配数据包头所有的域,也可以匹配由ipchains或者iptables做的标记。  服务类型(Type of Service)   某些QDisc有基于服务类型(Type of Service,ToS)的内置的规则为数据包分类。   skb->priority   用户空间的应用程序可以使用SO_PRIORITY选项在skb->priority域设置一个类的ID。  

 

树的每个节点都可以有自己的过滤器,但是高层的过滤器也可以直接用于其子类。   如果数据包没有被成功归类,就会被排到这个类的叶子QDisc的队中。相关细节在各个QDisc的手册页中。     命名规则   所有的QDisc、类和过滤器都有ID。ID可以手工设置,也可以有内核自动分配。  ID由一个主序列号和一个从序列号组成,两个数字用一个冒号分开。     QDISC   一个QDisc会被分配一个主序列号,叫做句柄(handle),然后把从序列号作为类的命名空间。句柄采用象10:一样的表达方式。习惯上,需要为有子类的QDisc显式地分配一个句柄。    类(CLASS)   在同一个QDisc里面的类分享这个QDisc的主序列号,但是每个类都有自己的从序列号,叫做类识别符(classid)。类识别符只与父QDisc有关,和父类无关。类的命名习惯和QDisc的相同。    过滤器(FILTER)   过滤器的ID有三部分,只有在对过滤器进行散列组织才会用到。详情请参考tc-filters手册页。  单位   tc命令的所有参数都可以使用浮点数,可能会涉及到以下计数单位。  带宽或者流速单位:    kbps   千字节/秒  mbps   兆字节/秒  kbit   KBits/秒  mbit   MBits/秒   bps或者一个无单位数字  字节数/秒   数据的数量单位:    kb或者k  千字节  mb或者m  兆字节  mbit  兆bit 

kbit  千bit   b或者一个无单位数字  字节数   时间的计量单位:  s、sec或者secs  秒   ms、msec或者msecs  分钟   us、usec、usecs或者一个无单位数字  微秒    TC命令   tc可以使用以下命令对QDisc、类和过滤器进行操作:  add   在一个节点里加入一个QDisc、类或者过滤器。添加时,需要传递一个祖先作为参数,传递参数时既可以使用ID也可以直接传递设备的根。如果要建立一个 QDisc或者过滤器,可以使用句柄(handle)来命名;如果要建立一个类,可以使用类识别符(classid)来命名。    remove   删除有某个句柄(handle)指定的QDisc,根QDisc(root)也可以删除。被删除QDisc上的所有子类以及附属于各个类的过滤器都会被自动删除。    change   以替代的方式修改某些条目。除了句柄(handle)和祖先不能修改以外,change命令的语法和add命令相同。换句话说,change命令不能一定节点的位置。    replace   对一个现有节点进行近于原子操作的删除/添加。如果节点不存在,这个命令就会建立节点。    link   只适用于DQisc,替代一个现有的节点。 

猜你喜欢

转载自blog.csdn.net/zhangxinji/article/details/83820921