Linux流量控制中的HTB隊列創建與過濾
眾所周知,在互聯網誕生之初都是各個高校和科研機構相互通訊,并沒有Linux流量控制方面的考慮和設計,IP協議的原則是盡可能好地為所有數據流服務,不同的數據流之間是平等的。然而多年的實踐表明,這種原則并不是最理想的,有些數據流應該得到特別的照顧, 比如,遠程登錄的交互數據流應該比數據下載有更高的優先級。
針對不同的數據流采取不同的策略,這種可能性是存在的。并且,隨著研究的發展和深入, 人們已經提出了各種不同的管理模式。IETF已經發布了幾個標準, 如綜合服務(Integrated Services)、區分服務(Diferentiated Services)等。其實,Linux內核從2 2開始,就已經實現了相關的流量控制功能。本文將介紹Linux中有關流量控制的相關概念, 用于Linux流量控制的工具TC的使用方法,并給出幾個有代表性實例。
一、相關概念
由此可以看出, 報文分組從輸入網卡(入口)接收進來,經過路由的查找, 以確定是發給本機的,還是需要轉發的。如果是發給本機的,就直接向上遞交給上層的協議,比如TCP,如果是轉發的, 則會從輸出網卡(出口)發出。網絡流量控制通常發生在輸出網卡處。雖然在路由器的入口處也可以進行流量控制,Linux也具有相關的功能, 但一般說來, 由于我們無法控制自己網絡之外的設備, 入口處的Linux流量控制相對較難。本文將集中介紹出口處的流量控制。流量控制的一個基本概念是隊列(Qdisc),每個網卡都與一個隊列(Qdisc)相聯系, 每當內核需要將報文分組從網卡發送出去, 都會首先將該報文分組添加到該網卡所配置的隊列中, 由該隊列決定報文分組的發送順序。因此可以說,所有的Linux流量控制都發生在隊列中,詳細流程圖見圖1。
圖1報文在Linux內部流程圖
有些隊列的功能是非常簡單的, 它們對報文分組實行先來先走的策略。有些隊列則功能復雜,會將不同的報文分組進行排隊、分類,并根據不同的原則, 以不同的順序發送隊列中的報文分組。為實現這樣的功能,這些復雜的隊列需要使用不同的過濾器(Filter)來把報文分組分成不同的類別(Class)。這里把這些復雜的隊列稱為可分類(ClassfuI)的隊列。通常, 要實現功能強大的Linux流量控制, 可分類的隊列是必不可少的。因此,類別(class)和過濾器(Filter)也是流量控制的另外兩個重要的基本概念。圖2所示的是一個可分類隊列的例子。
圖2多類別隊列
由圖2可以看出,類別(CIass)和過濾器(Filter)都是隊列的內部結構, 并且可分類的隊列可以包含多個類別,同時,一個類別又可以進一步包含有子隊列,或者子類別。所有進入該類別的報文分組可以依據不同的原則放入不同的子隊列或子類別中,以此類推。而過濾器(Filter)是隊列用來對數據報文進行分類的工具, 它決定一個數據報文將被分配到哪個類別中。
二、使用TC
在Linux中,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。
需要注意的是, 在TC 中使用下列的縮寫表示相應的帶寬:
◆ Kbps kiIobytes per second, 即"千字節每秒 ;
◆ Mbps megabytes per second, 即"兆字節每秒 ,
◆ Kbit kilobits per second,即"千比特每秒 ;
◆ Mbit megabits per second, 即"兆比特每秒 。#p#
三、創建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:1 1。更加詳細的有關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: 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中類別和子類別的包含關系,可以構建更加復雜的多層次類別樹,從而實現的更加靈活的帶寬共享和獨占模式,達到企業級的帶寬管理目的。
【編輯推薦】