流量控制

Traffic Control ,简称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的一些常用命令:



网卡限速:



ethtool -s eth0 speed 10 autoneg off



取消限速



ethtool -s eth0 autoneg on



监视



tc qdisc ls dev eth0



简单显示指定设备(eth0)的分类情况



tc class ls dev eth0



详细显示指定设备(eth0)的分类情况



tc -s class ls dev eth0



tc -s filter ls dev eth0



显示路由情况



ip route show



删除网卡上的过滤器



tc qdisc del dev eth0 root



增加网卡上的过滤器



tc qdisc add dev eth0 root handle 1:0 netem delay 5ms loss 5%



这条命令的作用是让网络产生5ms的延时,丢包率为5%

2.1. 什么是流量控制?



流量控制是路由器上报文的接收和发送机制及排队系统的统称。这包括在一个输入接口上决定以何种速率接收何种报文,在一个输出接口上以何种速率、何种顺序输出何种报文。



在绝大多数情况下,流量控制只包含一个单一队列,此队列以硬件所能处理的最大能力接收报文并尽快输出它们,这种队列就叫FIFO(first in,first out)。



Linux下的默认排队规则是pfifo_fast,此规则比FIFO稍复杂。



在很多类型的软件中都有使用队列的例子。队列是组织未定任务或数据流的一种方法(参考2.5节)。因为网络链路层单纯的以串行方式发送数据流,所以队列对于管理输出报文是必要的。



如果一桌面电脑和一台高效web服务器共享同一条上行链路,它们对带宽的竞争就可能发生。web服务器可能会填满路由器的发送队列,当web服务器发送数据的速率大于路由器上数据的输出速率时,路由器就会开始丢包(它的缓冲区满了)。这个时候,桌面电脑(拥有一个交互用户)就会面临丢包及高延时的风险。注意,高延迟有时候会让用户抓狂!通过划分两个内部队列给这两种不同类型的应用使用,这两种应用就可以较好的分享网络资源。



流量控制是一个工具集,它能够让用户通过它在网络设备上应用不同的队列和排队机制。虽然利用这些工具来重新划分数据流和报文的功能很强大,并且可以进行复杂的应用,但最好有足够多的带宽。



术语服务质量(QoS)通常是流量控制的同义词。



2.2. 为什么要应用流量控制?



分组交换网络和电路交换网络的一个重要不同之处是:分组交换网络是无状态的,而电路交换网络(比如电话网)必须保持其状态。分组交换网络和IP网络一样被设计成无状态的,实际上,无状态是IP的一个根本优势。



无状态的缺陷是不能对不同类型数据流进行区分。但通过流量控制,管理员就能够基于报文的属性对其进行排队和区别。它甚至能够被用于模拟电路交换网络,将无状态网络模拟成有状态网络。



有很多实际的理由去考虑使用流量控制,并且流量控制也有很多有意义的应用场景。下面是一些利用流量控制可以解决或改善的问题的例子



下面的列表不是流量控制可以解决的问题的完整列表,此处仅仅介绍了一些能通过流量控制来解决的几类问题



常用的流量控制解决方案



通过TBF和带子分类的HTB将带宽限制在一个数值之下
通过HTB分类(HTB class)和分类(classifying)并配合filter,来限制指定用户、服务或客户端的带宽。
通过提升ACK报文的优先级,以及使用wondershaper来最大化非对称线路上的TCP吞吐量。
通过带子分类的HTB和分类(classifying)为某个应用或用户保留带宽。
通过HTB分类(HTB class)中的(优先级)PRIO机制来提高延时敏感型应用的性能。
通过HTB的租借机制来管理多余的带宽。
通过HTB的租借机制来实现所有带宽的公平分配。
通过监管器(policer)加上带丢弃动作的过滤器(filter)来使某种类型的流量被丢弃。
请记住,很多时候,最好去购买更大的带宽,流量控制并不能解决所有的问题。



2.3. 优点



当正确的使用流量控制时,就能提高网络资源的利用率,并能减少潜在的竞争。正确使用后,网络就会符合流量控制的目标,比如能给大流量的下载分配一个合适的带宽然后使高优先级的交互报文也能进行正常的传送,低优先级的数据(比如邮件)也能正常的传输而不明显的影响其它数据传送。



广义上来说,如果流量控制能符合已和用户约定好的策略,那么用户就能最大限度的使用网络资源。



2.4. 缺点



复杂性是流量控制的主要缺点。而流量控制工具降低了学习流量控制及其机制的难度,虽然有一些方式来熟悉这些流量控制工具,但是从流量控制中找出不正确的配置也是一个挑战



恰当的使用流量控制可以使网络资源更加公平的被分配,但流量控制很容易被使用不当,如果使用不当就会导致对网络资源的分配更不公,对网络资源的竞争会更大。



为了维护流量控制结构,需要路由器上有足够的计算资源。幸运的是,它只会消耗较小的计算资源,不过当流量控制规则变得庞大且复杂时它所消耗的资源就不容忽视。



对于个人用户来说,流量控制几乎没什么成本。但对于公司来说,应用流量控制所带来的费用可能会比购买更多的带宽还多,因为培训一个精通流量控制的人员会比购买更多的带宽花费多。



尽管分组交换网上的流量控制是一种很宽泛的概念,但你可以认为流量控制提供了一种将电路交换网的有状态属性应用到分组交换网的方式。



2.5. 队列



队列是流量控制的基础,而且是调度的实现思想。一个队列中包含有限个对象,这些对象将在队列中等待被处理。在网络中,这些对象就是数据包,这些数据包在队列中等待被硬件传输。在最简单的模式中,数据包按照先进先出的原则进行传输,这种队列在计算机网络(或更广泛的计算机科学)中被称为FIFO。



当没有和其它机制配合使用时,队列并不能提供流量控制功能。实际上,队列只有两种操作:将对象加入到队列中,即入队,将对象从队列中移除,即出队。



当和其他组件配合时队列就会具有复杂的功能,比如在多队列中对报文进行延迟,对报文进行重新排队,丢弃报文,对报文进行分级。队列中也可以包含子队列,以便使用更为复杂的调度方式。



对于高层应用来说,报文就是入队然后发送,对于报文是以何种顺序、何种方式被发送的,高层应用并不关心。因此,对于高层应用来说,流量控制表现出来的就是一个单一队列。只有对应用流量控制的那一层来说,流量控制结构才是可见的。



2.6. 数据流



一条数据流就是两台主机之间的连接或会话。两台主机之间的任何数据交互报文可以被认为一条数据流。在TCP中,源IP加源端口和目的IP加端口的连接就决定了一条数据流,UDP也类似。



流量管理机制常常会将流量划分为不同类的数据流,这些流可以被聚合起来然后作为一条聚合流被传输(DiffServ,差分服务)。不同的流量控制机制能基于不同的流将带宽进行均等的划分。



如果想对带宽进行均分,然后分配给对带宽有竞争关系的数据流,那么对数据流进行处理就很重要。特别是有些应用会产生大量的数据流,这时的流量管理就更为重要。



2.7. 令牌桶



整流的两个关键要素就是令牌桶。



为了控制出队的速率,一种方式就是直接统计队列中出队的报文或字节数,但是为了保证精确性就需要复杂的计算。在流量控制中广泛应用的另一种方式就是令牌桶,令牌桶以一定的速率产生令牌,报文或字节出队时从令牌桶中取令牌,只有取到令牌后才能出队。



我们可以打一个比方,一群人正排队等待乘坐游乐场的游览车。让我们想象现在有一条固定的道路,游览车以固定的速度抵达,每个人都必须等待游览车到达后才能乘坐。游览车和游客就可以类比为令牌和报文,这种机制就是速率限制或流量整形,在一个固定的时间段内只有一部分人能乘坐游览车。



继续上面的比方,设想有大量的游览车正停在车站等待游客乘坐,但现在没有一个游客。如果现在有一大群游客同时过来了,那么他们都可以马上乘上游览车。在这里,我们就可以将车站类比为桶,一个桶中包含一定数量的令牌,桶中的令牌可以一次性被使用完而不管数据包到达的时间。



让我们来完成这个比方,游览车以固定的速率抵达车站,如果没人乘坐就会停满车站,即令牌以一定的速率进入桶中,如果令牌一直没被使用那么桶就可以被装满,而如果令牌不断的被使用那么桶就不会满。令牌桶是处理会产生流量突发应用(比如HTTP)的关键思想。



使用令牌桶过滤器的排队规则(TBF qdisc,Token Bucket Filter)是流量整形的一个经典例子(在TBF小节中有一个图表,通过该图表可以形象化的帮助读者理解令牌桶)。TBF以给定的速度产生令牌,当桶中有令牌时才发送数据,令牌是整流的基本思想。



在某些情况下,队列中可能无数据包,因此不会立即需要令牌,这些令牌就会被收集起来直到队列需要。但无限制的积累令牌可能会失去流量整形的意义,所以令牌积累到一定量就会停止。由于积累了令牌,当有大量的报文或字节需要出队时就有足够的令牌可用。这种虚拟的令牌被存储在虚拟的桶中,一个桶中能存放多少令牌取决于桶的大小。



这意味着如果桶的大小设计不合理,在任何时刻桶中都可能充满令牌。小型的令牌桶适合流量较为稳定的网络,大型的令牌桶适合有较大突发流量的网络,除非你的目的就是为了限制数据流的突发传输。



总之,令牌以固定的速度产生,桶中可以积满令牌,这样就可以处理突发流量,使网络流量更为平滑。



令牌和桶的概念紧密相联,它们被用于TBF(一种无类qdiscs)和HTB(一种分类qdiscs)中。在tcng语言中,二色和三色标识法就是令牌桶的应用。



2.8. 包和帧



在网络上传输的数据该被称为什么,其术语取决于其所在的网络层。本文档将不会区分两者在技术上的差别(不区分是错的),尽管在这里列出了这两个术语。



帧通常是用来描述第2层(数据链路层)上发送给下一接收者的数据。以太网接口,PPP接口,T1接口都把他们的第2层数据叫作帧。在流量控制中,帧其实就是其处理单位。



包就是对更高层数据单元的称呼,即第3层(网络层),在本文档中我们更多的会使用包这一术语,虽然这么用不够准确。



(译注:在本译文中,数据包和报文混用)




  1. 流量控制中的几个必备元素



3.1. 整流



整流器通过延迟数据包来使流量保持在一定速率。



整流就是让包在输出队列上被发送之前进行延时,然后一定的速率发送,使网络流量保持在一定的速率之下,这是大部分用户进行流量控制的目的。报文延时作为流量控制的一部分,使得所有整流算法都是非工作保留模式的,大致解释就是“必须保持工作来延迟报文”。



非工作保留模式提供了整形的功能,反过来看,工作保留排队机制(参考PRIO,优先级调度)就不具备流量整形的功能,因为其不能对报文进行延时。



整流器将流量控制在一个给定速率下(通常以pps,bps,Bps为单位)。当然其也有副作用,那就是整流器平滑了突发流量。对带宽进行整流的好处是可以控制报文的延时,整流的思想就是利用令牌桶,可以阅读2.7节获取更多有关令牌桶的信息。



(译注:工作保留就是为较高优先级的报文保留部分资源,在非工作保留模式下,当有报文可处理时就处理,在工作保留模式下,即使有报文需要处理,就算资源空闲,其也会为高优先级的报文保留部分资源)



3.2. 调度



调度器(scheduler)排列或重排输出报文。



调度就是对队列中的输入输出报文进行排列。最常的调度方法就是FIFO(先进先出),更广泛的来说,在输出队列上的任何流量控制都可以被称作调度,因为报文被排列以被输出。



有很多调度算法被用于不同的网络环境,一种公平调度算法(参考SFQ)用来阻止某一个客户端或数据占用太多网络资源,一种轮循调度算法(参考WRR)让每条数据流轮流出队,还有一些比较复杂的调度算法用来防止主干网流量过载(参考GRED)或还有一些用来改进其它调度算法的算法(参考ESFQ)。



3.3. 分类



分类器(classifier)将流量分类、划分到不同队列中。



分类就是将流量进行划分以便区别处理,例如拆分后放到不同的输出队列中。在报文的接收、路由、发送过程中,网络设备可以用多种方式来分类报文。分类包括对报文进行标记,标记可以在边际网络中由一个单一的控制单元来完成,也可以在每一跳中都进行标记。



Linux允许报文依次通过一系列分类器,而且还可以通过和监管器(policer)配合来对报文进行分类。



3.4. 监管



监管器(Policer)计算和限制队列中的流量。



监管作为流量控制的一部分,就是用于限制流量。监管常用于网络边际设备,使某个节点不能使用多于分配给它的带宽。监管器以特定的速率接收数据包,当流量超过这一速率时就对接收的数据包执行相应的动作。最严格的动作就是丢弃数据包,尽管该数据包可以被重新分类。



当流量以一定的速率进入队列时,监管器只有两个动作:当数据包以低于给定速率进入队列时,执行一个动作(允许入队),当数据包以高于给定速率进入队列时,执行另一个动作。尽管监管器内部使用了令牌桶,但是它不具备整流器延迟报文的能力。



3.5. 丢弃



丢弃就是丢掉整个数据包,整条流或一类流量。



丢弃就是通过某种机制来选择哪个数据包被丢掉。



3.6. 标记



标记对数据进行更改。



这里不是指fwmark,iptables和ipchains的标记都是用来修改数据包的元数据,而不是数据包本身。



流量控制在数据包中插入了DSCP部分,在一个可管理网络中,其可被其它路由器利用和识别(通常用于DiffServ,差分服务)。




  1. 流量控制组件



表1. 流量控制元素和Linux组件之间的联系



传统元素



Linux组件



整流(shaping)



class组件提供整流功能。



调度(scheduling)



qdisc是一个调度器。调度器可简可繁,简单的如FIFO,复杂的如带分类的qdisc,其他的如HTB。



分类(classifying)



filter加上classifier提供了分类功能,严格来说,Linux的classifier离不开filter。



监管(policing)



在Linux流量控制机制中,policer仅仅作为filter一个功能。



丢弃(dropping)



为了运用丢弃,需要一个filter和一个动作是“drop”的policer相配合。



标记(marking)



qdisc提供标记的功能。



4.1. 排队规则(qdisc)



简单来说,qdisc是一个调度器(参见3.2节)。每个输出接口都有一个调度器,默认的调度器就是FIFO。Linux下可用的调度器会按照调度器的规则对进入队列的包进行重新排列。



qdisc是Linux流量控制设计的主要部分,也被称为排队规则(quenuing discipline)。



分类qdisc(classful qdisc)可以包含多个类别(class),其也提供了可以附加到filter的句柄。使用不带子类的classful qdisc是允许的,尽管这会造成系统资源的浪费。



非分类qdisc是不带class的,所以其也不能被附加到一个filter,由于非分类qdisc不带任何子对象,所以不能用来对流量进行分类。这就意味着没有filter能被附加到一个非分类qdisc。



术语root qdisc和ingress qdisc常使人混淆,其实它们都不是真正的排队规则,它们只是流量控制可以被实施的地方,即入口(输入流量)和出口(输出流量)处。



每个接口既包含root qdisc又包含ingress qidsc。最主要也是最常见的就是入口排队规则(egress qdisc),即root qdisc。它能包含任何带分类或分类结构的排队规则。绝大多数文档都是针对root qdisc和它的子集的,接口上的流量都得通过egress或root qdisc。



对于在接口上接收的流量,会先通过ingress qdisc,由于组件的限制,ingress qdisc不能创建子分类,而且只能和一个filter相关联。在实际运用中,ingress qdisc仅仅和一个policer相关联来方便的限制网络接口上接收的数据量。



简而言之,你可以利用egress实现更为强大的功能,因为它包含一个真正的qdisc并且具有流量控制系统的完整功能。一个ingress qdisc仅仅支持一个policer。本文档的余下部分除非有特殊说明,将只关心和root qdisc有关的流量控制结构。



4.2. 分类(class)



分类只存在于可分类排队规则(classful qdisc)(例如,HTB和CBQ)中。分类可以很复杂,它可以包含多个子分类,也可以只包含一个子qdisc。在超级复杂的流量控制应用场景中,一个类中再包含一个可分类qdisc也是可以的。



任何一个分类都可以和任意多个filter相关联,这样就可以选择一个子分类或运用一个filter来重新排列或丢弃进入分类中的数据包。



叶子分类是qdisc中的最后一个分类,它包含一个qdisc(默认是FIFO)并且不包含任意子分类。任何包含子分类的分类都是内部分类而不是子分类。



4.3. 过滤器(filter)



过滤器是流量控制系统中最复杂的部分。过滤器提供了一种方便的机制将流量控制中的几个关键要素集合在了一起。过滤器最简单且最常见的功能就是分类数据包(参见3.3节)。Linux的过滤器可以允许用户利用一个或多个过滤器将数据包分类至输出队列上。



一个过滤器必须包含一个分类器(classifier)。
一个过滤器可以包含一个监管器(policer)。
过滤器既可以和可分类的qdisc相关联,也可以和分类(class)相关联。已入队的数据包首先通过root qdisc,当数据包通过了和root qdisc相关联的过滤器后,数据包可以被送入子分类(subclass)(子分类也可以有自己的过滤器)以进行进一步的分类。



4.4. 分类器(classifier)



分类器(filter)可以通过tc工具来管理,它可以运用不同的分类器,最常用的就是u32分类器,u32分类器可以允许用户基于数据包的属性来选择数据包。



分类器作为filter的一部分,可以用来识别数据包或数据包元数据的特征。Linux分类器是Linux流量控制中有关分类的直接实现。



4.5. 监管器(policer)



在Linux中,监管器这个关键部分只能作为filter的一部分来使用,监管器在速率超过指定速率时执行一个动作,在速率低于指定速率时执行另一个动作。可以巧秒的利用监管器来模拟三色标识法,参考第10节。



当利用监管器来限制带宽时,尽管监管和整形都是流量控制的基本元素,但它们从不延迟任何流量。基于指定的准则,监管器只能执行一个动作。可参考例5。



4.6. 丢包(drop)



在Linux流量控制中,drop仅能作为policer的一部分。任何和filter相关联policer都可以有drop动作。



在Linux流量控制系统中,数据包只能在policer中被显示的丢弃,policer能以指定的数率限制数据包入队,也能丢弃匹配某种模型的所有数据包。



然而,在流量控制系统的某些地方,数据包可能作为一个副作用被丢弃。例如,如果调度器(scheduler)使用和GRED一样的方式来控制数据流时,数据包就可能会被丢弃。



另外,当流量突发或流量过载的时候,整形器(shaper)或调度器(scheduler)可能会耗尽分配给它的缓冲区而不得不丢弃数据包。



4.7. 句柄(handle)



在流量控制结构中,每个分类或可分类qdisc(参见第7节)都需要一个唯一的标识符。这个唯一标识符就是我们所说的句柄,一个句柄由两组数字组成:一个主编号和一个次编号。这些编号可以由用户根据下面的规则任意分配。



class和qidsc句柄的编号准则



主编号(major)



这个编号对内核来说完全没有意义。用户可以使用任意一种方式来编号,但是在流量控制系统中,具有相当父对象的子对象应该使用相同的主句柄号。和root qdisc直接关联的对象,习惯上从1开始给它们编号。



次编号(minor)



如果次编号为0,那么就明确的表明这个对象是一个qdisc,其他非零值则表示该对象是class。所有拥有同一父class的class必须使用同一个次编号。



ffff:0这个句柄号保留给ingress qidsc使用。



在tc的filter中,句柄被作为classid和flowid的参数使用。句柄是对象的外部标识符,在用户侧应用中被使用,而在内核中,内核为每个对象都分配了一个对应的内部标识符。




  1. 软件包和工具集



5.1. 内核版本要求



许多Linux发行版都提供了带流量控制(QoS)功能的内核,该功能作为一个单独的模块存在,或直接编译在内核中。定制化的内核可能不包含流量控制功能,这时就可以按照下面列出的内核选项配置内核。



对于编译内核没有或只有一点经验的用户,建议参考KernelHOWTO。对于编译内核有经验的用户,在对流量控制有一定了解后,应该知道下面的选项哪一些应该被选择。



例1. 内核编译选项



#



QoS 和或公平排队(fair queueing)



#



CONFIG_NET_SCHED=y



CONFIG_NET_SCH_CBQ=m



CONFIG_NET_SCH_HTB=m



CONFIG_NET_SCH_CSZ=m



CONFIG_NET_SCH_PRIO=m



CONFIG_NET_SCH_RED=m



CONFIG_NET_SCH_SFQ=m



CONFIG_NET_SCH_TEQL=m



CONFIG_NET_SCH_TBF=m



CONFIG_NET_SCH_GRED=m



CONFIG_NET_SCH_DSMARK=m



CONFIG_NET_SCH_INGRESS=m



CONFIG_NET_QOS=y



CONFIG_NET_ESTIMATOR=y



CONFIG_NET_CLS=y



CONFIG_NET_CLS_TCINDEX=m



CONFIG_NET_CLS_ROUTE4=m



CONFIG_NET_CLS_ROUTE=y



CONFIG_NET_CLS_FW=m



CONFIG_NET_CLS_U32=m



CONFIG_NET_CLS_RSVP=m



CONFIG_NET_CLS_RSVP6=m



CONFIG_NET_CLS_POLICE=y



按上面的选项编译后的内核将能以模块化的方式提供本文档所讨论的任何组件。当需要使用相应功能时,用户可以使用modprobe来加载对应模块。再说一次,推荐有困惑的用户去阅读Kernel HOWTO,通过本文档并不能解决有关使用Linux内核的问题。



5.2. iproute2 工具 (tc)



iproute2是一组命令行工具组件,用来操作一台机器上有关IP网络配置的内核结构。有关这些工具的技术文档,参见iproute2 documentation,如果想了解更多,可以参考linux-ip.net 上的文档。在iproute2软件包的众多工具中,tc是唯一用来进行流量控制的工具,本指南将忽略其它工具。



由于tc直接作用于内核来创建、删除、修改流量控制结构,所以在编译tc时需要提前安装你想使用的所有qdisc。特别的,HTB qdisc还末在上游iproute2软件包中被支持,更多信息请参见7.1小节。



例2. 使用tc命令



[root@leander]# tc










Usage: tc [ OPTIONS ] OBJECT { COMMAND help }










where OBJECT := { qdisc class filter }


   OPTIONS := { -s[tatistics] | -d[etails] | -r[aw] }


每个对象都有更多且不同的选项,本文档不会完整涉及到所有选项,下面的例子将尽可能展现tc命令的使用。可以访问LARTC HOWTO来获取更多的例子,如果想更好的理解tc,可以参考内核和iproute2的代码。



例3. tc qidsc



[root@leander]# tc qdisc add \




             dev eth0     \




             root         \




             handle 1:0   \




             htb           



添加一个排队规则,也可以使用del来删除。



指定将和新排队规则相关联的设备。



对tc来说,root就是指 “egress”,但是这里必需使用单词“root”。对于另一个有功能限制的qdisc:ingress qdisc,其可以被关联到同一设备上。



handle 是用户指定的一个编号,其格式是主编号:次编号。对任何排队规则句柄来说,次编号必需是0。排队规则(qidsc)句柄的一种可用简写形式是“1:”,当没有指定次编号时就默认为0。



需要使用的排队规则,本例中是HTB。排队规则需要的一些参数可以跟在后面,本例中,我们没有其他参数。



上例是使用tc工具给一个设备添加排队规则的简单例子,下面是使用tc给一个存在的父class添加子class的例子。



例4. tc class



[root@leander]# tc class add \



             dev eth0     \ 
parent 1:1 \
classid 1:6 \
htb \
rate 256kbit \
ceil 512kbit



添加一个class,也可以用del删除。



指定我们将要关联新class的设备。



指定我们将要关联新class的父class句柄。



标识此class的唯一句柄(主编号:次编号)。次编号必需为非零值。



带分类的qdisc需要所有的子class都和其是相同的类型,因此,HTBqdisc将包含HTB classes。



class的参数,查看7.1节来获取关于这些参数的更多详细信息。



例5. tc filter



[root@leander]# tc filter add \



             dev eth0                 \ 
parent 1:0 \
protocol ip \
prio 5 \
u32 \
match ip port 22 0xffff \
match ip tos 0x10 0xff \
flowid 1:6 \
police \
rate 32000bps \ (11)
burst 10240 \ (12)
mpu 0 \ (13)
action drop/continue (14)



添加一个filter,也可以使用del来删除。



指定新的filter将要关联的设备。



指定新的filter将要关联的父句柄。



这个参数是必要的,它应该被显示的使用,尽管我不知道它还有什么其他功能。



prio参数能使一个filter在另一个之前被使用,pref是prio的同义词。



这是一个分类器(classifer),所有tc filter命令都需包含该选项。



这些是分类器的参数。在本例中,带有服务标识且端口号是22的数据包将会被选择。



flowid指定了一个目标class(或qdisc)句柄,filter所选择的数据包将发往这个句柄所指向的class(或qdisc)。



这是一个监管器(policer),在tc fitler命令中,这是一个可选选项。



(11) 当超过这个速率时,监管器将执行一个动作,低于这个速率时,监管器将执行另一个动作。



(12) burst相当于HTB中的burst(burst采用的是桶(bucket)原理)。



(13) 被监管的最小数据单位。为了统计所有流量,使用mpu 0。



(14) action指定了当流量大于给politer所配置的 rate时应采取的动作。第一个词指明了当流量超过rate时所要执行的操作,第二个词指明了其他情况下应该采取的操作。



正如你在上面所看到的,tc命令行工具语法晦涩且复杂,即使是一个简单的操作都要进行复杂的配置。当然你不必感到吃惊,因为在Linux下,我们有更容易的方式来配置流量控制结构。参见下一小节5.3。



5.3. tcng, 下一代流量控制(Traffic Control Next Generation)



此节有待补充;让我们为tcng喝彩。有关tcng的信息可参见Traffic Control using tcng and HTB HOWTO和tcng documentation。



下一代流量控制(也就是这里的tcng)将会以一种非常简单的方式提供Linux下流量控制所有的功能。



5.4. IMQ, 中间队列设备



此节有待补充;对于IMQ的探讨是必须的。可以参考Patrick McHardy网站上有关IMQ的内容。




  1. 无分类排队规则 (qdiscs)



下面的任一无类排队规则都可以作为一个网络接口的主要排队规则,或者作为分类排队规则的叶子分类(leaf class)。下面的这些排队规则都是在Linux下使用的基本规则。



6.1. FIFO, 先进先出 (pfifo and bfifo)



FIFO不是Linux网络接口上使用的默认排队规则(qdisc),有关默认排队规则(pfifo_fast)的完整信息请参考6.2节。



FIFO算法是所有Linux网络接口默认排队规则的基本组成形式。FIFO既不能对流量进行整形也不能对数据包进行重新排列,当收到数据包后它只能尽快的传输它们。FIFO也是所有新创建的class内部使用的排队规则,直到被其他排队规则或class替换。



实际使用的FIFO都有一个缓冲区来防止溢出,当FIFO不能及时将它所收到的数据包出队时就使用缓冲区将数据包暂时缓存起来。Linux运用了两种类型的FIFO,一种基于字节,一种基于报文。不管是哪种类型的FIFO,队列的大小都由参数limit来定义。基于报文的fifo(pfifo)其单位就是报文,基于字节的fifo(bfifo)其单位就是字节。



例6. 为基于报文或字节的FIFO设置一个大小



[root@leander]# cat bfifo.tcc



/*



*在eth0上创建一个大小为10k字节的FIFO队列



*



*/



dev eth0 {



egress {

fifo (limit 10kB );

}


}



[root@leander]# tcc < bfifo.tcc



======================Device eth0 ============================



tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0



tc qdisc add dev eth0 handle 2:0 parent 1:0 bfifo limit 10240



[root@leander]# cat pfifo.tcc



/*



*在eth0上创建一个可容纳30个数据包的FIFO队列



*



*/



dev eth0 {



egress {

fifo (limit 30p );

}


}



[root@leander]# tcc < pfifo.tcc



======================Device eth0 ============================



tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0



tc qdisc add dev eth0 handle 2:0 parent 1:0 pfifo limit 30



6.2. pfifo_fast,Linux默认排队排队



pfifo_fast是Linux上所有接口的默认排队规则(qdisc)。pfifo_fast基于传统的FIFO排队规则,但它支持优先级,它为分离的流量提供了三种不同等级的通道(三条独立的FIFO)。最高等级的流量(交互数据流)被放入0号通道且被优先处理,通道1中的数据包优先于通道2中的数据包被处理。



pfifo_fast对用户来说没有什么需要配置的。有关priomap和Tos使用的更详细信息请参考pfifo-fast section of the LARTC HOWTO。



6.3. SFQ, 随机公平队列



SFQ 试图让任意数量的数据流都有平等的机会来向网络传输数据。它通过一个哈希函数将数据流分配到不同的FIFO队列中,然后以轮循的方式依次出队这些队列中的数据。由于所选择的哈希函数可能会产生明显的不公平性,哈希函数会被定期的更换,参数perturb用来设置哈希函数的更换周期。



例7. 创建一个SFQ



[root@leander]# cat sfq.tcc
/*
*
在eth0上创建一个周期为10的SFQ队列
*
*/



dev eth0 {
egress {
sfq( perturb 10s );
}
}
[root@leander]# tcc < sfq.tcc


======================== Device eth0 =======================



tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0
tc qdisc add dev eth0 handle 2:0 parent 1:0 sfq perturb 10



不幸的是,一些自作聪明的软件(例如Kazaa,eMule等等)破坏了公平排队的好处,它们持续不断的创建尽可能多的TCP会话。在许多网络中,如果应用能遵守规范,SFQ能很好的将网络资源分给对资源有竞争的数据流,但当某些讨厌的应用产生大量的数据流时就必需采用其它措施了。



参考6.4节,了解一种可供用户使用的,拥有更多参数的SFQ排队规则。



6.4. ESFQ, 扩展的随机公平队列



从概念上来讲,ESFQ除了拥有更多的可用参数外,和它的同辈SFQ没有什么不同。ESFQ只是为了克服上节所述的SFQ的缺点而被提出。它允许用户选择哈希算法来分配网络带宽,使带宽的分配更公平。



例8. ESFQ的使用



Usage: … esfq [ perturb SECS ] [ quantum BYTES ] [ depth FLOWS ]



    [ divisor HASHBITS ] [ limit PKTS ] [ hash HASHTYPE]


Where:











HASHTYPE := { classic src dst }


待补充,需要补充实际例子和解释。



6.5. GRED, 通用早期随机丢包



待补充,我从没有使用过GRED,需要实用例子和解释。



RED算法的原理表明,它在骨干网和核网上非常有用,在末级用户处几乎无用。查看数据流这一节来简单了解下TCP



6.6. TBF, 令牌桶过滤器



TBF是建立在令牌桶之上,它对接口上的流量进行整形。为了限制某一特定接口上报文的出队速率,TBF排队规则将是一个不错的选择,它能将报文的发送速率降到指定值。



如果有足够的令牌,数据包就被传输,否则,数据包会被延迟。通过这种方式延迟报文将会给报文的往返造成人为的延时。



例9. 创建一个速率为256kbit/s的TBF



[root@leander]# cat tbf.tcc



/*




  • 在eth0上创建一个速率为256kbit/s的TBF



*



*/



dev eth0 {



egress {

tbf( rate 256 kbps, burst 20 kB, limit 20 kB, mtu 1514 B );

}


}



[root@leander]# tcc < tbf.tcc



======================== Device eth0 ===============================



tc qdisc add dev eth0 handle 1:0 root dsmark indices 1 default_index 0



tc qdisc add dev eth0 handle 2:0 parent 1:0 tbf burst 20480 limit 20480 mtu 1514 rate 32000bps




  1. 分类排队规则(qdiscs)



通过分类排队规则可以使流量控制更易操作、更灵活。记住,分类排队规则可以和filter相关联,这样就可以让数据包被送往特定的分类或子队列。



有几个常见的术语来描述和root qdisc以及末梢分类直接相关联的分类(class)。和root qdisc相关联的分类,通常被称为根分类(root class),或者更通用的被称为内部分类(inner class)。在特定排队规则中的末梢分类(terminal class)通常被称为叶子分类(leaf class),就好比一棵树的叶子一样。在本文中,除了将这种结构比喻成一棵树外,还会运用家庭成员关系来描述。



7.1. HTB, 分层令牌桶



HTB利用令牌和桶的概念,并基于分类和filter实现了一个复杂且精细的流量控制方法。通过复杂的租借机制(borrowingmodel),HTB能实现复杂且多样的流量控制机制。HTB最简单、最快速的应用就是整形(shaping)。



如果理解了令牌和桶,或者了解TBF的机制,那么学习HTB就轻而易举。HTB允许用户自己定义令牌和桶的属性,然后按照需求对这些桶分类。当和分类机制(classifying scheme)配合使用时,就能将流量控制得更为精细。



下面是tc工具在命令行上输出的HTB用法,尽管tcng有它自己的语法,但对于HTB的使用都是相同的。



例10. tc的HTB用法



Usage: … qdisc add … htb [default N] [r2q N]



default minor id of class to which unclassified packets are sent {0}



r2q DRR quantums are computed as rate in Bps/r2q {10}



debug string of 16 numbers each 0-3 {0}



… class add … htb rate R1 burst B1 [prio P] [slot S] [pslot PS]



                  [ceil R2] [cburst B2] [mtu MTU] [quantum Q]


rate rate allocated to this class (class can still borrow)



burst max bytes burst which can be accumulated during idle period {computed}



ceil definite upper class rate (no borrows) {rate}



cburst burst but for ceil {computed}



mtu max packet size we create rate map for {1600}



prio priority of leaf; lower are served first {0}



quantum how much bytes to serve from leaf at once {use r2q}



TC HTB version 3.3



7.1.1. 软件要求



不像这里讨论的其它规则,HTB是一个比较新的排队规则,你所使用的Linux发行版可能没有相应的操作工具或者没有HTB的功能。要使用HTB,就必需使用支持HTB的内核,内核主干版本2.4.20及其以上版本支持HTB,较低版本的内核需要打相应的补丁。为了在应用中使用HTB,参见HTB中有关tc的iproute2补丁信息。



7.1.2. 整流



HTB最常用的用法包含将网络流量限制在一个指定速率之下。



所有的整形都发生在叶子分类中(leaf class),在根(root)或内部(inner)分类(class)中不会进行整形,根分类仅仅决定租借机制如何分发可用令牌。



7.1.3. 租借



HTB排队规的一个基本组成部分就是租借机制。当子分类的流量超过了rate之后,就可以向父分类借用令牌。一个子分类会一直尝试向父分类借用令牌,直到该子分类的流量达到ceil,这个时候子分类就会将数据包入队,以等待有更多的可用令牌。HTB只创建两种基本类型的分类,下面的图表列出了在租借机制影响下,两种分类在各种可能状态可能会产生的相产动作。



表2. HTB分类在不同状态下可能会采取的动作



分类



类型



类状态



HTB 内部状态



动作



叶子(leaf)



< rate



HTB_CAN_SEND



只要有可用令牌就发送数据包 (不超过burst 个数据包)。



叶子(leaf)




rate, < ceil




HTB_MAY_BORROW



叶子分类会尝试向父分类借用令牌(token或ctoken),如有父分类有足够的令牌,叶子分类会以quantum的整数倍借用令牌发送数据,但发送的数据包总数不能超过cburst字节。



叶子(leaf)




ceil




HTB_CANT_SEND



将不会发送任何数据包,为了将速率限制在rate之下,会对数据包造成延时。



inner, root



< rate



HTB_CAN_SEND



内部分类向子分类借出令牌。



inner, root




rate, < ceil




HTB_MAY_BORROW



内部分类会尝试向父分类借用令牌(token或ctoken),然后以quantum的整数倍将借用的令牌再租借给它的子分类。



inner, root




ceil




HTB_CANT_SEND



内部分类既不会向父分类借用令牌,也不会向它的子分类借出令牌。



下图描绘了借用令牌时令牌的流向,以及向父分类归还令牌的方法。为了使租借模型能正常工作,必须明确的指定每个分类及其该分类所有子类的可用令牌数量。每个子分类都向它的父分类归还令牌,这样一级级归还,直到根分类。



任何想要借用令牌的子分类都向它的父分类借用,如果父分类由于超过了它的rate而没有令牌,父分类就会向它的父分类借用,这样一级级直到借到令牌或到达根分类为止。因此,借用令牌时,令牌从根向叶子的方向流动;归还令牌时,令牌从叶子向根的方向流动。



注意,该图中有多个根分类,每个根分类都可以模拟成一条虚拟线路。



7.1.4. HTB分类参数



default



这是HTB排队规则的一个可选参数,默认值为0, 当值为0时意味着会绕过所有和rootqdisc相关联的分类,然后以最大的速度出队任何未分类的流量。



rate



这个参数用来设置流量发送的最小期望速率。这个速率可以被当作承诺信息速率(CIR), 或者给某个叶子分类的保证带宽。



ceil



这个参数用来设置流量发送的最大期望速率。租借机制将会决定这个参数的实际用处。 这个速率可以被称作“突发速率”。



burst



这个参数是rate桶的大小(参见令牌桶这一节)。HTB将会在更多令牌到达之前将burst个字节的数据包出队。



cburst



这个参数是ceil桶的大小(参见令牌桶这一节)。HTB将会更多令牌(ctoken)到达之前将cburst个字节的数据包出队。



quantum



这个是HTB控制租借机制的关键参数。正常情况下,HTB自己会计算合适的quantum值,而不是由用户来设定。对这个值的轻微调整都会对租借和整形造成巨大的影响,因为HTB不仅会根据这个值向各个子分类分发流量(速率应高于rate,小于ceil),还会根据此值输出各个子分类中的数据。



r2q



通常,quantum 的值由HTB自己计算,用户可以通过此参数设置一个值来帮助HTB为某个分类计算一个最优的quantum值。



mtu



prio



7.1.5. 规则



下面是一些从http://docum.org/ 和LARTC mailing list上挑选出来的使用HTB的一般性提示。这些只是针对初学者的提示,以便初学者能最大化的掌握HTB,如果你有HTB的实际使用经验,就没必要看这些建议了。


· 整形只会发生在HTB的叶子分类中,参见第7.1.2小节。



· 由于只会在HTB的叶子分类中进行整形,所以所有叶子分类的速率(rate)之和应该不大于父分类速率的最大值(ceil)。在理想情况下,叶子分类的总速率应该和父分类的速率相同,这样父分类总是会有剩余的带宽分配给子分类。



这是HTB的一个关键点,我们一再重复。只有叶子分类能对流量进行整形,数据包也只会在叶子分类中被延时,所有的内部分类(从叶子分类开始一直到根分类的所有分类)只是决定如何进行租借。



· quantum只会在某个分类的速率大于rate小于ceil时起作用。



· quantum应该被设置成MTU或更大。即使quantum的值被设置得过小,HTB只要有机会也会出队一个数据包,不过这样就不能准确的计算真实的带宽消耗了。



· 父分类向子分类租出的令牌以quantum的倍数增加,所以为了最大粒度、最为迅速的公平分发带宽,quantum的值应该尽可能的小,但不能小于MTU。



· token和ctoken只有在叶子分类中才有区别,因为非叶子分类只是向子分类租借令牌。



· HTB的租借模型应该更为准备的被称为“使用”。



7.2. HFSC, 分层公平服务曲线



HFSC分类排队规则在延时敏感型流量和吞吐敏感型流量之间做了一个平衡。在拥塞状态下,HFSC排队规则会根据服务区线的定义来决定是否发送延时敏感型数据包。访问HFSC Schedulingmit Linux参阅在Linux下使用HFSC的德文文档,或者访问HFSC Scheduling with Linux阅读该德文文档的英译版。你也可以通过访问AHierarchical Fair Service Curve Algorithm For Link-Sharing, Real-Time andPriority Services来获取最初的研究论文。



本节将会在稍后完善。


7.3. PRIO, 优先级调度



PRIO分类排队规则有一个非常简单的准则,当它准备发送数据包时,它会检查第一个分类中有没有数据包,如果有就发送数据包,如果没有就检查下一个分类,直到队列中的最后一个分类。



本节将会在稍后完善。



7.4. CBQ, 基于类的队列



CBQ是流量控制系统的典型排队算法,本节稍后会完善。




  1. 流量控制的常见规则和方法



8.1. Linux流量控制的一般规则



下面的一些规则可以使流量控制的学习更简单,不管是使用tcng来配置或tc来配置,Linux下的流量控制结构都是相同的。



应当只有在路由器出现瓶颈时才去实施流量整形,而且流量整形值应该比最大带宽稍低,这样就能防止从其它路由器过来的大量数据流阻塞路由器,同时也能保证路由器的最大处理能力。
只能对设备发送的流量进行整形,当流量被入口接收后,就不能对其进行整形了。该问题的传统解决方案是利用ingress policer。
每个接口都有一个默认排队规则,当接口上没有显示指明使用哪一种qdisc时就会使用默认qdisc。
给接口配置一个没有子class的分类qdisc是毫无用处的,仅仅消耗了CPU资源。
每个新创建的class内部默认都是使用的FIFO排队规则,可以用其它排队规则来代替FIFO,如果有一个子class和这个新建的class相关联,那么FIFO排队规则将会被删除。
可以将分类(class)和根排队规则(root qdisc)直接关联起来,用来模拟一个虚拟线路。
filter可以和分类(class)或者一个可分类排队规则(classful qdisc)关联起来。
8.2. 在已知带宽的线路上实施流量控制



在已知带宽的线路上实施流量控制,HTB是一个完美的选择。最内部(最顶端)的分类可以配置成允许最大带宽的流量进入,然后数据流可以被划分到各个子分类(children class)中,我们可以为某些子类保留一定带宽,或者让某些特殊的流量优先传送。



8.3. 在可变(或未知)带宽的线路上实施流量控制



理论上来说,PRIO调度器(scheduler)是在可变带宽上实施流量控制的完美方案,因为它是一个工作保留型的排队规则(这也意味着PRIO没有整形功能)。在一个带宽未知或有波动的网络中,PRIO调度器简单的先将最高优先级通道中的数据包出队,然后再将次优先级队列中的数据包出队。



8.4. 基于流来分享、划分带宽



对网络带宽的竞争有多种形式,SFQ是解决竞争的最易方式之一。通过使用SFQ,流量能被划分为不同的流,每条流都会被公平的服务。对于行为良好的应用和用户来说,使用SFQ和ESFQ将能高效的完成大多数有带宽分享需求的情形。



这些公平排队算法的死穴就是某些行为不端的应用或用户会同时打开太多的连接(例如emule,eDonkey,Kazaa)。通过创建大量的数据流,这些应用会占用公平排队算法中的大多数资源。换种方式来说,就是公平排队算法对那些创建大量数据流的应用毫无办法,它也不能去惩罚该用户,你只能采取其它的对应措施。



8.5. 基于IP来分享、划分带宽



对于网络管理员来说,这是将带宽划分给用户的一个很好的方式。但不幸的是,没有简单的方案来实现它,随着网络中设备的增加它会变得更复杂。



如果要将网络带宽公平的分给N个IP地址,那么就需要N个分类(classs)。




  1. 用于Qos和流量控制的脚本



9.1. wondershaper



待完善,参见wondershaper。



9.2. 用于ADSL宽带的指南脚本 (myshaper)



待完善,参见myshaper。



9.3. htb.init



待完善,参见htb.init。



9.4. tcng.init



待完善,参见tcng.init。



9.5. cbq.init



待完善,参见cbq.init。




  1. 图表



10.1. 总图



下图是分类排队规则各组件之间的关系总图(图中是HTB排队规则)。点这里可以查看大图



例11. tcng配置HTB示例



/*



*





  • 可以在下面网址中获取模拟图




  • http://linux-ip.net/traffic-control/htb-class.png





*



*/



$m_web = trTCM (



             cir 512  kbps,  /* 承诺信息速率 */

cbs 10 kB, /* 承诺突发信息速率 */

pir 1024 kbps, /* 峰值信息速率 */

pbs 10 kB /* 突发峰值信息速率 */

) ;


dev eth0 {



egress {



class ( <$web> ) if tcp_dport == PORT_HTTP && __trTCM_green( $m_web );

class ( <$bulk> ) if tcp_dport == PORT_HTTP && __trTCM_yellow( $m_web );

drop if __trTCM_red( $m_web );

class ( <$bulk> ) if tcp_dport == PORT_SSH ;



htb () { /* root qdisc */



class ( rate 1544kbps, ceil 1544kbps ) { /* root class */



$web = class ( rate 512kbps, ceil 512kbps ) { sfq ; } ;

$bulk = class ( rate 512kbps, ceil 1544kbps ) { sfq ; } ;



}

}

}


}




  1. 有关流量控制的资源链接



本部分列出了一些有关流量控制和流量控制软件的文档链接。每个链接下面都有一个该链接内容的简单描述。



· HTB site, HTBuser guide and HTBtheory (Martin “devik” Devera)



分层令牌桶, 也就是HTB,是一个分类排队规则。它被广泛的使用和支持,其拥有完善的用户使用手册和网站 Stef Coene’s site。



· General Quality of Service docs(Leonardo Balliache)



在这个网站上有许多易懂的介绍性文档,特别是有很多优秀的概述文章。



· tcng (Traffic Control NextGeneration) and tcngmanual (WernerAlmesberger)



tcng软件包包含了一个语言,以及一组用来创建和测试流量控制结构的工具。除了能以tc命令的方式输出外,它还能够为非Linux应用提供输出。在本文档中被忽视掉的关键部分是tscim流量控制模拟器



tcng软件包提供的帮助手册已经通过latex2html工具转换成了HTML格式,该版本将通过TeX文档来发布。



· iproute2 and iproute2 manual (Alexey Kuznetsov)



这里是iproute2套件的源代码,包含了必不可少的tc二进制可执行命令。注意,iproute2-2.4.7-now-ss020116-try.tar.gz并不支持HTB,需要从HTB上获取一个支持HTB的补丁。



这里有该工具套件中所有工具的帮助文档,尽管有关tc的文档可能不完整。当对帮助文档中的内容有疑惑时,最好去LARTC HOWTO寻找相关答案。



· Documentation, graphs, scripts and guidelines to traffic controlunder Linux (StefCoene)



Stef Coene已经收集了在Linux下使用QoS的一些脚本、建议、统计数据和测试结构。 在Stef的站点上还有一些非常实用的图表和指南。



· LARTC HOWTO (bert hubert, et. al.)



Linux高级路由和流量控制指南(Linux Advanced Routing and Traffic Control HOWTO)是讲解Linux下复杂流量控制技术的有用文档。流量控制入门指南(Traffic ControlIntroduction HOWTO)应该向读者提供足够的应用背景及流量控制思想,LARTC HOWTO是读者查找流量控制信息的好地方。



· Guide to IP Networking with Linux (Martin A. Brown)



虽然和流量控制没有直接联系,但这个站点上有一些和Linux IP层有关的文章和常见资源。



· WernerAlmesberger’s Papers



Werner Almesberger是Linux流量控制的主要开发者和拥护者之一(他也是tcng的作者)。他的文章《Linux流量控制-应用概述》,是描述Linux内核中流量控制架构的一份重要文档,你可以获取该文档的PDF 或 PS版。



· Linux DiffServ project



下面这段内容是从DiffServ网站主页上毫不犹豫的剪切过来的…



差分服务 (简称: Diffserv) 为网络流量提供不同类或不同等级的服务。差分服务的一个关键特征是:流可以在网络中聚合在一起形成一条聚合流,因此核心路由器只需要识别少量的聚合流就行了,即使一条聚合流中可能包含成千上万条独立的流。
Linux操作系统中的流量控制框架创建了一个通用环境,它集成了所有用于限制和流量整形的可以互联的不同元素。在实际操作中这些元素甚至可以作为一个模块动态地加载和卸载。



TC(Traffic Control)工具提供了一个命令行用户接口来配置Linux流量控制。该工具让用户可以设定并配置几乎所有的流量控制框架要素,比如排队规则(qdisc)、类(class)及过滤器(filter),他们之间的关系见下图。

排队规则:每个网络设备配有一个排队规则。通常,要发送的报文被送到一个排队规则中并且按照特定规则在此队列中排序。

类:排队规则可以有多个接口,这些接口用于向队列管理插入报文。在单个排队规则中,可以把报文分配到不同的类。

过滤器:通常用来将外发报文分片到排队规则的类中。

排队规则

Linux可支持无类排队规则和分类排队规则。无类排队规则包括FIFO(先进先出)、TBF(令牌桶过滤器)、SFQ(随机公平队列)等;分类排队规则包括PRIO(优先级)、CBQ(类基队列)、HTB(分层令牌桶)等。

FIFO

FIFO(pfifo_fast)

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

pfifo_fast 队列规定作为硬性的缺省设置,不能对它进行配置。

TBF & HTB

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

TBF 的实现在于一个缓冲器(桶),它不断地被一些称为令牌的虚拟数据以特定速率填充。桶最重要的参数就是它的大小,也就是它能够存储令牌的数量。每个到来的令牌从数据队列中收集一个数据包,然后从桶中被删除。如下图。

这个算法将令牌流和数据流进行了紧密的关联,我们有以下三种情景:

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

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

数据流以大于令牌流的速率到达TBF。这意味着桶里的令牌很快就会被耗尽。导致TBF中断一段时间,称为“越限”。如果数据包持续到来,将发生丢包。

TBF提供了一些可控参数,如令牌桶大小、令牌流入速率、峰值速率、排队时延等。

例如:

# tc qdisc add dev eth0 root tbf rate 512kbit latency 30ms burst 1600

它的意思是在eth0上设置一个tbf过滤队列,网络带宽为512kbit,延迟为30m,突发数据量(缓冲区)为1600个字节。

分层令牌桶(Hierarchical Token Bucket,HTB)即分类的令牌桶过滤器,它可以通过TBF实现带宽限制,也能够划分类别的优先级。

SFQ

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

SFQ的关键词是“会话”(或称作“流”),主要针对一个TCP会话或者UDP流。流量被分成相当多数量的FIFO 队列中,每个队列对应一个会话。数据按照简单轮转的方式发送, 每个会话都按顺序得到发送机会。

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

因为使用了散列,所以可能多个会话分配在同一个队列里,从而需要共享发包的机会,也就是共享带宽。为了不让这种效应太明显,SFQ 会频繁地改变散列算法,以便把这种效应控制在几秒钟之内。

需要注意的是:只有当出口网卡确实已经挤满了的时候,SFQ才会起作用,否则在Linux 机器中根本就不会有队列,SFQ 也就不会起作用。

SFQ基本上不需要手工调整:它的参数有perturb和quantum。

例如:

# 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 个可以同时激活。每隔10 秒种散列算法更换一次。

PRIO

PRIO 队列规定并不进行整形,它仅仅根据配置的过滤器把流量进一步细分。可以认为PRIO 队列规定是pfifo_fast 的一种衍生物,区别在每个波段都是一个单独的类,而非简单的FIFO。

当数据包进入PRIO 队列规定后,将根据你给定的过滤器设置选择一个类。缺省情况下有三个类,这些类仅包含纯FIFO 队列规定而没有更多的内部结构。可以把它们替换成需要的任何队列规定。

每当有一个数据包需要出队时,首先处理:1类。只有当标号更小的类中没有需要处理的包时,才会标号大的类。

当希望不仅仅依靠包的TOS,而是想使用tc所提供的更强大的功能来进行数据包的优先权划分时,可以使用这个队列规定。它也可以包含更多的队列规定,而pfifo_fast 却只能包含简单的fifo 队列规定。

因为它不进行整形,所以使用时与SFQ 有相同的考虑:要么确保这个网卡的带宽确实已经占满,要么把它包含在一个能够整形的分类的队列规定的内部。后者几乎涵盖了所有cable modems 和DSL 设备。

严格地说,PRIO 队列规定是一种Work-Conserving 调度。

CBQ

CBQ(Class Based Queueing,基于类的队列)是一种基于类的算法,根据流量特征处理数据包,并确保一定的传输速率。接收的数据包根据变量如差分服务代码点(DSCP:Differentiated Services Code Point)中的IP协议头、IP 地址、应用程序或协议、URL或其它信息等进行分类。每类流量被分配到指定的FIFO(First In First Out)队列,其中每个队列的使用由部分路由器总带宽决定。如果队列为空闲,带宽便可以供其它队列使用。同时CBQ也是一种QoS方案,用于识别不同类型的流量并根据预置的参数对流量进行排队。

它是最复杂、最琐碎、最难以理解的队列规定。这是因为CBQ算法本身的不精确,而且与Linux 的内在机制不协调造成的。

Category linux