2011年10月12日 星期三

Coyote Linux 頻寬管制 (QoS) 設定教學

轉貼自:http://b2d.phc.edu.tw/modules/tadbook2/view.php?book_sn=5&bdsn=761

這一篇由linux_xp兄(於PCZONE 論壇)上所發表。

Coyote Linux 頻寬管制 (QoS) 設定教學

前言:
———————————————————————-
此篇教學以 Coyote Linux 軟件路由器為範例系統
演示如何以 tc 指令設定 QoS 頻寬管制

由於 Coyote Linux,即是精簡型 Linux
所以此篇 Linux QoS 設定原理,亦適用任何 Linux distro 發行版

以下教學內容會有點複雜,但完成的效果,可以媲美一台幾萬元的硬件路由器,物超所值。
名詞解釋:
——————————————————————–
QoS (Quality of Service):網絡服務質量保證,俗稱的頻寬管制。

隊列規則 (qdisc):
隊列 (Queue) 是網卡存放外送封包的地方
可以想像成是高速公路的網關管制
如同網關管制是用來管制高速公路(網絡)的車流量(封包流量)
隊列規則就是用來管制網絡流量的規則

若沒有設定,預設的規則是 FIFO (First In First Out,先進先出) ,意即完全無管制。

Linux QoS 的隊列規則有兩種:CBQ,HTB
CBQ (Class Based Queueing) 的設定比較複雜,但可設定的東西較多,彈性較大
HTB (Hierarchy Token Bucket) 是 CBQ 的改良版 ,設定較精簡,效能也比 CBQ 來的好
此篇教學,以 HTB 為主。

類別 (class):
類別是一個集合,舉例要把頻寬分成:看網頁類,玩在線遊戲類,P2P 下載類….等等
P2P 下載類:不需要實時反應,所以給予最少的頻寬,最低的優先權
看網頁類:頻寬大一點,才不會等到睡著,但優先權用普通的即可
玩在線遊戲類:玩在線遊戲最怕的就是和人 PK 時網絡 LAG,LAG 一下可能就輸了,所以優先權要最高,這是無庸置疑的

過濾器:
檢查封包該屬於哪個類別,並給予歸類的東西,稱作過濾器。
Linux QoS 過濾器有兩種:u32,fw
u32: 設定比較複雜,需懂封包結構,才有辦法設定
fw:fw 是靠 iptables 給封包貼標籤,設定比較簡單
此篇教學,以 fw 為主。

iptables 指令:
Linux 負責防火牆功能的,是一個叫 NetFilter 的模塊,而 iptables 就是用來設定 NetFilter 模塊的指令。

tc 指令:
Linux 負責QoS (頻寬管制) 功能的,是一個叫 Traffic Control 的模塊,而 tc 就是用來設定 Traffic Control 模塊的指令。

shell script:
俗稱腳本文件(劇本),Linux 操作系統會依照裡面的內容,逐行執行程序
類似 windows 下的 .bat 自動批次文件,但 shell script 功能比較強

在設定 QoS 的時候,往往要打上幾十行的指令
但是打了這一大堆東西,重開機之後就會消失
所以要把這些指令,編輯成一個腳本文件,讓計算機一開機就執行。

教學開始 ↓

規劃篇: (分配頻寬,定義類別)
———————————————————————–
由於 QoS 要先計算出整體頻寬,給予分配,才有辦法設定
所以在設定之前,必須先進行規劃的前置作業

導讀:
講解「類別」原理的部份,因為較深入可能會比較煩,可省略跳過
最重要的部分,是要完成那個頻寬計算分配表,因為底下實作時必須填入分配的數字。


此次教學示範的網絡架構如上

對外網卡:eth1
對內網卡:eth0

將分配頻寬給三台 PC 計算機
每台計算機可以得到各自的保證的頻寬,以及可借用的最大頻寬

另有一台 服務器,上面有 web、e-mail、dns 三個服務
近來利用 ADSL 在家裡架設服務器的人數也有增多的趨勢
故此次教學,也示範如何管制服務器的頻寬

default (預設) 類別
指如果封包不屬於那三台計算機,也不屬於服務器,則歸類於 default 類別,進行頻寬控管
具體來說,此種情況就是筆記型計算機,PDA,PSP掌上遊戲機……. 等等之類,有使用到網絡頻寬的設備

首先,第一步要計算出「合理的頻寬分配」

分配頻寬,就像在分家產一樣,務必公平合理,否則 QoS 便無法運作,或者無法達到預期的效果

請拿出紙、筆、計算器,或者利用電子錶格軟件,進行計算

此次的範例是 ADSL 2M/512K

HTB 隊列規則用的是 KByte/s ,所以要先換算

ADSL 的頻寬單位,是 bps (bits per second)
————————————–
8 bps = 1 Byte/s

下載 2Mbps = 256 KB/s
上傳 512Kbps = 64 KB/s

保證下載,保證上傳:是手動填入的數字

「保證」指的是無論如何,別的「類別」都不能來搶這個頻寬

這個值不宜設太大,因為還可以借用頻寬,且保證設太大,整體頻寬都用完了,就失去意義了
一般建議值是每台計算機的保證上傳,最少要有 32Kbps = 4KB/s

其餘數值,是公式計算所得,計算方式如下:
—————————————————————–
賸餘頻寬 (可借用的頻寬量) = 總頻寬 – 保證頻寬總和

最大下載 = 保證下載 + 下載賸餘頻寬
最大上傳 = 保證上傳 + 上傳賸餘頻寬

最大下載,最大上傳:亦可填入固定數字

「最大」指的是無論如何,該「類別」能使用的頻寬不會超過這個數字

優先權:指誰可以有較大權力搶用賸餘頻寬,由 0 開始的整數,數字愈小,優先權愈高,0 為最高優先權。

以上表的例子來說
192.168.1.1 這台計算機是筆者所用,俗話說肥水不落外人田,當然優先權為 0 最高
其餘計算機設 1,優先權普通,但若有特別的下載狂,可考慮降低他的優先權
至於服務器的 http、smtp、dns 等對外的服務,服務的是外面的人
優先權可設小一點,以不干擾自己內部的人使用網絡為原則

Linux QoS 有三要素:隊列規則、類別、過濾器

完成了這三項的設定,也就完成了 Linux QoS 的設定
在計算分配好頻寬表的前置作業之後,接著要做的事,是規劃「類別」

—————————————————————————
Q.為什麼「類別」規劃,會分成 下載、上傳 兩部份?

前面提到「隊列」是網卡存放外送封包的地方,故「隊列規則」也只能管制外送的封包

『Linux Advanced Routing & Traffic Control HOWTO’文件
用一個生動的比喻,來解釋這種情況:
“我們只能規定自己寫多少信給別人,無法限制每天會有多少人寫信給我們”

簡單的說,Linux QoS 只能管制網卡往外傳送的流量

不過這並不是說 Linux QoS 只能管制上傳
因 NAT 主機上,會有兩片網卡

「對外網卡」往外傳送,稱之為:上傳
「對內網卡」往外傳送,稱之為:下載

所以若要同時進行 上傳/下載 的雙向管制,必要條件為兩片網卡

整個 Qos 的設定,亦會分成兩部分,上傳 和 下載

————————————————————————-

類別規劃圖,看起來像一張樹形圖
實體網卡的隊列規則,稱作「根」隊列規則
其下的類別,就像葉子一樣,又稱「葉類別」
而最末尾的「葉類別」,必須帶有「葉隊列規則」

您可能會注意到,每個「隊列規則」、「類別」都有編號
這是因為待會實作下指令時,必須用到

編號中的冒號為必須
「隊列規則」只有冒號左邊有數字
「葉類別」冒號左邊數字是指掛在哪個「根隊列規則」,右邊則是「葉類別」的編號

編號是隨人高興取的,但習慣上,會有一些固定的取法
「根隊列規則」會取編號 10:
第 1 層,第 1 個「葉類別」,取編號 10:1
第 2 層,第 1 個「葉類別」,取編號 10:10
第 2 層,第 2 個「葉類別」,取編號 10:20 ……….以此類推
最末尾的「葉隊列規則」,取編號 101: 、102: ……以此類推

此範例圖,是只有二層架構的樹形圖
實際上,Linux QoS 的類別規劃,最多可以到八層,應用在規劃網段的頻寬管制
但一般用途,規劃到二層即夠使用,故不再做多層規劃的範例
若對多層規劃有興趣,請參考 Linux QoS 相關書籍

類別規劃圖,可畫也可不畫
畫出來的話,可以幫助 QoS 設定更容易瞭解
不過下面的實作教學,將會提供參考用原始碼,小部份修改後,直接套用即可 ^^

#################################################################################

實作篇: (開始實際設定 Linux QoS )
—————————————————————————————–

實作篇,將開始用 tc 指令,和 iptables 指令,撰寫 shell script,實現 Linux QoS

原理講解的部份,由於上面規劃篇的時候,已經差不多都講解完了
再者指令的語法是變化多端的,礙於篇幅
因此底下實作篇將不做任何原理方面的講解
改以直接秀出參考用原始碼的方法,小部分修改後,套用即可

Coyote 自定義 QoS 設定步驟:(看圖說故事)

STEP.1


STEP.2


STEP.3


STEP.4


STEP.5


STEP.6


STEP.7

Linux QoS 參考用原始碼

基本說明:

1.凡是以 # 符號開頭,代表該行為批註,不會被系統執行
2.第一行的 #!/bin/sh 為 shell script 必要語法,不可刪除
3.Coyote 不支持 Big5 繁體中文,所以繁體中文批註貼上後會變成亂碼,是正常的
4.若要顯示繁體中文批註,需轉碼成 UTF-8 (無 BOM格式)

tc 指令 ( /etc/rc.d/rc.local ) :
===================================================================
#!/bin/sh
#
# Coyote local command init script

# 清除 eth1 所有隊列規則
tc qdisc del dev eth1 root 2>/dev/null

# 定義最頂層(根)隊列規則,並指定 default 類別編號
tc qdisc add dev eth1 root handle 10: htb default 70

# 定義第一層的 10:1 類別 (總頻寬)
tc class add dev eth1 parent 10: classid 10:1 htb rate 64kbps ceil 64kbps

# 定義第二層葉類別
# rate 保證頻寬,ceil 最大頻寬,prio 優先權
tc class add dev eth1 parent 10:1 classid 10:10 htb rate 2kbps ceil 4kbps prio 2
tc class add dev eth1 parent 10:1 classid 10:20 htb rate 2kbps ceil 4kbps prio 2
tc class add dev eth1 parent 10:1 classid 10:30 htb rate 32kbps ceil 40kbps prio 3

tc class add dev eth1 parent 10:1 classid 10:40 htb rate 8kbps ceil 16kbps prio 0
tc class add dev eth1 parent 10:1 classid 10:50 htb rate 4kbps ceil 12kbps prio 1
tc class add dev eth1 parent 10:1 classid 10:60 htb rate 4kbps ceil 12kbps prio 1
tc class add dev eth1 parent 10:1 classid 10:70 htb rate 4kbps ceil 12kbps prio 1

# 定義各葉類別的隊列規則
# parent 類別編號,handle 葉類別隊列規則編號
# 由於採用 fw 過濾器,所以此處使用 pfifo 的隊列規則即可
tc qdisc add dev eth1 parent 10:10 handle 101: pfifo
tc qdisc add dev eth1 parent 10:20 handle 102: pfifo
tc qdisc add dev eth1 parent 10:30 handle 103: pfifo
tc qdisc add dev eth1 parent 10:40 handle 104: pfifo
tc qdisc add dev eth1 parent 10:50 handle 105: pfifo
tc qdisc add dev eth1 parent 10:60 handle 106: pfifo
tc qdisc add dev eth1 parent 10:70 handle 107: pfifo

# 設定過濾器
# 指定貼有 10 標籤 (handle) 的封包,歸類到 10:10 類別,以此類推
tc filter add dev eth1 parent 10: protocol ip prio 100 handle 10 fw classid 10:10
tc filter add dev eth1 parent 10: protocol ip prio 100 handle 20 fw classid 10:20
tc filter add dev eth1 parent 10: protocol ip prio 100 handle 30 fw classid 10:30
tc filter add dev eth1 parent 10: protocol ip prio 100 handle 40 fw classid 10:40
tc filter add dev eth1 parent 10: protocol ip prio 100 handle 50 fw classid 10:50
tc filter add dev eth1 parent 10: protocol ip prio 100 handle 60 fw classid 10:60
tc filter add dev eth1 parent 10: protocol ip prio 100 handle 70 fw classid 10:70

# QoS eth0 下載方面
#

# 清除 eth0所有隊列規則
tc qdisc del dev eth0 root 2>/dev/null

# 定義最頂層(根)隊列規則,並指定 default 類別編號
tc qdisc add dev eth0 root handle 10: htb default 70

# 定義第一層的 10:1 類別 (總頻寬)
tc class add dev eth0 parent 10: classid 10:1 htb rate 256kbps ceil 256kbps

# 定義第二層葉類別
# rate 保證頻寬,ceil 最大頻寬,prio 優先權
tc class add dev eth0 parent 10:1 classid 10:10 htb rate 2kbps ceil 32kbps prio 2
tc class add dev eth0 parent 10:1 classid 10:20 htb rate 2kbps ceil 32kbps prio 2
tc class add dev eth0 parent 10:1 classid 10:30 htb rate 32kbps ceil 212kbps prio 3

tc class add dev eth0 parent 10:1 classid 10:40 htb rate 16kbps ceil 196kbps prio 0
tc class add dev eth0 parent 10:1 classid 10:50 htb rate 8kbps ceil 188kbps prio 1
tc class add dev eth0 parent 10:1 classid 10:60 htb rate 8kbps ceil 188kbps prio 1
tc class add dev eth0 parent 10:1 classid 10:70 htb rate 8kbps ceil 188kbps prio 1

# 定義各葉類別的隊列規則
# parent 類別編號,handle 葉類別隊列規則編號
tc qdisc add dev eth0 parent 10:10 handle 101: pfifo
tc qdisc add dev eth0 parent 10:20 handle 102: pfifo
tc qdisc add dev eth0 parent 10:30 handle 103: pfifo
tc qdisc add dev eth0 parent 10:40 handle 104: pfifo
tc qdisc add dev eth0 parent 10:50 handle 105: pfifo
tc qdisc add dev eth0 parent 10:60 handle 106: pfifo
tc qdisc add dev eth0 parent 10:70 handle 107: pfifo

# 設定過濾器
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 10 fw classid 10:10
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 20 fw classid 10:20
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 30 fw classid 10:30
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 40 fw classid 10:40
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 50 fw classid 10:50
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 60 fw classid 10:60
tc filter add dev eth0 parent 10: protocol ip prio 100 handle 70 fw classid 10:70
=====================================================================

說明:
——————————–
這邊的 eh1 是對外網卡,eth0 是對內網卡
若與您的實際環境不同,請自行修改

主要過程:
1.清除網卡上的所有隊列規則 (不論有或沒有)
2.定義網卡的隊列規則
3.定義各類別
4.定義各類別的隊列規則
5.定義過濾器

rate 後面的數字:保證頻寬
ceil 後面的數字:最大頻寬
單位只有:KByte/s ,不過上面要寫 kbps,因為這是 HTB 的規定語法

prio 後面的數字:優先權,數字愈低愈高,0最大

classid 後面的編號:完整類別編號
parent 後面的編號:父類別,或者隊列規則,亦即該項目上一層的對象

這裡列出了 7 個類別,可以自行新增或減少

default 類別,可有可無
較嚴謹的頻寬管制,可取消 default 類別,以避免內部有人鑽漏洞
一般情況,則建議設 default 比較好

注1:可參考前面的「類別規劃示意圖」,比較容易瞭解此處的設定用意

注2:這段參考用原始碼,只是一個範例,必須修改後,才能符合您的環境

iptables 指令,過濾器 (編輯自定義防火牆規則) :
======================================================================
# uploads
# 設定上傳方面,先利用 iptables 給封包貼標籤,再交由 fw 過濾器進行過濾

iptables -t mangle -A PREROUTING -s 192.168.1.6 -m layer7 –l7proto dns -j MARK –set-mark 10
iptables -t mangle -A PREROUTING -s 192.168.1.6 -m layer7 –l7proto smtp -j MARK –set-mark 20
iptables -t mangle -A PREROUTING -s 192.168.1.6 -m layer7 –l7proto http -j MARK –set-mark 30

iptables -t mangle -A PREROUTING -s 192.168.1.1 -j MARK –set-mark 40
iptables -t mangle -A PREROUTING -s 192.168.1.2 -j MARK –set-mark 50
iptables -t mangle -A PREROUTING -s 192.168.1.3 -j MARK –set-mark 60

# downloads
# 下載方面

iptables -t mangle -A POSTROUTING -d 192.168.1.6 -m layer7 –l7proto dns -j MARK –set-mark 10
iptables -t mangle -A POSTROUTING -d 192.168.1.6 -m layer7 –l7proto smtp -j MARK –set-mark 20
iptables -t mangle -A POSTROUTING -d 192.168.1.6 -m layer7 –l7proto http -j MARK –set-mark 30

iptables -t mangle -A POSTROUTING -d 192.168.1.1 -j MARK –set-mark 40
iptables -t mangle -A POSTROUTING -d 192.168.1.2 -j MARK –set-mark 50
iptables -t mangle -A POSTROUTING -d 192.168.1.3 -j MARK –set-mark 60
=====================================================================

說明:
——————–
iptables 會去檢查封包,看它來自哪裡,或者 Layer-7 協議是哪種的 ,然後貼上標籤
之後 fw 過濾器,會依照卷標上的數字,來給封包歸類別

IP:計算機的 IP

Layer-7 協定種類:
此部份是採用 l7-filter 直接做過濾,例如:dns,smtp,http
P2P 下載的封包,也可以管制
l7-filter 詳細用法請參考 Coyote 的教學文章,補充說明

mark 後面的數字:「類別」的編號

註:這段參考用原始碼,只是一個範例,必須修改後,才能符合您的環境

#############################################################################

Linux QoS 設定,看似複雜,然其實可以做到非常彈性化 (可程序化)

其效能是取決 CPU、RAM、網卡芯片,可由使用者自行決定組裝等級
若使用高等配備,並不會輸給一台幾萬元的昂貴硬件路由器
且在價格上,更具優勢

昔日網絡上的中文 Linux QoS 數據,非常稀少
即使是現在,雖然市面上已有幾本 Linux QoS 相關中文書籍了
但網絡上的 Linux QoS 的中文討論,仍是寥寥可數
故小弟今日貼此一篇,望能拋磚引玉之效,開創 Linux QoS 風潮

Linux QoS 的技術
基礎的像此篇管制小型網絡頻寬之應用
進階的可以配合 l7-filter 做 service 的頻寬管制
到深入一點,複雜一點的
更可以藉由 iproute2 多重路由,達到多WAN的架構

沒有留言: