名称: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,替代一个现有的节点。