Linux自带的高级流控(Traffic Control)工具使用参考
2024-11-21 15:47:07 阿炯

原理部分参考多方文档进行整理,感谢一众网友提供的学习资料。如果对 Linux 流控感兴趣或需要搭建高性能的 Linux 网关,本文将会使你受益颇多。

注意:至少具备 Linux OS 的中级水平知识,熟悉 TCP/IP, Linux 网卡工作原理,以及配置 Linux 网关的经验,将有助于对本文的理解。

本文参考文档:

Tc 流控 HOWTO 英文文档,本站收录有中文翻译文档:《Linux流量控制指南(Traffic control HOWTO)

Linux流控简介

流量控制的意义:有效的控制 Linux 网卡进出流量,了解网卡工作原理,搭建高性能的 Linux 网关,对 Linux 高级系统流控有进一步的认识。

流量控制的方法:控发不控收,所以能直接对产生瓶颈网卡处的发包速率进行控制,可间接对收到的流量进行控制,而网络瓶颈分析亦为 Linux 网络流控的第一步。

Linux流量控制过程分几种:
队列控制即 QOS,瓶颈处的发送队列的规则控制,常见的有 SFQ、PRIO
带宽控制,队列的排队整形, 一般为 TBF、HTB

无类算法用于树叶级无分支的队列,例如:SFQ
分类算法用于多分支的队列,例如:PRIO、TBF、HTB

Linux 流控实现工具 tc:从 Linux2.2 版开始已并入内核,功能非常强大,详见上述参考文档。


原理

Linux 操作系统中的流量控制器 TC(Traffic Control)用于 Linux 内核的流量控制,主要是通过在输出端口处建立一个队列来实现流量控制。接收包从输入接口进来后,经过流量限制丢弃不符合规定的数据包,由输入多路分配器进行判断选择:
1.如果接收包的目的主机是本主机,那么将该包送给上层处理,否则需要进行转发,将接收包交到转发块(Forwarding Block)处理。
2.转发块同时也接收本主机上层 (TCP、UDP 等) 产生的包,通过查看路由表,决定所处理包的下一跳。
3.然后对包进行排列以便将它们送到输出接口。

一般只能限制网卡发送的数据包,不能限制网卡接收的数据包,所以可以通过改变发送次序来控制传输速率。Linux 流量控制主要是在输出接口排列时进行处理和实现的。

规则

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

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

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

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

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

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

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

qdisc 的类别如下:

CLASSLESS QDisc (不可分类 QDisc)

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

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

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

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

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)。

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

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

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

1.tc 过滤器 (tc filter):如果过滤器附属于一个类,相关的指令就会对它们进行查询。过滤器能够匹配数据包头所有的域,也可以匹配由 ipchains 或者 iptables 做的标记。

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

3.skb->priority:用户空间的应用程序可以使用 SO_PRIORITY 选项在 skb->priority 域设置一个类的 ID。

树的每个节点都可以有自己的过滤器,但是高层的过滤器也可以直接用于其子类。如果数据包没有被成功归类,就会被排到这个类的叶子 QDisc 的队中。相关细节在各个 QDisc 的手册页中。

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

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

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

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

5、单位
带宽或流速单位:
kbps    千字节 /s
mbps    兆字节 /s
kbit    Kbit/s
mbit    Mbit/s
bps 或者一个无单位数字    字节/s

数据数量单位:
kb 或者 k     千字节
mb 或者 m    兆字节
mbit    兆 bit
kbit     千 bit
b 或者一个无单位数字    字节数

tc命令参数

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

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

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

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

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

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


6、两种排队规则算法对应的不同流控分别介绍:

1. 无类算法 SFQ

a. 队列控制的无类算法 SFQ

SFQ (Stochastic Fairness Queueing 随机公平队列) 是公平队列算法家族中的一个简单实现。它的精确性不如其它的方法,但实现了高度的公平,需要的计算量亦很少。

SFQ 算法主要针对一个 TCP 会话或者 UDP 流。流量被分成相当多数量的 FIFO 队列中,每个队列对应一个会话。数据按照简单轮转的方式发送,每个会话都按顺序得到发送机会。这种方式非常公平,保证了每一个会话都不会没其它会话所淹没。

SFQ之所以被称为"随机",是因为它并不是真的为每一个会话创建一个队列,而是使用一个散列算法,把所有的会话映射到有限的几个队列中去。因为使用了散列,所以可能多个会话分配在同一个队列里,从而需要共享发包的机会,也就是共享带宽。为了不让这种效应太明显,SFQ 会频繁地改变散列算法,以便把这种效应控制在几秒钟之内 (时间由参数设定)。

注间:SFQ 只会发生在数据发生拥堵,产生等待队列的网卡上,出口网卡若无等待队列,SFQ 亦不起作用。

清单 1. 在网卡上建立 SFQ
#tc qdisc add dev eth0 root handle 1: sfq

SFQ 参数有 perturb( 重新调整算法间隔 ) 、quantum这些基本上不需要手工调整,handle 1: 规定算法编号,可以不用设置而由系统生成指定。

#tc qdisc sh dev eth0 显示算法

#tc qd del dev eth0 root 删除规则

注意:默认 eht0 支持 TOS

SFQ 队列一般用在树叶级,配合其它流量整形算法一并使用。

b. 流量控制的无类算法 TBF

令牌桶过滤器 (TBF) 是一个简单的队列规定:只允许以不超过事先设定的速率到来的数据包通过,但可能允许短暂突发流量朝过设定值。

TBF 很精确,对于网络和处理器的影响都很小,实现是针对数据的字节数进行的,而不是针对数据包进行,常用于网关限速。其实现在于一个缓冲器(桶),不断地被一些叫做"令牌"的虚拟数据以特定速率填充着(token rate)。桶最重要的参数就是它的大小,也就是它能够存储令牌的数量。每个到来的令牌从数据队列中收集一个数据包,然后从桶中被删除。这个算法关联到两个流上 —— 令牌流和数据流,于是得到 3 种情景:

a).数据流以等于令牌流的速率到达 TBF。这种情况下,每个到来的数据包都能对应一个令牌,然后无延迟地通过队列。

b).数据流以小于令牌流的速度到达 TBF。通过队列的数据包只消耗了一部分令牌,剩下的令牌会在桶里积累下来,直到桶被装满。剩下的令牌可以在需要以高于令牌流速率发送数据流的时候消耗掉,这种情况下会发生突发传输。

c).数据流以大于令牌流的速率到达 TBF。这意味着桶里的令牌很快就会被耗尽。导致 TBF 中断一段时间,称为"越限"。如果数据包持续到来,将发生丢包。此种情况最重要,因为它可以用来对数据通过过滤器的速率进行整形。令牌的积累可以导致越限的数据进行短时间的突发传输而不必丢包,但是持续越限的话会导致传输延迟直至丢包。

清单 2. 在网卡建立 TBF

#tc qd add dev eth1 root handle 1: tbf rate 256kbit burst 10000 latency 50ms
速率 256kbit,突发传输 10k,最大延迟 50ms。

#tc -s qd sh dev eth1 统计
#tc qd del dev eth1 root 删除

rate 限制的传输速率,用位来计算

latency 确定了一个包在 TBF 中等待传输的最长等待时间

burst 桶的大小,以字节计。指定了最多可以有多少个令牌能够即刻被使用

注意:管理的带宽越大,需要的缓冲器就越大。在 Intel 体系上,10 Mbit/s 的速率需要至少 10k 字节的缓冲区才能达到期望的速率。缓冲区太小则会导致潜在的丢包。

c. 无类算法除这二种队列以外,另有 pfifo_fast (网卡出口默认根队列规定)

经常使用的也就是 SFQ/TBF。这二种用法如下:
1).单纯地降低出口速率,使用令牌桶过滤器。调整桶的配置后可用于控制很高的带宽。

2).链路已经塞满,保证不会有某一个会话独占出口带宽,使用随机公平队列。

当然最重要的还是工作中得来的经验,就其应用方面只要能满足需求即可,但要做到灵活应用还得大量的实践。

2. 分类算法 PRIO/CBQ/HTB

分类算法主要作用是可以对多种数据流区别对待。一旦数据包进入一个分类的队列规定,它就得被送到某一个类中分类,对数据包进行分类的工具是过滤器。过滤器会返回一个决定,队列规定就根据这个决定把数据包送入相应的类进行排队。每个子类都可以再次使用它们的过滤器进行进一步的分类。直到不需要进一步分类时,数据包才进入该类包含的队列规定排队。除了能够包含其它队列规定之外,绝大多数分类的队列规定能够流量整形。

注意:过滤器对数据包进行分类的工具,是从队列规定内部调用的,而不是从别处(用在分叉的分支上)

列规定家族:根,句柄,兄弟和父辈。

每块网卡都有一个出口 "根队列规定", 缺省情况下是前面提到的 pfifo_fast 队列规定。每个队列规定都指定一个句柄,以便以后的配置语句能够引用这个队列规定。除了出口队列规定之外,每块网卡还有一个入口,以便 policies 进入的数据流。

队列规定的句柄有两个部分:一个主号码和一个次号码。习惯上把根队列规定称为 "1:",等价于 "1:0"。队列规定的次号码永远是0;类的主号码必须与它们父辈的主号码一致。

数据包如何出队并交给硬件

当内核决定把一个数据包发给网卡的时候,根队列规定 1: 会得到一个出队请求,然后把它传给 1:1, 然后依次传给 10:,12: 和 13:(子类自定义),然后试图从它们中进行 dequeue() 操作。也就是说,内核需要遍历整颗树,换句话说,类及其兄弟仅仅与其 "父队列规定" 进行交谈,而不会与网卡进行交谈。只有根队列规定才能由内核进行出队操作!更进一步,任何类的出队操作都不会比它们的父类更快。可以把 SFQ 作为一个子类,放到一个可以进行流量整形的父类中,从而能够同时得到 SFQ 的调度功能和其父类的流量整形功能。

a. 队列控制的分类算法 PRIO

PRIO 分类优先算法 (从左至右优先发包), 队列规定并不进行整形,它仅仅根据你配置的过滤器把流量进一步细分。你可以认为 PRIO 队列规定是 pfifo_fast 的一种衍生物,区别在每个频道都是一个单独的类,而非简单的 FIFO。

当数据包进入 PRIO 队列规定后,将根据你给定的过滤器设置选择一个类。缺省情况下有三个类,这些类仅包含纯 FIFO 队列规定而没有更多的内部结构。你可以把它们替换成你需要的任何队列规定。每当有一个数据包需要出队时,首先处理 :1 类。只有当标号更小的类中没有需要处理的包时,才会标号大的类。

PRIO 配置范例示意图:


大批量数据使用 30:,交互数据使用 20: 或 10:。

清单 3. 在网卡建立 PRIO

#tc qdisc add dev eth0 root handle 1: prio

#此命令立即创建了类 : 1:1, 1:2, 1:3 ( 缺省三个子类 )
#tc qdisc add dev eth0 parent 1:1 handle 10: sfq
#tc qdisc add dev eth0 parent 1:2 handle 20: tbf rate 20kbit buffer 1600 limit 3000

注意:此为 TBF 限速的另一写法,前文有讲解。

#tc qdisc add dev eth0 parent 1:3 handle 30: sfq

主要参数有:(后续有实例)

bands 创建频道的数目,每个频道实际上就是一个类跟 priomap 参数配合使用。

注意:频道是类,缺省情况下命名为主标号 :1 到主标号 :3。如果你的 PRIO 队列规定是 12:,把数据包过滤到 12:1 将得到最高优先级。0 频道的次标号是 1,1 频道的次标号是 2, 以此类推。

priomap 给 tc 提供过滤器,如不提供 PRIO 队列规定将参考 TC_PRIO 的优先级来决定如何给数据包入队。

b. 流量整形的分类算法 CBQ

CBQ的工作机制是确认链路的闲置时间足够长,以达到降低链路实际带宽的目的。为此它要计算两个数据包的平均发送间隔。操作期间,有效闲置时间的测量使用 EWMA (exponential weighted moving average, 指数加权移动均值) 算法,也就是说最近处理的数据包的权值比以前的数据包按指数增加。UNIX 的平均负载也是这样算出来的。计算出来的平均时间值减去 EWMA 测量值,得出的结果叫做 "avgidle"。最佳的链路负载情况下,这个值应当是 0: 数据包严格按照计算出来的时间间隔到来。在一个过载的链路上,avgidle 值应当是负的。如果这个负值太严重,CBQ 就会暂时禁止发包,称为 "overlimit"( 越限)。相反地,一个闲置的链路应该有很大 avgidle 值,这样闲置几个小时后,会造成链路允许非常大的带宽通过。为了避免这种局面,用 maxidle 来限 avgidle 的值不能太大。

理论上讲,如果发生越限,CBQ 就会禁止发包一段时间 (长度就是事先计算出来的传输数据包之间的时间间隔),然后通过一个数据包后再次禁止发包。

清单 4. WEB 服务器的流量控制为 5Mbps,SMTP 流量控制在 3Mbps 上;而且二者一共不得超过 6Mbps,互相之间允许借用带宽

#tc qdisc add dev eth0 root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8

#tc class add dev eth0 parent 1:0 classid 1:1 cbq bandwidth 100Mbit rate 6Mbit weight 0.6Mbit prio 8 allot 1514 cell 8 maxburst 20 avpkt 1000 bounded

这部分按惯例设置了根为 1:0, 并且绑定了类 1:1. 也就是说整个带宽不能超过 6Mbps.

#tc class add dev eth0 parent 1:1 classid 1:3 cbq bandwidth 100Mbit rate 5Mbit weight 0.5Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000
#tc class add dev eth0 parent 1:1 classid 1:4 cbq bandwidth 100Mbit rate 3Mbit weight 0.3Mbit prio 5 allot 1514 cell 8 maxburst 20 avpkt 1000

建立了 2 个类。注意如何根据带宽来调整 weight 参数的。两个类都没有配置成"bounded",但它们都连接到了类 1:1 上 , 而 1:1 设置了"bounded". 所以两个类的总带宽不会超过 6Mbps. 别忘了,同一个 CBQ 下面的子类的主号码都必须与 CBQ 自己的号码相一致。

#tc qdisc add dev eth0 parent 1:3 handle 30: sfq
#tc qdisc add dev eth0 parent 1:4 handle 40: sfq

缺省情况下两个类都有一个 FIFO 队列规定;但是我们把它换成 SFQ 队列,以保证每个数据流都公平对待。

#tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip sport 80 0xffff flowid 1:3
#tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 match ip sport 25 0xffff flowid 1:4

CBQ 流量整形算法相对比较复杂,工作中还常用,示例中的各参数请参阅:HOWTO 中文文档 Linux 流量控制 II -- 分类算法 PRIO/CBQ/HTB。

c. 流量整形的分类算法 HTB

HTB (Hierarchical Token Bucket) 分层的令牌桶一个分类的令牌桶过滤器,工作原理和相关配置同于 TBF,拥有 TBF 的各项性能。

清单 5. 环境与要求同上述 CBQ 的例子

#tc qdisc add dev eth0 root handle 1: htb default 30
#tc class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k

#tc class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit burst 15k
#tc class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k
#tc class add dev eth0 parent 1:1 classid 1:30 htb rate 1kbit ceil 6mbit burst 15k

#tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
#tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10
#tc qdisc add dev eth0 parent 1:30 handle 30: sfq perturb 10

# 添加过滤器,直接把流量导向相应的类:
#U32="tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32"
#$U32 match ip dport 80 0xffff flowid 1:10
#$U32 match ip sport 25 0xffff flowid 1:20

7、U32 过滤规则

过滤器是对数据包进行分类工具,过滤器用与把数据包分类并放入相应的子队列,这些过滤器在分类的队列规定内部被调用。为了决定用哪个类处理数据包,必须调用所谓的 "分类器链" 进行选择。这个链中包含了这个分类队列规定所需的所有过滤器,常用到的为 U32 过滤器。

分类的一示例图:


当一个数据包入队的时候,每一个分支处都会咨询过滤器链如何进行下一步。典型的配置是在 1:1 处有一个过滤器把数据包交给 12:,然后 12: 处的过滤器在把包交给 12:2。可以把后一个过滤器同时放在 1:1 处,而得到效率的提高。

另外不能用过滤器把数据包向 "上" 送。而且,使用 HTB 的时候应该把所有的规则放到根上。

注意:数据包只能向 "下" 进行入队操作!只有处队的时候才会上到网卡所在的位置来。他们不会落到树的最底层后送到网卡。

清单 6. 过滤器过滤示例

#tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip dport 22 0xffff flowid 10:1
在 10: 节点添加一个过滤规则 , 优先权 1: 凡是去往 22 口 (精确匹配) 的 IP 数据包 , 发送到频道 10:1

#tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip sport 80 0xffff flowid 10:1
在 10: 节点添加一个过滤规则 , 优先权 1: 凡是来自 80 口 (精确匹配) 的 IP 数据包 , 发送到频道 10:1

#tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2
在 eth0 上的 10: 节点添加一个过滤规则 , 它的优先权是 2,凡是上二句未匹配的 IP 数据包 , 发送到频道 10:2

#tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip dst 4.3.2.1/32 flowid 10:1
去往 4.3.2.1 的包发送到频道 10:1 其它参数同上例

#tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 1.2.3.4/32 flowid 10:1
来自 1.2.3.4 的包发到频道 10:1

#tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2
凡上二句未匹配的包送往 10:2

#tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip src 4.3.2.1/32 match ip sport 80 0xffff flowid 10:1
可连续使用 match,匹配来自 1.2.3.4 的 80 口的数据包

常用到的过滤命令一览

#tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32 -------

根据源/目的地址

源地址段 'match ip src 1.2.3.0/24'

目的地址段 'match ip dst 4.3.2.0/24'

单个 IP 地址 'match ip 1.2.3.4/32'

根据源/目的端口,所有 IP 协议

源 'match ip sport 80 0xffff' 0xffff 表所有数据包

目的 'match ip dport 80 0xffff'

根据 IP 协议(tcp, udp, icmp, gre, ipsec)

icmp 是 1:'match ip protocol 1 0xff',1 是根据 /etc/protocols 协议号来定。

根据 fwmark

#iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6
#tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1

注意:handle 根据过滤器的不同,含义也不同。

按 TOS 字段

#tc filter add dev ppp0 parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff flowid 1:4
选择交互和最小延迟的数据流匹配大量传输,使用 "0x08 0xff"。

#tc filter add dev eth0 protocol ip parent 1:0 pref 10 u32 match u32 00100000 00ff0000 at 0 flowid 1:10
匹配那些 TOS 字段带有 '最小延迟' 属性的数据包。


8、应用与实例

Linux 流量控制主要分为建立队列、建立分类和建立过滤器三个方面。

1 步骤:
针对网络物理设备(如以太网卡 eth0)绑定一个队列 QDisc;
在该队列上建立分类 class;
为每一分类建立一个基于路由的过滤器 filter;
最后与过滤器相配合,建立特定的路由表。

2 应用 1:
git 限速1:针对端口进行限速
在使用 git 拉去代码时很容易跑满带宽,为了控制带宽的使用,配置如下:

#查看现有的队列
tc -s qdisc ls dev eth0

#查看现有的分类
tc -s class ls dev eth0

#创建队列
tc qdisc add dev eth0 root handle 1:0 htb default 1
#添加一个tbf队列,绑定到eth0上,命名为1:0,默认归类为1
#handle:为队列命名或指定某队列

#创建分类
tc class add dev eth0 parent 1:0 classid 1:1 htb rate 10Mbit burst 15k
#为eth0下的root队列1:0添加一个分类并命名为1:1,类型为htb,带宽为10M
#rate:是一个类保证得到的带宽值,如果有不只一个类,请保证所有子类总和是小于或等于父类
#ceil:是一个类最大能得到的带宽值

#创建一个子分类
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 10Mbit ceil 10Mbit burst 15k
#为1:1类规则添加一个名为1:10的类,类型为htb,带宽为10M

#为了避免一个会话永占带宽,添加随即公平队列sfq
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
#perturb:是多少秒后重新配置一次散列算法,默认为10秒
#sfq算法可以防止一个时段内的一个ip占用整个带宽

#使用u32创建过滤器
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip sport 22 flowid 1:10

#删除队列
tc qdisc del dev eth0 root

配置完成后加入本地启动文件:  
/etc/rc.local

git 限速 2:针对 ip 进行限速
情景:因为带宽资源有限(20Mbit≈2Mbyte),使用 git 拉取代码的时候导致带宽资源告警,所以对 git 进行限速,要求:内网不限速;外网下载速度为 1M 左右(注意:此处需要注意单位转换 1byte=8bit)。

#!/bin/bash
#针对不同的ip进行限速

#清空原有规则
tc qdisc del dev eth0 root

#创建根序列
tc qdisc add dev eth0 root handle 1: htb default 1

#创建一个主分类绑定所有带宽资源(20M)
tc class add dev eth0 parent 1:0 classid 1:1 htb rate 20Mbit burst 15k

#创建子分类
tc class add dev eth0 parent 1:1 classid 1:10 htb rate 20Mbit ceil 10Mbit burst 15k
tc class add dev eth0 parent 1:1 classid 1:20 htb rate 20Mbit ceil 20Mbit burst 15k

#避免一个ip霸占带宽资源(git1有讲到)
tc qdisc add dev eth0 parent 1:10 handle 10: sfq perturb 10
tc qdisc add dev eth0 parent 1:20 handle 20: sfq perturb 10

#创建过滤器
#对所有ip限速
tc filter add dev eth0 protocol ip parent 1:0 prio 2 u32 match ip dst 0.0.0.0/0 flowid 1:10
#对内网ip放行
tc filter add dev eth0 protocol ip parent 1:0 prio 1 u32 match ip dst 12.0.0.0/8 flowid 1:20

该过程遇到的问题:
1.未配置优先级以至于只有一条规则生效(所有的 ip 都被限速)
解决办法:在过滤器中加入 prio,指定规则的优先级

2.不知道本地带宽是多大:
解决办法:直接给你一个很大很大的带宽(10Gib),对需要限速的 ip 分配指定的带宽资源,然后把剩余的带宽全部分配给内网 ip(简单粗暴有效)。

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

假如有三种类型的流量需要控制:
是发往主机 1 的,其 IP 地址为 192.168.1.24。其流量带宽控制在 8Mbit,优先级为 2;
是发往主机 2 的,其 IP 地址为 192.168.1.30。其流量带宽控制在 1Mbit,优先级为 1;
是发往子网 1 的,其子网号为 192.168.1.0,子网掩码为 255.255.255.0。流量带宽控制在 1Mbit,优先级为 6。

实现:
建立队列:一般情况下,针对一个网卡只需建立一个队列。将一个 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
#cell:包间隔发送单元的大小为8字节

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

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
#prio:用来指示借用带宽时的竞争力,prio越小优先级越高,竞争力越强。

该队列的最大可用带宽为 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

建立过滤器
过滤器主要服务于分类。一般只需针对根分类提供一个过滤器,然后为每个子分类提供路由映射。
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

建立路由
该路由是与前面所建立的路由映射一一对应。
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 主机地址流量控制限制,不要使用子网流量控制限制。如一定需要对直连子网实施流量控制,则在建立该子网的路由映射前,需将原先由系统建立的路由删除,才可完成相应步骤。

4 应用 3:MySQL 数据库同步数据限速方案
mysql1:10.9.57.162
may1:10.12.1.45

# mysql1上实施(限制到may1的流量:8mbit)
tc qdisc add dev eth0 root handle 1: htb r2q 1
tc class add dev eth0 parent 1: classid 1:1 htb rate 8mbit ceil 8mbit
tc qdisc add dev eth0 parent 1:1 handle 10: sfq perturb 10
tc filter add dev eth0 parent 1: protocol ip prio 16 u32 match ip dst 10.12.1.45 flowid 1:1  

# may1(限制到mysql1的流量:8mbit)
tc qdisc del dev em1 root
tc qdisc add dev em1 root handle 2: htb r2q 1
tc class  add dev em1 parent 2: classid 2:1 htb rate 8mbit ceil 8mbit
tc qdisc add dev em1 parent 2:1 handle 11: sfq perturb 10
tc filter add dev em1 parent 2: protocol ip prio 16 u32 match ip dst 10.9.57.162 flowid 2:1

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

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

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

2)显示分类的状况
简单显示指定设备 (这里为 eth0) 的分类状况

# tc class ls dev eth0
详细显示指定设备 (这里为 eth0) 的分类状况

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

显示过滤器的状况
# tc -s filter ls dev eth0

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

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

实例脚本

限速
#!/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

模型
#!/bin/sh
tc qdisc del dev eth7 root &> /dev/null
tc qdisc del dev eth8 root &> /dev/null

#Add qdisc
tc qdisc add dev eth7 root handle 10: htb default 9998
tc qdisc add dev eth8 root handle 10: htb default 9998

#Add htb root node
tc class add dev eth7 parent 10: classid 10:9999 htb rate 1000000kbit ceil 1000000kbit
tc class add dev eth8 parent 10: classid 10:9999 htb rate 1000000kbit ceil 1000000kbit

#Add htb fake default node here
tc class add dev eth7 parent 10:9999 classid 10:9998 htb rate 1000000kbit ceil 1000000kbit
tc class add dev eth8 parent 10:9999 classid 10:9998 htb rate 1000000kbit ceil 1000000kbit

#Add rule node
tc class add dev eth7 parent 10:9999 classid 10:3 htb rate 1kbit ceil 50kbit
tc filter add dev eth7 parent 10: protocol ip handle 3 fw classid 10:3
tc class add dev eth8 parent 10:9999 classid 10:3 htb rate 1kbit ceil 50kbit
tc filter add dev eth8 parent 10: protocol ip handle 3 fw classid 10:3

#Add htb real default node here
tc class change dev eth7 classid 10:9998 htb rate 1kbit ceil 1000000kbit
tc class change dev eth8 classid 10:9998 htb rate 1kbit ceil 1000000kbit

tc
#创建一个主队列
tc qdisc add dev eth0 root handle 1: htb  default 1
#tc 队列 添加设置接口root为最上层句柄(做标记用):标记类型 默认使用1的class
#命令解释:将一个htb队列绑定在eth0上,编号为1:0,默认归类是1

tc class add dev eth0 parent 1:0 classid 1:30 htb rate 10mbit
#为eth0 下的root队列1:0 添加分类并命名为 1:30 类型为htb,速度为10M

tc class add dev eth0 parent 1:30 classid 1:31 htb rate 10mbit

tc qdisc add dev eth0 root tbf  match ip sport 22 0xffff rate 10mbit

网络速度测试的方法

可以使用iperf来测试。

wondershaper

了解完 tc 工具后再来看一个简单实用的限速工具:wondershaper。这个单词看似很复杂,但是当看过源码之后会发现,其只不过是将 tc 一些简单的功能封装成了一个 shell 脚本而已,安装和使用方法如下:
yum install epel-release -y # 依赖第三方库
yum install wondershaper -y

查看使用说明:
# wondershaper
Wonder Shaper 1.2.1
Usage: /usr/sbin/wondershaper [device] clean|[upload speed in Kb/s] [download speed in Kb/s]
Example: /usr/sbin/wondershaper eth0 20 500

示例:
# 将上行带宽限制为1M,下行带宽限制为10M
# wondershaper eth0 1024 10240

# 清除原有规则 (两个参数可以是任何字符)
# wondershaper clean clean

# 查看已有规则 (查看eth0的规则)
# wondershaper eth0
Note: 一般为 3 个参数,第一个参数为网卡名,第二个上行速度(出)限制,第三个参数为下行速度(入)限制。


实例解析

以下实例由实际工作环境要求编写而得:

1. PRIO 分类优先算法 (从左至右优先发包)
网卡工作示例图:


清单 7. PRIO 分类优先算法示例(从左至右优先发包)

#tc ad add dev eth0 root handle 1: prio hands 3 priomap 1---1 16 个 1 (tos 比特 ) 表示所有数据包
注 : 此命令自动在 1: 下创建三子类 1:1 1:2 1:3,此例中只用到 1:1

#tc qd add dev eth0 parent 1:1 handle 11: sfq

#tc qdisc add dev eth0 parent 1:1 handle 12: tbf rate 20kbit buffer 1600 limit 3000

#tc qd add dev eth0 parent 1:1 handle 13: sfq

#tc filter add dev eth0 parent 1:1 prio 1003 protocol ip u32 match ip src 192.168.1.0/24 flowid 1:13

#tc filter add dev eth0 parent 1:1 prio 1001 protocol ip u32 match ip src 10.0.0.0/8 flowid 1:12

#tc filter add dev eth0 parent 1:1 protocol ip prio 1001 u32 match ip tos 0x10 0xff flowid 1:11  交互和最小延迟的数据流

2. HTB 分层令牌桶
网卡工作示例图:


清单 8. HTB 分层令牌桶示例

#tc qd del dev eth1 root

#tc qdisc add dev eth1 root handle 1: htb default 12

#tc class add dev eth1 parent 1: classid 1:1 htb rate 2Mbit burst 1500000 在 1: 下定义子类 1:1

#tc class add dev eth1 parent 1:1 classid 1:11 htb rate 512kbit burst 150000 ceil 1Mbit

#tc qd add dev eth1 parent 1:11 handle 111: sfq

#tc class add dev eth1 parent 1:1 classid 1:12 htb rate 1Mbit burst 150000 ceil 1Mbit

#tc qd add dev eth1 parent 1:12 handle 122: sfq 注:亦可不在 1:12 class 下定义 122: qd

#tc class add dev eth1 parent 1:1 classid 1:13 htb rate 2Mbit burst 150000 ceil 2Mbit

#tc qd add dev eth1 parent 1:13 handle 133: sfq

#tc filter add dev eth1 parent 1: prio 10001 protocol ip u32 match ip src 192.168.1.0/24 flowid 1:12    其它二类亦如此

3. ADSL 上网流量限控脚本
ADSL 带宽是下行 3200Kbit,上行只有 320Kbit。

网卡工作示例图:


清单 9. 上网流量限控脚本示例

tc qdisc add dev eth0 root handle 1: htb default 24

tc class add dev eth0 parent 1: classid 1:1 htb rate 300kbit ceil 300kbit prio 0

tc class add dev eth0 parent 1: classid 1:2 htb rate 150kbit prio 3

tc class add dev eth0 parent 1:1 classid 1:11 htb rate 300kbit ceil 300kbit prio 1
tc class add dev eth0 parent 1:1 classid 1:12 htb rate 150kbit ceil 250kbit prio 2
tc class add dev eth0 parent 1:2 classid 1:21 htb rate 100kbit ceil 150kbit prio 4
tc class add dev eth0 parent 1:2 classid 1:22 htb rate 30kbit ceil 140kbit prio 5
tc class add dev eth0 parent 1:2 classid 1:23 htb rate 15kbit ceil 130kbit prio 6
tc class add dev eth0 parent 1:2 classid 1:24 htb rate 5kbit ceil 50kbit prio 7

tc qdisc add dev eth0 parent 1:11 handle 111: sfq perturb 5
tc qdisc add dev eth0 parent 1:12 handle 112: sfq perturb 5

tc qdisc add dev eth0 parent 1:21 handle 121: sfq perturb 10
tc qdisc add dev eth0 parent 1:22 handle 122: sfq perturb 10
tc qdisc add dev eth0 parent 1:23 handle 133: sfq perturb 10
tc qdisc add dev eth0 parent 1:24 handle 124: sfq perturb 10

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

tc filter add dev eth0 parent 1:0 protocol ip prio 3 handle 3 fw classid 1:21
tc filter add dev eth0 parent 1:0 protocol ip prio 4 handle 4 fw classid 1:22
tc filter add dev eth0 parent 1:0 protocol ip prio 5 handle 5 fw classid 1:23
tc filter add dev eth0 parent 1:0 protocol ip prio 6 handle 6 fw classid 1:24

1:11 最高优先级的数据包通道优先通过,主要为一些 ACK SYN 确认包 .. 必要时全部占用带宽 .. 全速通过。

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 数据通道可能大量上传文件,rate 不能给得太多,ceil 设置大些 (其它通道剩余带宽应用)

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

其次的工作即在 iptables 端对相应数据包打上标记 ...

4. Linux+NAT+TC
脚本是 Linux NAT 网关实例,根据此脚本思路,可进一步细致的进行针对于数据包的限制。

清单 10. 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-source 124.42.97.36
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j SNAT --to-source 124.42.97.36
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 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

流量监测相关命令 :
tc -s qdisc/class ls dev eth0
tc -s qdisc/class ls dev eth1

5. Linux 网关/服务器限速 --- HTB
清单 11. Linux 网关/服务器 HTB 限速

#!/bin/sh
PWD=/home/huaying/net
TC=/sbin/tc
$TC class ls dev eth0
$TC qdisc del dev eth0 root
$TC qdisc add dev eth0 root handle 1: htb r2q 1
U32="$TC filter add dev eth0 parent 1: protocol ip prio 16 u32"

while read line
do
ip=`echo $line | awk '{print $1}'`
limit=`echo $line | awk '{print $2}'`
$TC class add dev eth0 parent 1: classid 1:$ip htb rate
"$limit"kbit burst 1k
$U32  match ip dst 192.168.1.$ip/32 flowid 1:$ip
done < $PWD/ip_limit

注意:ip_limit 分行记录,第一列为 ip,第二列为限制的带宽,二列以 tables 分开。

服务器限速

#!/bin/sh
/sbin/tc qdisc del dev eth0 root
/sbin/tc qdisc add dev eth0 root handle 1:0 htb r2q 1
/sbin/tc class add dev eth0 parent 1:0 classid 1:1 htb rate 75mbit burst 10k
/sbin/tc filter add dev eth0 parent 1: protocol ip prio 16 u32  match ip dst 0.0.0.0/0 flowid 1:1
/sbin/tc class ls dev eth0

最大限制服务器 eth0 流量在 75Mbit/s。