Version: RouterOS v6.24
這一篇我們來簡單探討一下如何在MikroTik RouterOS上實作QoS (Quality of Service),在這之前,有幾個名詞我們先釋義
Queue:
佇列,透過一個先進先出(FIFO)的緩衝區,先把要送往外的封包儲存起來後再根據條件往外送出,可以用來限制頻寬。
有關Queue的詳細說明,可以參考MirkoTik Queue
HTB(Hierarchical Token Bucket):
一個採優先權制的階層式佇列模式。依照優先權來決定,將擁有較高優先權的封包往外送。
有關HTB的詳細說明,可以參考MikroTik Queue - HTB
PCQ(Per Connection Queue):
一種佇列的準則,用來動態平均分配頻寬給所有的使用者。
有關PCQ的詳細說明,可以參考MikroTik Queue - PCQ
我們這次要應用這些功能來實現QoS。在 [/queue] 裡面,共有三樣東西:
1. /queue simple
2. /queue tree
3. /queue type
先來說說 [/queue type],這裡用來描述不同的佇列應用種類,除了預先設定的幾個之外,我們可以根據我們的需求來新增,這時我們先來設定兩個新的種類,並建構於PCQ這項演算法
/queue type
add kind=pcq name=Download_PCQ pcq-classifier=dst-address pcq-limit=100 pcq-rate=300M pcq-total-limit=5000 pcq-src-address-mask=32 pcq-dst-address-mask=32 pcq-src-address6-mask=128 pcq-dst-address6-mask=128
add kind=pcq name=Upload_PCQ pcq-classifier=src-address pcq-limit=100 pcq-rate=100M pcq-total-limit=5000 pcq-src-address-mask=32 pcq-dst-address-mask=32 pcq-src-address6-mask=128 pcq-dst-address6-mask=128
其中Download_PCQ的pcq-classifier=dst-address,表示我們要依據下載的目標地址來平均分配頻寬,也就是依據區網內每一台設備來分;而Upload_PCQ的pcq-classifier=src-address,表示我們要依據上傳的來源地址來平均分配頻寬,也是依據區網內每一台設備來分。
pcq-limit=100,代表每一台設備可以有100個封包的緩衝區,而pcq-total-limit=5000則表示我們最多支援50台設備。根據之前MikroTik提供的資料,緩衝區中每一個封包約需2200 bytes的儲存空間,因此pcq-total-limit=5000全用滿也就需要10.5MB的RAM,上傳加下載全用滿就需要21MB的RAM。有關pcq-limit設定值的影響,可以參考MikroTik Queue Size
好,接下來我們來說說 [/queue simple] 及 [/queue tree] 的不同點,這時需要MikroTik的Packet Flow v6來幫忙 http://wiki.mikrotik.com/images/f/f3/PacketFlowDiagram_v6_c.svg
1. Queue只發生在Input Chain及PostRouting Chain
2. [/queue tree] 限制過頻寬一次後,還會交由 [/queue simple] 再限制一次
在 [/queue simple] 裡面的規則,是序列式處理,一條規則接著一條規則運行;在 [/queue tree] 裡面的規則,是平行式處理,整體而言處理速度較快也消耗較少系統資源。我們今天拿 [/queue tree] 來使用,因為 [/queue tree] 裡面的規則是根據每個封包的標記來決定要進行的動作,所以在設定 [/queue tree] 前,我們先來介紹 [/ip firewall mangle] 裡的 "mark packet" 與 "mark connection"
mark-connection與mark-packet
注意:封包中所有的標記只會留在RouterOS內使用,一旦離開RouterOS的範圍,封包中的任何標記將被移除
封包的標記,是針對每一個滿足條件的封包進行標記,也就是說條件設定的愈多,需要進行比對的動作也就愈多;條件設定的愈少,需要進行比對的動作也就愈少,換句話說
/ip firewall mangle
add action=mark-packet chain=forward protocol=tcp dst-port=443 src-address=192.168.1.0/24 new-packet-mark=SSL out-interface=PPPoE passthrough=no
add action=mark-packet chain=forward protocol=tcp src-port=443 dst-address=192.168.1.0/24 new-packet-mark=SSL in-interface=PPPoE passthrough=no
每個封包在forward chain時,就要比對是否是TCP?是否目的埠是443?是否來源地只是來自於192.168.1.0/24網段?是否out-interface是WAN?如果都是,則添加SSL標記到這個封包。這麼多的比對動作在forward chain的每個封包都要跑過一次。如果改成
/ip firewall mangle
add action=mark-connection chain=forward protocol=tcp dst-port=443 src-address=192.168.1.0/24 new-connection-mark=SSL_conn out-interface=PPPoE
add action=mark-packet chain=forward connection-mark=SSL_conn new-packet-mark=SSL passthrough=no
則當forward chain上的第一個封包因為符合TCP, port 443, 來自192.168.1.0/24, out-interface是PPPoE之後,會被冠上SSL_conn的連線標記,此後此連線上所有的封包都會自動冠上SSL_conn的連線標記。而在forward chain上的封包在做封包標記檢查時,只要確認這個封包是否有含SSL_conn連線標記,如果有則加上SSL封包標記。比對動作由原先的每個封包四個降到每個封包一個,大幅縮減系統資源。
Queue Tree
介紹完mark-connection與mark-packet,我們來進入Queue Tree,今天要介紹的一種通用的概念。Queue的優先權共分為8類,Priority設定由1~8,其中1代表最高優先級、8代表最低優先級。
/queue tree
add max-limit=100M name=Total_Upload parent=global priority=1 queue=default
add max-limit=300M name=Total_Download parent=global priority=1 queue=default
add limit-at=270M max-limit=300M name=Download_Int parent=Total_Download priority=1 queue=default
add limit-at=30M max-limit=300M name=Download_NonInt parent=Total_Download queue=default
add limit-at=90M max-limit=100M name=Upload_Int parent=Total_Upload priority=1 queue=default
add limit-at=10M max-limit=100M name=Upload_NonInt parent=Total_Upload queue=default
add name=Download_Int_P1 packet-mark=Down_Int_P1 parent=Download_Int queue=Download_PCQ
add name=Download_Int_P2 packet-mark=Down_Int_P2 parent=Download_Int queue=Download_PCQ
add name=Download_Int_P3 packet-mark=Down_Int_P3 parent=Download_Int queue=Download_PCQ
add name=Download_Int_P4 packet-mark=Down_Int_P4 parent=Download_Int queue=Download_PCQ
add name=Download_Int_P5 packet-mark=Down_Int_P5 parent=Download_Int queue=Download_PCQ
add name=Download_Int_P6 packet-mark=Down_Int_P6 parent=Download_Int queue=Download_PCQ
add name=Download_Int_P7 packet-mark=Down_Int_P7 parent=Download_Int queue=Download_PCQ
add name=Download_Int_P8 packet-mark=Down_Int_P8 parent=Download_Int queue=Download_PCQ
add name=Download_NonInt_P1 packet-mark=Down_NonInt_P1 parent=Download_NonInt queue=Download_PCQ
add name=Download_NonInt_P2 packet-mark=Down_NonInt_P2 parent=Download_NonInt queue=Download_PCQ
add name=Download_NonInt_P3 packet-mark=Down_NonInt_P3 parent=Download_NonInt queue=Download_PCQ
add name=Download_NonInt_P4 packet-mark=Down_NonInt_P4 parent=Download_NonInt queue=Download_PCQ
add name=Download_NonInt_P5 packet-mark=Down_NonInt_P5 parent=Download_NonInt queue=Download_PCQ
add name=Download_NonInt_P6 packet-mark=Down_NonInt_P6 parent=Download_NonInt queue=Download_PCQ
add name=Download_NonInt_P7 packet-mark=Down_NonInt_P7 parent=Download_NonInt queue=Download_PCQ
add name=Download_NonInt_P8 packet-mark=Down_NonInt_P8 parent=Download_NonInt queue=Download_PCQ
add name=Upload_Int_P1 packet-mark=Up_Int_P1 parent=Upload_Int queue=Upload_PCQ
add name=Upload_Int_P2 packet-mark=Up_Int_P2 parent=Upload_Int queue=Upload_PCQ
add name=Upload_Int_P3 packet-mark=Up_Int_P3 parent=Upload_Int queue=Upload_PCQ
add name=Upload_Int_P4 packet-mark=Up_Int_P4 parent=Upload_Int queue=Upload_PCQ
add name=Upload_Int_P5 packet-mark=Up_Int_P5 parent=Upload_Int queue=Upload_PCQ
add name=Upload_Int_P6 packet-mark=Up_Int_P6 parent=Upload_Int queue=Upload_PCQ
add name=Upload_Int_P7 packet-mark=Up_Int_P7 parent=Upload_Int queue=Upload_PCQ
add name=Upload_Int_P8 packet-mark=Up_Int_P8 parent=Upload_Int queue=Upload_PCQ
add name=Upload_NonInt_P1 packet-mark=Up_NonInt_P1 parent=Upload_NonInt queue=Upload_PCQ
add name=Upload_NonInt_P2 packet-mark=Up_NonInt_P2 parent=Upload_NonInt queue=Upload_PCQ
add name=Upload_NonInt_P3 packet-mark=Up_NonInt_P3 parent=Upload_NonInt queue=Upload_PCQ
add name=Upload_NonInt_P4 packet-mark=Up_NonInt_P4 parent=Upload_NonInt queue=Upload_PCQ
add name=Upload_NonInt_P5 packet-mark=Up_NonInt_P5 parent=Upload_NonInt queue=Upload_PCQ
add name=Upload_NonInt_P6 packet-mark=Up_NonInt_P6 parent=Upload_NonInt queue=Upload_PCQ
add name=Upload_NonInt_P7 packet-mark=Up_NonInt_P7 parent=Upload_NonInt queue=Upload_PCQ
add name=Upload_NonInt_P8 packet-mark=Up_NonInt_P8 parent=Upload_NonInt queue=Upload_PCQ
在這情況下,只要設定好packet-mark,自然會落入我們規劃好的優先權範圍內,所以在這之前,我們要先加入以下設定
/ip firewall mangle
add action=mark-packet chain=prerouting connection-mark=Int_P1 new-packet-mark=Down_Int_P1 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=Int_P2 new-packet-mark=Down_Int_P2 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=Int_P3 new-packet-mark=Down_Int_P3 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=Int_P4 new-packet-mark=Down_Int_P4 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=Int_P5 new-packet-mark=Down_Int_P5 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=Int_P6 new-packet-mark=Down_Int_P6 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=Int_P7 new-packet-mark=Down_Int_P7 passthrough=no
add action=mark-packet chain=prerouting connection-mark=Int_P8 new-packet-mark=Down_Int_P8 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P1 new-packet-mark=Down_NonInt_P1 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P2 new-packet-mark=Down_NonInt_P2 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P3 new-packet-mark=Down_NonInt_P3 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P4 new-packet-mark=Down_NonInt_P4 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P5 new-packet-mark=Down_NonInt_P5 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P6 new-packet-mark=Down_NonInt_P6 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P7 new-packet-mark=Down_NonInt_P7 in-interface=PPPoE passthrough=no
add action=mark-packet chain=prerouting connection-mark=NonInt_P8 new-packet-mark=Down_NonInt_P8 in-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P1 new-packet-mark=Up_Int_P1 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P2 new-packet-mark=Up_Int_P2 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P3 new-packet-mark=Up_Int_P3 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P4 new-packet-mark=Up_Int_P4 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P5 new-packet-mark=Up_Int_P5 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P6 new-packet-mark=Up_Int_P6 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P7 new-packet-mark=Up_Int_P7 passthrough=no
add action=mark-packet chain=postrouting connection-mark=Int_P8 new-packet-mark=Up_Int_P8 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P1 new-packet-mark=Up_NonInt_P1 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P2 new-packet-mark=Up_NonInt_P2 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P3 new-packet-mark=Up_NonInt_P3 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P4 new-packet-mark=Up_NonInt_P4 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P5 new-packet-mark=Up_NonInt_P5 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P6 new-packet-mark=Up_NonInt_P6 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P7 new-packet-mark=Up_NonInt_P7 out-interface=PPPoE passthrough=no
add action=mark-packet chain=postrouting connection-mark=NonInt_P8 new-packet-mark=Up_NonInt_P8 out-interface=PPPoE passthrough=no
在這樣的方式之下,我們不再針對每一個特定連線條件而單獨給它一個優先級,取而代之的是通用式,換句話說,我們會根據特定連線條件給封包一個落於上述區間的連線標記。舉個例子,假設要設定通過port 80的HTTP連線為優先級3,我們就可以這樣設定
/ip firewall mangle
add action=mark-connection chain=forward dst-port=80 new-connection-mark=Int_P3 out-interface=PPPoE protocol=tcp
又或者要設定BT的優先級是最低的,我們可以這樣設定
/ip firewall mangle
add action=mark-connection chain=forward new-connection-mark=NonInt_P8 p2p=all-p2p
add action=mark-connection chain=forward dst-port=4662,16881 new-connection-mark=NonInt_P8 protocol=tcp
add action=mark-connection chain=forward dst-port=4672,6881 new-connection-mark=NonInt_P8 protocol=udp
藉由這樣的方式,未來我們想針對某些條件設定優先權時,就可以只在mark-connection動手腳就好,此外,拿BT與HTTP來作示範,當有人在上網、有人在下載BT時,這是瀏覽網頁的優先權就會比下載BT的高,而當多人同時下載BT時,還記得我們在Queue Tree時的 [queue=Download_PCQ]嗎?每一台下載BT的設備也會取得平均分配的頻寬,而又不影響到其他人上網瀏覽網頁的權利,同時瀏覽網頁的所有設備也會取得平均分配的頻寬。
記憶體的使用,依照先前計算的若上傳加下載的PCQ要用掉21MB,我們在Queue Tree裡設定8組的Interactive及8組的Non-Interactive,如果全部用滿,則約需21MBx16=336MB的RAM。
延伸閱讀
.[開箱] MikroTik CCR1016-12G
.MikroTik RouterOS VPN (PPTP/L2TP/OpenVPN/SSTP/SSH Tunnel)
.MikroTik RouterOS Stateless Tunnel (EoIP/IPIP/GRE)
.MikroTik RouterOS IGMP Proxy w/ CHT MOD
.MikroTik RouterOS Hairpin NAT - Pros & Cons
.MikroTik RouterOS Hotspot
.MikroTik RouterOS User Manager - RADIUS
.MikroTik RouterOS Load Balancing - Pros & Cons