在著手學(xué)習(xí)TC采用如下單位來描述帶寬:
mbps = 1024 kbps = 1024 * 1024 bps => byte/s
mbit = 1024 kbit => kilo bit/s
mb = 1024 kb = 1024 * 1024 b => byte
mbit = 1024 kbit => kilo bit
內(nèi)定:數(shù)值以bps和b方式儲存。但當(dāng)設(shè)置 1Mbit = 1024 Kbit = 1024 * 1024 bps => byte/s
提醒:bit=1位,相當(dāng)于一個0 或1(開或關(guān));byte=1字節(jié),相當(dāng)于一個英文字母的大小。
8bit=1byte,所以往往聽說帶寬是10M是指bit,我們看到的下載速度是byte/s =10M/8byte的來。
隊列和隊列規(guī)則
利用隊列,我們可以控制數(shù)據(jù)發(fā)送的方式。但我們只能對發(fā)送數(shù)據(jù)進(jìn)行控制(或稱為流量整形)。
由 于網(wǎng)絡(luò)的工作機制,我們無法直接控制別人向我們發(fā)送什么數(shù)據(jù)。然而,Internet主要依靠TCP/IP,它的一些特性很有用。因為TCP/IP沒辦法 知道兩個主機之間的網(wǎng)絡(luò)容量,所以它會試圖越來越快地發(fā)送數(shù)據(jù)(所謂的“慢啟動”),在因為網(wǎng)絡(luò)容量不夠而開始丟失數(shù)據(jù)時,才放慢發(fā)送數(shù)據(jù)的速度。
這就像你家門口的郵箱一樣,當(dāng)郵箱幾乎塞滿了郵件時,你會希望不要再發(fā)送郵件了。在Internet上可以做到這一點。如果你有一個路由器,并且希望防止某些主機下載速度太快,你需要在路由器的內(nèi)網(wǎng)卡上進(jìn)行流量控制。
你還要保證你正在控制的是流量瓶頸環(huán)節(jié)。如果你有一個100M以太
簡單的無類隊列規(guī)則
如前所述,利用隊列,我們決定了數(shù)據(jù)被發(fā)送的方式。無類隊列能夠接收數(shù)據(jù)和重新編排、延遲或丟棄數(shù)據(jù)包。
這可以用作對于整個 最廣泛應(yīng)用的規(guī)則是pfifo_fast隊列規(guī)則,因為它是缺省配置。還有其他隊列規(guī)則,后面會有所介紹。每種隊列都有它們各自的優(yōu)勢和弱點。
1.pfifo_fast
這個隊列的特點就像它的名字一樣——先進(jìn)先出(FIFO),也就是說沒有任何數(shù)據(jù)包被特殊處理。這個隊列有3個所謂的“頻道”(band)。FIFO規(guī)則應(yīng)用于每一個頻道。并且:如果在0頻道有數(shù)據(jù)包等待發(fā)送,1頻道的包就不會被處理,1頻道和2頻道之間的關(guān)系也是如此。
內(nèi)核遵照數(shù)據(jù)包的TOS標(biāo)記,把帶有“最小延遲”標(biāo)記的包放進(jìn)0頻道。
*參數(shù)與使用*
pfifo_fast隊列規(guī)則作為硬性的缺省設(shè)置,不能對它進(jìn)行配置。
其缺省配置如下:
priomap:
內(nèi)核規(guī)則,根據(jù)數(shù)據(jù)包的優(yōu)先權(quán)情況,映射到相應(yīng)的頻道。這個映射過程是根據(jù)數(shù)據(jù)包的TOS字節(jié)進(jìn)行的。
TOS是這樣的:
TOS字段的4個bit是如下定義的:
因為在這4bit的后面還有一個bit(MBZ),所以TOS字段的實際值是上述值的2倍。tcpdump -v -v命令可以讓你看到整個TOS字段的情況,而不僅僅是這4個bit,也就是你在下表的第一列看到的值:
第二列寫著與4個TOS位相關(guān)的數(shù)值,接著第三列對應(yīng)是它們的意義。比如,15表示一個數(shù)據(jù)包要求最小成本、最大可靠性、最大吞吐量和最小延遲。
第四列寫出了Linux內(nèi)核對于TOS位的理解,并表明了它們對應(yīng)哪種優(yōu)先權(quán)。最后一列表明缺省的權(quán)限圖。在命令行里,缺省的權(quán)限圖應(yīng)該是:
1,2,2,2,1,2,0,0,1,1,1,1,1,1,1,1
也就是說,比如優(yōu)先權(quán)4將被映射到1頻道。權(quán)限圖允許你列出更高的優(yōu)先權(quán)值(只要小于7),它們不對應(yīng)TOS映射,但是有其它的意圖。
下表來自RFC 1349,告訴你應(yīng)用程序可能如何設(shè)置它們的TOS:
tx queuelen
隊列的長度來自
如設(shè)置隊列長度為10,執(zhí)行:ifconfig eth0 txqueuelen 10(不能用2.令牌桶過濾器(TBF)
令牌桶過濾器(TBF,Token Bucket Filter)是一個簡單的隊列規(guī)則:只允許以不超過事先設(shè)定的速率到來的數(shù)據(jù)包通過,但可能允許短暫突發(fā)流量超過設(shè)定值。
TBF很精確,對于網(wǎng)絡(luò)和處理器的影響都很小。所以如果您想對一個
TBF的實現(xiàn)在于一個緩沖器(桶),該緩沖器(桶)不斷地被一些叫做”令牌”的虛擬數(shù)據(jù)以特定速率(token rate)填充著。桶最重要的參數(shù)就是它的大小,也就是它能夠存儲令牌的數(shù)量。
每個到來的令牌從數(shù)據(jù)隊列中收集一個數(shù)據(jù)包,然后從桶中被刪除。這個算法關(guān)聯(lián)到兩個流上——令牌流和數(shù)據(jù)流,于是我們得到3種情景:
*數(shù)據(jù)流以等于令牌流的速率到達(dá)TBF。這種情況下,每個到來的數(shù)據(jù)包都能對應(yīng)一個令牌,然后無延遲地通過隊列。
*數(shù)據(jù)流以小于令牌流的速度到達(dá)TBF。通過隊列的數(shù)據(jù)包只消耗了一部分令牌,剩下的令牌會在桶里積累下來,直到桶被裝滿。剩下的令牌可以在需要以高于令牌流速率發(fā)送數(shù)據(jù)流的時候消耗掉,這種情況下會發(fā)生突發(fā)傳輸。
*數(shù)據(jù)流以大于令牌流的速率到達(dá)TBF。這意味著桶里的令牌很快就會被耗盡。導(dǎo)致TBF中斷一段時間,稱為”越限”(overlimit)。如果數(shù)據(jù)包持續(xù)到來,將發(fā)生丟包。
第三種情景非常重要,因為它會對數(shù)據(jù)通過過濾器的速率進(jìn)行整形。令牌的積累可以導(dǎo)致越限的數(shù)據(jù)進(jìn)行短時間的突發(fā)傳輸而不必丟包,但是持續(xù)越限的話會導(dǎo)致傳輸延遲直至丟包。實際的實現(xiàn)是針對數(shù)據(jù)的字節(jié)數(shù)進(jìn)行的,而不是針對數(shù)據(jù)包進(jìn)行的。
*參數(shù)與使用*
TBF提供了一些可調(diào)控的參數(shù)。第一個參數(shù)永遠(yuǎn)可用:
limit/latency
limit確定最多有多少數(shù)據(jù)(字節(jié)數(shù))在隊列中等待令牌。你也可以通過設(shè)置latency來指定這個參數(shù),latency參數(shù)確定了一個包在TBF中等待傳輸?shù)淖铋L等待時間。兩者計算決定桶的大小、速率和峰值速率。
burst/buffer/maxburst
桶的大小,以字節(jié)計。這個參數(shù)指定了最多可以有多少個令牌能夠即刻被使用。通常,管理的帶寬越大,需要的緩沖器就越大。在Intel體系上,10Mbit/s的速率需要至少10k字節(jié)的緩沖區(qū)才能達(dá)到期望的速率。
如果你的緩沖區(qū)太小,就會導(dǎo)致到達(dá)的令牌沒有地方放(桶滿了),這會導(dǎo)致潛在的丟包。
MPU
一個零長度的包并不是不耗費帶寬。比如以太網(wǎng),數(shù)據(jù)幀不會小于64字節(jié)。MPU(Minimum Packet Unit,最小分組單元)決定了令牌的最低消耗。
rate
速度操縱桿。參見上面的limit。
如果桶里存在令牌而且允許沒有令牌,相當(dāng)于不限制速率(缺省情況)。如果不希望這樣,可以調(diào)入以下參數(shù):
peakrate(峰值速率)
如果有可用的令牌,數(shù)據(jù)包一旦到來就會立刻被發(fā)送出去,就像光速一樣。那可能并不是你希望的,特別是你有一個比較大的桶的時候。
峰值速率可以用來指定令牌以多快的速度被刪除。用書面語言來說,就是:釋放一個數(shù)據(jù)包,然后等待足夠的時間后再釋放下一個。我們通過計算等待時間來控制峰值速率。例如:UNIX定時器的分辨率是10毫秒,如果平均包長10kb,我們的峰值速率被限制在了1Mbps。
MTU(Maximum Transmission Unit, 最大傳輸單元)/minburst
但是如果你的常規(guī)速率比較高,1Mbps的峰值速率就需要調(diào)整。要實現(xiàn)更高的峰值速率,可以在一個時鐘周期內(nèi)發(fā)送多個數(shù)據(jù)包。最有效的辦法就是:再創(chuàng)建一個令牌桶!這第二個令牌桶缺省情況下為一個單個的數(shù)據(jù)包,并非一個真正的桶。
要計算峰值速率,用MTU乘以100就行了。(應(yīng)該說是乘以HZ數(shù),Intel體系上是100,Alpha體系上是1024)
*配置范例*
這是一個非常簡單而實用的例子:
# root tbf rate 220kbit latency 50ms burst 1540
為什么它很實用呢?如果你有一個隊列較長的網(wǎng)絡(luò)設(shè)備,比如DSL modem或者cable modem什么的,并通過一個快速設(shè)備(如以太
這是因為上傳數(shù)據(jù)會充滿modem的隊列,而這個隊列為了改善上載數(shù)據(jù)的吞吐量而設(shè)置的特別大。你可能為了提高交互性只需要一個不太大的隊列,也就是說你希望在發(fā)送數(shù)據(jù)的時候干點其他的事情。
上面的命令行并非直接影響了modem中的隊列,而是通過控制Linux中的隊列而放慢了發(fā)送數(shù)據(jù)的速度。
把220kbit修改為你實際的上載速度再減去幾個百分點。如果你的modem確實很快,就把“burst”值提高一點。
3.隨機公平隊列(SFQ)
SFQ(Stochastic Fairness Queueing,隨機公平隊列)簡單實現(xiàn)公平隊列算法。它的精確性不如其它的方法,但是它在實現(xiàn)高度公平的同時,需要的計算量卻很少。
SFQ的關(guān)鍵詞是”會話”或“流”,主要針對一個TCP會話或者UDP流。流量被分成相當(dāng)多數(shù)量的FIFO隊列中,每個隊列對應(yīng)一個會話。數(shù)據(jù)按照簡單輪轉(zhuǎn)的方式發(fā)送,每個會話都按順序得到發(fā)送機會。
這
種方式非常公平,保證了每一個會話都不會沒其它會話所淹沒。SFQ之所以被稱為“隨機”,是因為它并不是真的為每一個會話創(chuàng)建一個隊列,而是使用一個散列
算法,把所有的會話映射到有限的幾個隊列中去。因為使用了散列,所以可能多個會話分配在同一個隊列里,從而需要共享發(fā)包的機會,也就是共享帶寬。為了不讓
這種效應(yīng)太明顯,SFQ會頻繁地改變散列算法,以便把這種效應(yīng)控制在幾秒鐘之內(nèi)。
有很重要的一點需要聲明:只有當(dāng)你的輸出
特別地,在你使用DSL modem或者cable modem的以太
*參數(shù)與使用*
SFQ基本上不需要手工調(diào)整:
perturb: 多少秒后重新配置一次散列算法。如果取消設(shè)置,散列算法將永遠(yuǎn)不會重新配置(不建議這樣做)。10秒應(yīng)該是一個合適的值。
quantum: 一個流至少要傳輸多少字節(jié)后才切換到下一個隊列。缺省設(shè)置為一個最大包的長度(MTU的大小)。不要設(shè)置這個數(shù)值低于MTU!
*配置范例*
如果你有一個
# 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:”
這個號碼是系統(tǒng)自動分配的一個句柄號(handle),“l(fā)imit”意思是這個隊列中可以有128個數(shù)據(jù)包排隊等待。一共可以有1024個散列目標(biāo)可以
用于速率審計,而其中128個可以同時激活。(no more packets fit in the queue!)每隔10秒種散列算法更換一次。
關(guān)于如何選用隊列的建議
總之,我們有幾種簡單的隊列,分別使用排序、限速和丟包等手段來進(jìn)行流量整形。
下列提示可以幫你決定使用哪一種隊列。
*如果想單純地降低出口速率,使用令牌桶過濾器(tbf, token bucket filter)。調(diào)節(jié)桶的配置可用于控制很高的帶寬。
*如果你的鏈路已經(jīng)塞滿了,而你想保證不會有某一個會話獨占出口帶寬,使用隨機公平隊列(sfq, stochastical fairness queueing)。
*如果你有一個很大的骨干帶寬,并且了解了相關(guān)技術(shù)后,可以考慮前向隨機丟包(red, random eraly drop)。
*如果希望對入口流量進(jìn)行“整形”(不是轉(zhuǎn)發(fā)流量),可使用入口流量策略(ingress policer),注意,這不是真正的“整形”。
*如果你正在轉(zhuǎn)發(fā)數(shù)據(jù)包,在數(shù)據(jù)流出的網(wǎng)卡起決定性作用的時候,除非你希望讓數(shù)據(jù)包從多個網(wǎng)卡流出,在這種情況下還是使用入口策略(ingress policer)。
*如果你并不希望進(jìn)行流量整形,只是想看看你的
*最后,你可以進(jìn)行所謂的“社交整形”。你不能通過技術(shù)手段解決一切問題。用戶的經(jīng)驗技巧永遠(yuǎn)是不友善的。正確而友好的措辭可能幫助你的正確地分配帶寬!
術(shù)語
為了正確地理解更多的復(fù)雜配置,有必要先解釋一些概念。由于這個主題的歷史不長和其本身的復(fù)雜性,人們經(jīng)常在說同一件事的時候使用各種詞匯。
以下來自draft-ietf-diffserv-model-06.txt,Diffserv路由器的建議管理模型。關(guān)于這些詞語的嚴(yán)格定義請參考這個文檔。
隊列規(guī)則(Queuing Discipline,qdisc)
管理設(shè)備輸入(ingress)或輸出(egress)的算法。
根隊列規(guī)則(Root Qdisc)
根隊列規(guī)則就是直接依附于設(shè)備的隊列規(guī)則。
無類的隊列規(guī)則(Classless Qdisc)
一個內(nèi)部不包含可配置子類的隊列規(guī)則。
分類的隊列規(guī)則(Classiful Qdisc)
一個分類的隊列規(guī)則內(nèi)可以包含更多的類。其中每個類又進(jìn)一步地包含一個隊列規(guī)則,這個隊列規(guī)則可以是分類的,也可以是無類的。
類(Classes)
一個分類的隊列規(guī)則可以擁有很多類,類內(nèi)包含隊列規(guī)則。
分類器(Classifier)
每個分類的隊列規(guī)則都需要決定什么樣的包使用什么類進(jìn)行發(fā)送。分類器就是做這個用的。
過濾器(Filter)
分類是通過過濾器完成的。一個過濾器包含若干的匹配條件,如果符合匹配條件,就按此過濾器分類。
調(diào)度(Scheduling)
在分類器的幫助下,一個隊列規(guī)則可以裁定某些數(shù)據(jù)包可以排在其他數(shù)據(jù)包之前發(fā)送。這種處理叫做”調(diào)度”,比如此前提到的pfifo_fast就是這樣的。
整形(Shaping)
在一個數(shù)據(jù)包發(fā)送之前進(jìn)行適當(dāng)?shù)难舆t,以免超過事先規(guī)則好的最大速率,這種處理叫做”整形”。整形在egress處進(jìn)行。習(xí)慣上,通過丟包來降速也經(jīng)常被稱為整形。
策略(Policing)
通過延遲或是丟棄數(shù)據(jù)包來保證流量不超過事先規(guī)則的帶寬。在Linux中,策略總是規(guī)定丟棄數(shù)據(jù)包而不是延遲,即不存在ingress隊列。
Work-Conserving
對于一個work-conserving隊列規(guī)則,如果得到一個數(shù)據(jù)包,它總是立刻對它進(jìn)行分發(fā)。換句話說,只要
non-Work-Conserving
有些隊列——比如令牌桶過濾器——可能需要暫時停止發(fā)包以實現(xiàn)限制帶寬。也就是說它們有時候即使有數(shù)據(jù)包需要處理,也可能拒絕發(fā)送。
現(xiàn)在我們簡單了解了一些術(shù)語,讓我們看看它們的位置:
1、整個大方框表示內(nèi)核。
2、最左面的箭頭表示從網(wǎng)絡(luò)上進(jìn)入計算機的數(shù)據(jù)包。它們進(jìn)入Ingress隊列規(guī)則,并有可能被某些過濾器丟棄即所謂策略(在進(jìn)入內(nèi)核之前丟棄數(shù)據(jù)有利于節(jié)約CPU時間)。
3、數(shù)據(jù)包順利通過的話,如果它是發(fā)往本地進(jìn)程的,就會進(jìn)入IP協(xié)議棧處理并提交給該進(jìn)程。
4、如果它需要轉(zhuǎn)發(fā)而不是進(jìn)入本地進(jìn)程,就會發(fā)往egress。本地進(jìn)程也可以發(fā)送數(shù)據(jù),交給Egress分類器。
5、然后經(jīng)過審查,并放入若干隊列規(guī)則中的一個進(jìn)行排隊。這個過程叫做“入隊”。在不進(jìn)行任何配置的情況下,只有一個egress隊列規(guī)則——pfifo_fast——總是接收數(shù)據(jù)包。
6、數(shù)據(jù)包進(jìn)入隊列后,就等待內(nèi)核處理并通過某
7、這張圖僅僅表示了機器上只有一塊網(wǎng)卡都有它自己的ingress和egress。
分類的隊列規(guī)則
如果你有多種數(shù)據(jù)流需要進(jìn)行區(qū)別對待,分類的隊列規(guī)則就非常有用了。其中一種叫CBQ(Class Based Queueing,基于類的隊列)經(jīng)常被提起,以至于大家認(rèn)為CBQ就是鑒別隊列是否分類的標(biāo)準(zhǔn),這是不對的:
CBQ不過是家族中年紀(jì)最大的孩子而已,同時也是最復(fù)雜的。它并不能為你做所有你想做的事情。因此很多人認(rèn)為不可思議,因為他們受“sendmail效應(yīng)”影響較深,總是認(rèn)為復(fù)雜的且沒有文檔的技術(shù)肯定是最好的。
1.分類的隊列規(guī)則及其類中的數(shù)據(jù)流向
一旦數(shù)據(jù)包進(jìn)入一個分類的隊列規(guī)則,它就得被送到某一個類中——也就是需要分類。對數(shù)據(jù)包進(jìn)行分類的工具是過濾器。一定要記住:“分類器”是從隊列規(guī)則內(nèi)部調(diào)用的,而不是從其他地方。
過濾器會返回一個決定,隊列規(guī)則就根據(jù)這個決定把數(shù)據(jù)包送入相應(yīng)的類進(jìn)行排隊。每個子類都可以再次使用它們自己的過濾器進(jìn)行進(jìn)一步的分類,直到不需要分類為止,數(shù)據(jù)包才進(jìn)入該類包含的隊列規(guī)則等待處理。
除了能夠包含其它隊列規(guī)則之外,絕大多數(shù)分類的隊列規(guī)則還能夠進(jìn)行流量整形。這對于需要同時進(jìn)行調(diào)度(如使用SFQ)和流量控制的場合非常有用。
如果你僅僅使用SFQ,那什么用也沒有。因為數(shù)據(jù)包進(jìn)、出路由器時沒有任何延遲。雖然你的輸出2.隊列規(guī)則家族:根、句柄、兄弟和父輩
每塊網(wǎng)卡還有一個入口隊列規(guī)則以便對進(jìn)入的數(shù)據(jù)流進(jìn)行策略調(diào)整。
隊列規(guī)則的句柄有兩個部分:一個主號碼和一個次號碼。習(xí)慣上把根隊列規(guī)則稱為“1:”,等價于“1:0”。隊列規(guī)則的次號碼永遠(yuǎn)是0。
類的主號碼必須與它們父輩的主號碼一致。
*如何用過濾器進(jìn)行分類*
下圖給出一個典型的分層關(guān)系:
數(shù)據(jù)包是在根隊列規(guī)則處入隊和出隊的,而內(nèi)核只與“根”打交道。
一個數(shù)據(jù)包可能是按照下面這個鏈狀流程進(jìn)行分類的:
1: -> 1:1 -> 12: -> 12:2
數(shù)據(jù)包現(xiàn)在應(yīng)該處于12:2下屬的某個隊列規(guī)則中的某個隊列中。在這個例子中,樹的每個節(jié)點都附帶著一個過濾器,用來選擇下一步進(jìn)入哪個分支。這樣比較直觀。然而,這樣也是允許的:
1: -> 12:2
也就是說,根所附帶的一個過濾器要求把數(shù)據(jù)包直接交給12:2。
*數(shù)據(jù)包如何出隊并交給硬件
當(dāng)內(nèi)核決定把一個數(shù)據(jù)包發(fā)給網(wǎng)卡進(jìn)行交談。只有根隊列規(guī)則才能由內(nèi)核操作進(jìn)行出隊操作!
更進(jìn)一步,任何類的出隊操作都不會比它們的父類更快。這恰恰是你所需要的:我們可以把SFQ作為一個子類,放到一個可以進(jìn)行流量整形的父類中,從而能夠同時得到其父類的流量整形功能和SFQ的調(diào)度功能。
3.PRIO隊列規(guī)則
PRIO隊列規(guī)則并不進(jìn)行流量整形,它僅僅根據(jù)配置的過濾器把流量進(jìn)一步細(xì)分。你可以認(rèn)為PRIO隊列規(guī)則是pfifo_fast的一種衍生物,區(qū)別在每個頻道都是一個單獨的類,而非簡單的FIFO。
當(dāng)數(shù)據(jù)包進(jìn)入PRIO隊列規(guī)則后,根據(jù)你給的過濾器設(shè)置選擇一個類,缺省情況下有三個類。這些類僅包含純FIFO隊列規(guī)則而沒有更多的內(nèi)部結(jié)構(gòu)。你可以把它們替換成你需要的任何隊列規(guī)則。
每當(dāng)有一個數(shù)據(jù)包需要出隊時,首先處理:1類。只有當(dāng)標(biāo)號更小的類中沒有需要處理的數(shù)據(jù)時,才會處理標(biāo)號更大的類。
當(dāng)你希望不僅僅依靠包的TOS,而是想使用
因為它不進(jìn)行整形,所以使用時與SFQ有相同的考慮:要么確保這個
*PRIO的參數(shù)與使用*
PRIO識別下列參數(shù):
bands
創(chuàng)建頻道的數(shù)目。每個頻道實際上就是一個類。如果你修改了這個數(shù)值,你必須同時修改:
priomap
如果你不給TC_PRIO的優(yōu)先級來決定如何給數(shù)據(jù)包入隊。
它的行為就像前面提到過的pfifo_fast隊列規(guī)則(先入先出)
其實頻道是類,缺省情況下命名為“主標(biāo)號:1”到“主標(biāo)號:3”。如果你的PRIO隊列規(guī)則是“12: ”,把數(shù)據(jù)包過濾到“12:1”將得到最高優(yōu)先級。注意:0頻道的次標(biāo)號是1;1頻道的次標(biāo)號是2,以此類推。
*配置范例*
我們想創(chuàng)建這樣一個樹:
大批量數(shù)據(jù)使用30:交互數(shù)據(jù)使用20:或10:。
命令如下:
#root handle 1: prio
##這個命令立即創(chuàng)建了類: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
#tc qdisc add dev eth0 parent 1:3 handle 30: sfq
我們看看結(jié)果如何:
# tc -s qdisc ls dev eth0
qdisc sfq 30: quantum 1514b
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms
Sent 0 bytes 0 pkts (dropped 0, overlimits 0)
qdisc sfq 10: quantum 1514b
Sent 132 bytes 2 pkts (dropped 0, overlimits 0)
qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 174 bytes 3 pkts (dropped 0, overlimits 0)
如你所見,0頻道已經(jīng)有了一些流量,那是在運行這個命令之后發(fā)送了一個包!
現(xiàn)在我們來點大批量數(shù)據(jù)傳輸(使用能夠正確設(shè)置TOS標(biāo)記的工具):
# scp tc ahu@10.0.0.11:./
ahu@10.0.0.11’s password:
tc 100% |*****************************| 353 KB 00:00
# tc -s qdisc ls dev eth0
qdisc sfq 30: quantum 1514b
Sent 384228 bytes 274 pkts (dropped 0, overlimits 0)
qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms
Sent 2640 bytes 20 pkts (dropped 0, overlimits 0)
qdisc sfq 10: quantum 1514b
Sent 2230 bytes 31 pkts (dropped 0, overlimits 0)
qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 389140 bytes 326 pkts (dropped 0, overlimits 0)
如你所見,所有的流量都是經(jīng)過30:處理的,優(yōu)先權(quán)最低?,F(xiàn)在我們驗證一下交互數(shù)據(jù)傳輸經(jīng)過更高優(yōu)先級的頻道,我們生成一些交互數(shù)據(jù)傳輸:
# tc -s qdisc ls dev eth0
qdisc sfq 30: quantum 1514b
Sent 384228 bytes 274 pkts (dropped 0, overlimits 0)
qdisc tbf 20: rate 20Kbit burst 1599b lat 667.6ms
Sent 2640 bytes 20 pkts (dropped 0, overlimits 0)
qdisc sfq 10: quantum 1514b
Sent 14926 bytes 193 pkts (dropped 0, overlimits 0)
qdisc prio 1: bands 3 priomap 1 2 2 2 1 2 0 0 1 1 1 1 1 1 1 1
Sent 401836 bytes 488 pkts (dropped 0, overlimits 0)
工作正常,所有額外的流量都是經(jīng)10:這個更高優(yōu)先級的隊列規(guī)則處理的。與先前的整個scp不同,沒有數(shù)據(jù)經(jīng)過最低優(yōu)先級的隊列規(guī)則。
4.著名的CBQ隊列規(guī)則
如前所述,CBQ是最復(fù)雜、最瑣碎、最難以理解、最刁鉆的隊列規(guī)則。這并不是因為其作者的惡毒或者不稱職,而是因為CBQ算法本身的不精確,而且與Linux的內(nèi)在機制不協(xié)調(diào)造成的。
除了可以分類之外,CBQ也是一個整形器,但是從表面上看來工作得并不好。它應(yīng)該是這樣的:如果你試圖把一個10Mbps的連接整形成1Mbps的速率,就應(yīng)該讓鏈路90%的時間處于閑置狀態(tài),必要的話我們就強制,以保證90%的閑置時間。
但閑置時間的測量非常困難,所以CBQ就采用了它一個近似值——來自硬件層的兩個傳輸請求之間的毫秒數(shù)來代替它。這個參數(shù)可以近似地表現(xiàn)這個鏈路的繁忙程度。
這樣做相當(dāng)慎重,而且不一定能夠得到正確的結(jié)論。比如,由于驅(qū)動程序方面或者其它原因造成一塊網(wǎng)卡永遠(yuǎn)也不會達(dá)到100Mbps。那么我們該怎么計算閑置時間呢?
如果我們引入非物理
*CBQ整形的細(xì)節(jié):*
CBQ的工作機制是確認(rèn)鏈路的閑置時間足夠長,以達(dá)到降低鏈路實際帶寬的目的。為此,它要計算兩個數(shù)據(jù)包的平均發(fā)送間隔。
操作期間,有效閑置時間的測量使用EWMA(exponential weighted moving average,指數(shù)加權(quán)移動均值)算法,也就是說最近處理的數(shù)據(jù)包的權(quán)值比以前的數(shù)據(jù)包按指數(shù)增加。UNIX的平均負(fù)載也是這樣算出來的。
計算出來的平均時間值減去EWMA測量值,得出的結(jié)果叫做“avgidle”。最佳的鏈路負(fù)載情況下,這個值應(yīng)當(dāng)是0:數(shù)據(jù)包嚴(yán)格按照計算出來的時間間隔到來。
在一個過載的鏈路上,avgidle值應(yīng)當(dāng)是負(fù)的。如果這個負(fù)值太嚴(yán)重,CBQ就會暫時禁止發(fā)包,稱為”overlimit”(越限)。
相反地,一個閑置的鏈路應(yīng)該有很大的avgidle值,這樣閑置幾個小時后,會造成鏈路允許非常大的帶寬通過。為了避免這種局面,我們用maxidle來限制avgidle的值不能太大。
理論上講,如果發(fā)生越限,CBQ就會禁止發(fā)包一段時間(長度就是事先計算出來的傳輸數(shù)據(jù)包之間的時間間隔),然后通過一個數(shù)據(jù)包后再次禁止發(fā)包。但是最好參照下面的minburst參數(shù)。
下面是配置流量整形時需要指定的一些參數(shù):
avpkt
平均包大小,單位是字節(jié)。計算maxidle(最大閑置)時需要,maxidle從maxburst得出。
bandwidth
cell
一個數(shù)據(jù)包被發(fā)送出去的時間可以是基于包長度而階梯增長的。一個800字節(jié)的包和一個806字節(jié)的包可以認(rèn)為耗費相同的時間。也就是說它用作設(shè)置時間力度。通常設(shè)置為8,必須是2的整數(shù)次冪。
maxburst
這個參數(shù)的值決定了計算maxidle所使用的數(shù)據(jù)包的個數(shù)。在avgidle跌落到0之前,這么多的數(shù)據(jù)包可以突發(fā)傳輸出去。這個值越高,越能夠容納突發(fā)傳輸。你無法直接設(shè)置maxidle的值,必須通過這個參數(shù)來控制。
minburst
如
前所述,發(fā)生越限時CBQ會禁止發(fā)包。實現(xiàn)這個的理想方案是根據(jù)事先計算出的閑置時間進(jìn)行延遲之后,發(fā)一個數(shù)據(jù)包。然而,UNIX的內(nèi)核一般來說都有一個
固定的調(diào)度周期(一般不大于10ms),所以最好是這樣:禁止發(fā)包的時間稍長一些,然后突發(fā)性地傳輸minburst個數(shù)據(jù)包,而不是一個一個地傳輸。等
待的時間叫做offtime。
從大的時間尺度上說,minburst值越大,整形越精確。但是,從毫秒級的時間尺度上說,就會有越多的突發(fā)傳輸。
minidle
如果avgidle值降到0,也就是發(fā)生了越限,就需要等待,直到avgidle的值足夠大才發(fā)送數(shù)據(jù)包。為避免因關(guān)閉鏈路太久而引起的以外突發(fā)傳輸,在avgidle的值太低的時候會被強制設(shè)置為minidle的值。
參數(shù)minidle的值是以負(fù)微秒記的。所以10代表avgidle被限制在-10us上。
mpu
最小分組大小——因為即使是0長度的數(shù)據(jù)包,在以太網(wǎng)上也要生成封裝成64字節(jié)的幀,而需要一定時間去傳輸。為了精確計算閑置時間,CBQ需要知道這個值。
rate
期望中的傳輸速率。也就是“速度操縱桿”!
在CBQ的內(nèi)部有很多的微調(diào)參數(shù)。比如,那些已知隊列中沒有數(shù)據(jù)的類就不參加計算、越限的類將被懲罰性地降低優(yōu)先級等等。都非常巧妙和復(fù)雜。
*CBQ在分類方面的行為*
除了使用上述idletime近似值進(jìn)行整形之外,CBQ還可以象PRIO隊列那樣,把各種類賦予不同的優(yōu)先級,優(yōu)先權(quán)數(shù)值小的類會比優(yōu)先權(quán)值大的類被優(yōu)先處理。
每當(dāng)網(wǎng)卡請求把數(shù)據(jù)包發(fā)送到網(wǎng)絡(luò)上時,都會開始一個WRR(weighted round robin,加權(quán)輪轉(zhuǎn))過程,從優(yōu)先權(quán)值小的類開始。
那些隊列中有數(shù)據(jù)的類就會被分組并被請求出隊。在一個類收到允許若干字節(jié)數(shù)據(jù)出隊的請求之后,再處理下一個相同優(yōu)先權(quán)值的類。
*下面是控制WRR過程的一些參數(shù):*
allot
當(dāng)從外部請求一個CBQ發(fā)包的時候,它就會按照“priority(prio)”參數(shù)指定的順序輪流嘗試其內(nèi)部的每一個類的隊列規(guī)則。當(dāng)輪到一個類發(fā)數(shù)據(jù)時,它只能發(fā)送一定量的數(shù)據(jù)。“allot”參數(shù)就是這個量的基值。更多細(xì)節(jié)請參照“weight”參數(shù)。
prio
CBQ可以象PRIO設(shè)備那樣工作。其中“prio”值較低的類只要有數(shù)據(jù)就必須先服務(wù),其他類要延后處理。
weight
“weight”
參數(shù)控制WRR過程。每個類都輪流取得發(fā)包的機會。如果其中一個類要求的帶寬顯著地高于其他的類,就應(yīng)該讓它每次比其他的類發(fā)送更多的數(shù)據(jù)(以字節(jié)為單
位,可以理解為偏袒數(shù)量,例如weight 200Kbit就相當(dāng)于每次處理優(yōu)先級的數(shù)據(jù)比普通數(shù)據(jù)多處理200Kbit)。
CBQ會把一個類下面所有的weight值加起來后歸一化,所以數(shù)值可以任意定,只要保持比例合適就可以。人們常把“速率/10”作為參數(shù)的值來使用,實際工作得很好。歸一化值后的值乘以“allot”參數(shù)后,決定了每次傳輸多少數(shù)據(jù)。
*決定鏈路的共享和借用的CBQ參數(shù)*
除了純粹地對某種數(shù)據(jù)流進(jìn)行限速之外,CBQ還可以指定哪些類可以向其它哪些類借用或者出借一部分帶寬。
Isolated/Sharing (isolated字面意思:獨立,單獨的)
凡是使用“isolated”選項配置的類,就不會向其兄弟類借出帶寬。如果你的鏈路上同時存在著不友好的人,你就可以使用這個選項。
選項“sharing”是“isolated”的反義選項。
Bounded/Borrow (bounded字面意思:受限制的,有限的;borrow=借入)
一個類也可以用“bounded”選項配置,意味著它不會向其兄弟類借入帶寬。選項“borrow”是“bounded”的反義選項。
一個典型的情況就是你的一個鏈路上有多個客戶都設(shè)置成了“isolated”和“bounded”,那就是說他們都被限制在其要求的速率之下,且互相之間不會借用帶寬(就是我們常說的帶寬獨享)。在這樣的一個類的內(nèi)部的子類之間是可以互相借用帶寬的。
*配置范例*
這個配置把WEB服務(wù)器的流量控制為5mbit、SMTP流量控制在3mbit上。而且二者一共不得超過6mbit,互相之間允許借用帶寬。我們的
# root handle 1:0 cbq bandwidth 100Mbit avpkt 1000 cell 8
# 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
這部分按慣例設(shè)置了根為1:0,并且綁定了類1:1。也就是說整個帶寬不能超過6Mbps。
如前所述,CBQ需要調(diào)整很多的參數(shù)。其實所有的參數(shù)上面都解釋過了。但是,相應(yīng)的的
# 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
# 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個類。注意我們?nèi)绾胃鶕?jù)帶寬來調(diào)整weight參數(shù)的。兩個類都沒有配置成“bounded”,但它們都連接到了類1:1上,而1:1設(shè)置了 “bounded”。所以兩個類的
# tc qdisc add dev eth0 parent 1:3 handle 30: sfq
# tc qdisc add dev eth0 parent 1:4 handle 40: sfq
缺省情況下,兩個類都有一個FIFO隊列規(guī)則。但是我們把它換成SFQ隊列,以保證每個數(shù)據(jù)流都公平對待。
# 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
這些命令規(guī)則了根上的過濾器,保證數(shù)據(jù)流被送到正確的隊列規(guī)則中去。
注意:我們先使用了“class add” 在一個隊列規(guī)則中創(chuàng)建了類,然后使用“tc qdisc add”在類中創(chuàng)建隊列規(guī)則。
你可能想知道,那些沒有被那兩條規(guī)則分類的數(shù)據(jù)流怎樣處理了呢?從這個例子來說,它們被1:0直接處理,沒有限制。
如果SMTP+web的
*其它CBQ參數(shù):split和defmap (split:分離、分裂)*
如前所述,一個分類的隊列規(guī)則需要調(diào)用過濾器來決定一個數(shù)據(jù)包應(yīng)該發(fā)往哪個類去排隊。
除了調(diào)用過濾器,CBQ還提供了其他方式,defmap和split。很難掌握,但好在無關(guān)大局。但是現(xiàn)在是解釋defmap和split的最佳時機,我會盡力解釋。
因
為你經(jīng)常是僅僅需要根據(jù)TOS來進(jìn)行分類,所以提供了一種特殊的語法。當(dāng)CBQ需要決定了數(shù)據(jù)包要在哪里入隊時,要檢查這個節(jié)點是否為“split節(jié)
點”。如果是,子隊列規(guī)則中的一個應(yīng)該指出它接收所有帶有某種優(yōu)先權(quán)值的數(shù)據(jù)包,權(quán)值可以來自TOS字段或者應(yīng)用程序設(shè)置的套接字選項。
數(shù)據(jù)包的優(yōu)先權(quán)位與defmap字段的值進(jìn)行”或”運算來決定是否存在這樣的匹配。換句話說,這是一個可以快捷創(chuàng)建僅僅匹配某種優(yōu)先權(quán)值數(shù)據(jù)包的過濾器的方法。如果defmap等于0xff,就會匹配所有包,0則是不匹配。下面的實例可以幫助理解:
# root handle 1: cbq bandwidth 10Mbit allot 1514 cell 8 avpkt 1000 mpu 64
# class add dev eth1 parent 1:0 classid 1:1 cbq bandwidth 10Mbit rate 10Mbit allot 1514 cell 8 weight 1Mbit prio 8 maxburst 20 avpkt 1000
一個標(biāo)準(zhǔn)的CBQ前導(dǎo)。
Defmap參照
然后是交互和大吞吐量的類:
# class add dev eth1 parent 1:1 classid 1:2 cbq bandwidth 10Mbit rate 1Mbit allot 1514 cell 8 weight 100Kbit prio 3 maxburst 20 avpkt 1000 split 1:0 defmap c0
# class add dev eth1 parent 1:1 classid 1:3 cbq bandwidth 10Mbit rate 8Mbit allot 1514 cell 8 weight 800Kbit prio 7 maxburst 20 avpkt 1000 split 1:0 defmap 3f
“split隊列規(guī)則”是1:0,也就是做出選擇的地方。c0是二進(jìn)制的11000000,3F是00111111,所以它們共同匹配所有的數(shù)據(jù)包。第一個類匹配第7和第6位,也就是負(fù)責(zé)“交互”和“控制”的數(shù)據(jù)包。第二個類匹配其余的數(shù)據(jù)包。
節(jié)點1:0現(xiàn)在應(yīng)該有了這樣一個表格:
為了更有趣,你還可以傳遞一個“change掩碼”,確切地指出你想改變哪個優(yōu)先權(quán)值。你只有在使用了“class change”的時候才需要。比如,往1:2中添加best effort數(shù)據(jù)流,應(yīng)該執(zhí)行:
# class change dev eth1 classid 1:2 cbq defmap 01/01
現(xiàn)在,1:0上的優(yōu)先權(quán)分布應(yīng)該是:
5.HTB(Hierarchical Token Bucket, 分層的令牌桶)
Martin Devera意識到CBQ太復(fù)雜,而且并沒有按照多數(shù)常見情況進(jìn)行優(yōu)化。他的Hierarchical能夠很好地滿足這樣一種情況:你有一個固定速率的鏈路,希望分割給多種不同的用途使用。為每種用途做出帶寬承諾并實現(xiàn)定量的帶寬借用。
隨著你的HTB3 (關(guān)于它的版本情況,請參閱它的網(wǎng)站)已經(jīng)成了官方內(nèi)核的一部分(2.4.20-pre1、2.5.31及其后)。然而,你可能仍然要為你的HTB3支持補丁,否則你的HTB3。
如果你已經(jīng)有了一個新版內(nèi)核或者已經(jīng)打了補丁,請盡量考慮使用
*配置范例*
環(huán)境與要求與上述CBQ的例子一樣:
把WEB服務(wù)器的流量控制為5mbit、SMTP流量控制在3mbit上。而且二者一共不得超過6mbit,互相之間允許借用帶寬。我們的
# root handle 1: htb default 30
# class add dev eth0 parent 1: classid 1:1 htb rate 6mbit burst 15k
# class add dev eth0 parent 1:1 classid 1:10 htb rate 5mbit burst 15k
# class add dev eth0 parent 1:1 classid 1:20 htb rate 3mbit ceil 6mbit burst 15k
# class add dev eth0 parent 1:1 classid 1:30 htb rate 1kbit ceil 6mbit burst 15k
作者建議在那些類的下方放置SFQ:
# 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
添加過濾器,直接把流量導(dǎo)向相應(yīng)的類:
# U32="
# $U32 match ip dport 80 0xffff flowid 1:10
# $U32 match ip sport 25 0xffff flowid 1:20
不錯,沒有奇怪的數(shù)字,沒有復(fù)雜的參數(shù)。
它們借用的比率是5:3,正如你期望的那樣。
未被分類的流量被送到了30:,僅有一點點帶寬,但是卻可以任意借用剩下的帶寬。因為我們內(nèi)部使用了SFQ,而可以公平發(fā)包。
使用過濾器對數(shù)據(jù)包進(jìn)行分類
為了決定用哪個類處理數(shù)據(jù)包,必須調(diào)用所謂的“分類器鏈” 進(jìn)行選擇。這個鏈中包含了這個分類隊列規(guī)則所需的所有過濾器。
重復(fù)前面那棵樹:
當(dāng)一個數(shù)據(jù)包入隊的時候,每一個分支處都會咨詢過濾器鏈如何進(jìn)行下一步。典型的配置是在1:1處有一個過濾器把數(shù)據(jù)包交給12:,然后12:處的過濾器在把包交給12:2。
你可以把后一個過濾器同時放在1:1處,但是你可以通過在鏈路上進(jìn)行更多特定的測試來使效率得以提高。
另外,你不能用過濾器把數(shù)據(jù)包向“上”送。而且,使用
再次強調(diào):數(shù)據(jù)包只能向“下”進(jìn)行入隊操作!只有出隊的時候才會上到網(wǎng)卡!
*過濾器的一些簡單范例*
下面,我們開始簡單地匹配一些比較有明顯特征的語法。
比方說,我們有一個PRIO隊列規(guī)則,叫做“10:”,包含3個類,我們希望把去往22口的數(shù)據(jù)流發(fā)送到最優(yōu)先的頻道中去。應(yīng)該這樣設(shè)置過濾器:
# tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip dport 22 0xffff flowid 10:1
# tc filter add dev eth0 protocol ip parent 10: prio 1 u32 match ip sport 80 0xffff flowid 10:1
# tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2
意思是說:
向eth0上的10:節(jié)點添加一個u32過濾規(guī)則,它的優(yōu)先權(quán)是1:凡是去往22口(精確匹配)的IP數(shù)據(jù)包,發(fā)送到頻道10:1。
向eth0上的10:節(jié)點添加一個u32過濾規(guī)則,它的優(yōu)先權(quán)是1:凡是來自80口(精確匹配)的IP數(shù)據(jù)包,發(fā)送到頻道10:1。
向eth0上的10:節(jié)點添加一個過濾規(guī)則,它的優(yōu)先權(quán)是2:凡是上面未匹配的IP數(shù)據(jù)包,發(fā)送到頻道10:2。
別忘了添加“dev eth0”(你的網(wǎng)卡的句柄都有完全相同的命名空間。
想通過IP地址進(jìn)行篩選的話,可以使用以下命令:
# tc filter add dev eth0 parent 10:0 protocol ip prio 1 u32 match ip dst 4.3.2.1/32 flowid 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
# tc filter add dev eth0 protocol ip parent 10: prio 2 flowid 10:2
這個例子把去往4.3.2.1和來自1.2.3.4的數(shù)據(jù)包送到了最高優(yōu)先的隊列,其它的則送到次高權(quán)限的隊列。
你可以連續(xù)使用match,想匹配來自1.2.3.4的80口的數(shù)據(jù)包的話,可以使用命令:
# 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
*常用到的過濾命令一覽*
這里列出的絕大多數(shù)命令都根據(jù)這個命令改編而來:
# tc filter add dev eth0 parent 1:0 protocol ip prio 1 u32
這些是所謂的“u32”匹配,可以匹配數(shù)據(jù)包的任意部分。
根據(jù)源/目的地址
源地址段 match ip src 1.2.3.0/24
目的地址段 match ip dst 4.3.2.0/24
單個IP地址使用“/32”作為掩碼即可。
根據(jù)源/目的端口,所有IP協(xié)議
源端口 match ip sport 80 0xffff
目的端口 match ip dport 80 0xffff
根據(jù)IP協(xié)議(tcp, udp, icmp, gre, ipsec)
使用/etc/protocols所指定的數(shù)字。
比如:icmp是 match ip protocol 1 0xff
根據(jù)fwmark(防火墻標(biāo)記功能)
你可以使用ipchains/iptables給數(shù)據(jù)包做上標(biāo)記,并且這個標(biāo)記會在穿過
#tc filter add dev eth1 protocol ip parent 1:0 prio 1 handle 6 fw flowid 1:1
注意,這不是一個u32匹配!
你可以象這樣給數(shù)據(jù)包打標(biāo)記:
# iptables -A PREROUTING -t mangle -i eth0 -j MARK --set-mark 6(數(shù)字6是可以任意指定的)
如果你不想去學(xué)習(xí)所有的
按TOS字段選擇交互和最小延遲的數(shù)據(jù)流:
# tc filter add dev ppp0 parent 1:0 protocol ip prio 10 u32 match ip tos 0x10 0xff flowid 1:4
想匹配大量傳輸?shù)脑?,使用?x08 0xff”。
IMQ(Intermediate queueing device,中介隊列設(shè)備)
中介隊列設(shè)備不是一個隊列規(guī)則,但它的使用與隊列規(guī)則是緊密相連的。
就Linux而言,隊列規(guī)則是附帶在網(wǎng)卡上排隊的數(shù)據(jù)都排進(jìn)這個隊列規(guī)則。所以出現(xiàn)了兩個局限:
1.只能進(jìn)行出口整形(雖然也存在入口隊列規(guī)則,但在上面實現(xiàn)分類的隊列規(guī)則的可能性非常小)。
2.一個隊列規(guī)則只能處理一塊
IMQ就是用來解決上述兩個局限的。簡單地說,你可以往一個隊列規(guī)則中放任何東西。被打了特定標(biāo)記的數(shù)據(jù)包在netfilter的 NF_IP_PRE_ROUTING和NF_IP_POST_ROUTING兩個鉤子函數(shù)處被攔截,并被送到一個隊列規(guī)則中,該隊列規(guī)則附加到一個IMQ設(shè)備上。對數(shù)據(jù)包打標(biāo)記要用到iptables的一種處理方法。
這樣你就可以對剛剛進(jìn)入網(wǎng)卡們當(dāng)成一個個的類來看待而進(jìn)行全局整形設(shè)置。你還可以做很多事情,比如:把http流量放到一個隊列規(guī)則中去、把新的連接請求放到一個隊列規(guī)則中去。
*配置范例*
我們首先想到的是進(jìn)行入口整形,以便讓你自己得到高保證的帶寬。就像配置其它
#root handle 1: htb default 20
#class add dev imq0 parent 1: classid 1:1 htb rate 2mbit burst 15k
#class add dev imq0 parent 1:1 classid 1:10 htb rate 1mbit
#class add dev imq0 parent 1:1 classid 1:20 htb rate 1mbit
#tc qdisc add dev imq0 parent 1:10 handle 10: pfifo
#tc qdisc add dev imq0 parent 1:20 handle 20: sfq
#tc filter add dev imq0 parent 10:0 protocol ip prio 1 u32 match ip dst 10.0.0.230/32 flowid 1:10
在這個例子中,使用了u32進(jìn)行分類。其它的分類器應(yīng)該也能實現(xiàn)。然后,被打上標(biāo)記的包被送到imq0排隊。
#iptables -t mangle -A PREROUTING -i eth0 -j IMQ --todev 0
#ip link set imq0 up
iptables的IMQ處理方法只能用在PREROUTING和POSTROUTING鏈的mangle表中。語法是:
IMQ [ --todev n ]
n: imq設(shè)備的編號
注:ip6tables也提供了這種處理方法。
請注意,如果數(shù)據(jù)流是事后才匹配到IMQ處理方法上的,數(shù)據(jù)就不會入隊。數(shù)據(jù)流進(jìn)入imq的確切位置取決于這個數(shù)據(jù)流究竟是流進(jìn)的還是流出的。下面是netfilter(也就是iptables)在內(nèi)核中預(yù)先定義優(yōu)先級:
enum nf_ip_hook_priorities {
NF_IP_PRI_FIRST = INT_MIN,
NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_LAST = INT_MAX,
};
對于流入的包,imq把自己注冊為優(yōu)先權(quán)等于NF_IP_PRI_MANGLE+1。也就是說數(shù)據(jù)包在經(jīng)過了PREROUTING鏈的mangle表之后才進(jìn)入imq設(shè)備。
對于流出的包,imq使用優(yōu)先權(quán)等于NF_IP_PRI_LAST,也就是說不會白白處理本應(yīng)該被filter表丟棄的數(shù)據(jù)包。
http://m.blog.csdn.net/blog/zhaobryant/38797739
|