具多重路徑頻寬整合能力的路由架構 — 以社區網路整合為例
李讚紘 廖享進 吳啟瑞 陳致舜
長庚大學網路資訊策進會
cccc@stmail.cgu.edu.tw
本文就開放原始碼技術,提出一套高效率且低成本又能透過多個網際網路服務提供者(nternet Service Provider, ISP )骨幹線路,作為整體網路對外頻寬的路由架構, 並實作出 具備多重路徑路由、頻寬整合、 QoS 能力的路由器 來作為架構中的運作主幹。同時我們將此架構實際使用在社區網路的架設上,從實際的運作狀況和實驗,驗證該架構的可行性。
ECMP 的應用
ECMP ,比較正確的說法應該是「以目的位置為基礎的負載平衡」( Destination Address-Based Load Balancing )路由。一般路由器為一個 IP 位址進行路由動作的時候,通常會因為效能的問題而先去查驗路由器中暫存 (Cache) 的資料,如果目標 IP 並沒有在暫存空間中,那麼路由器會先檢查比對自己的 Routing Table ,來決定該 IP 位址的路由去向,並將該路由 放進暫存 中。通常來說,路由器中的路由功能只能為某個封包決定唯一的路由,但使用 ECMP 機制,可以讓某個 Package Pattern 具有好幾種不同的路由方向,讓某個符合路由條件的封包透過相同權重( Equal Cost )的方式或是自訂的權重來選擇這個封包該走的路由。
根據這個關鍵技術,可以設計出一個依據連線 Session ( by Session )的流量負載平衡的路由架構,此架構可以應用於任何市面常見的 ADSL 頻寬撥接線路、專線等,實踐出多重線路的頻寬整合機制。此機制同時還不限制使用的 ISP ,對於一般組織或企業來說,不但能夠大幅降低流量集中於部分線路而造成網路擁塞的狀況,也可以達到頻寬的最佳運用以及降低建置成本,提高網路線路的使用效率。甚至搭配一些開放原始碼社群所提供的 Patch ,還可以做到依據封包( By Packet )的流量負載平衡!
我們採用 Linux 作為此多重路由架構中的中心作業路由器平台, Linux 在近來開放原始碼機制發展下,對於網路路由方面的機制有長遠的進步和相當的成熟度,同時也支援 ECMP 機制,而且對於 QoS 和 Firewall 等線路 頻寬控管 議題的解決方案也相當多元,是我們實作一台多功能路由器的首選。同時我們採用 Gentoo 這套 Linux Distribution ,他的設定更動彈性大以及運作效能,都是我們考量的目標。
QoS 的導入
對於多重路徑的路由架構,只做到頻寬整合和負載平衡,在實際應用面上還是不足的。現代網路應用多元,使用者對頻寬的需求與渴望也越來越大,因此在「開源」的部分除了採取多重線路的政策之外,在「節流」面上也有相當多的作法, QoS 即是一種相當有效率的方法。而 QoS 的主要目的包括有:利用控制網路的延遲性來提供即時性的服務、提供專屬的頻寬、提供改進網路封包的遺失率、或是提供保留網路頻寬來達到有效的網路服務品質。在眾多的網路服務中 QoS 機制能夠讓最優先的服務封包運作傳輸,例如假設管理者最重視 RTP 傳輸等及時的影像及語音服務,就可以考慮使用 QoS 機制讓這些類型的 封包先通過 網路設備,確保影音不會被其他的如 FTP 、 WWW 、 TELNET 等影響。在技術層面來說, QoS 機制可以讓路由器辨別所有進出的 封包並切割 一個頻寬,讓最重要的 封包先通過 ,次要的服務 封包將在 不影響重要的封包情況下通過。
這是一個相當成熟且實用的技術,尤其對於多重線路下的路由決策設計上,更可以有效增進頻寬的利用率,以及調控整體網路的運用狀況。由於採用 Linux 為路由作業平台的中心,因此我們使用其中已經內建的 Iptables 中的 Mangle Table 來實作,使用的 Packet Scheduler 是 HTB (從 Linux Kernel 2.4.20 之後便內建於核心中)
架構設計與實作
我們將以一個社區網路整合的案例,實際說明此路由架構的規劃以及實作。這個社區網路使用的人數大約有 75 人,網路使用需求為網際網路服務、 線上遊戲 、以及 彼此間的資料 分享存取等等,根據需求,我們以 Layer 2 Switch 先在內部規劃一個區域網路,滿足網路內使用人的資料分享需求,並且避免無謂的區域網路內流量影響路由器運作。另外我們根據這個人數比例和需求去評估頻寬的使用量, 規劃拉牽了 四條頻寬為 3 M bps 的 ADSL ,同時也由於我們申請的 ADSL 線路每條線路只給予我們一個實體 IP ,因此我們在內部的區域網路上使用了 NAT 機制來解決 IP 不足的問題。在此網路使用需求中,還有線上遊戲這種封包多 屬小而且多的需求,有網路實務經驗的網管人員大都瞭解,一般網路 設備均不擅長 處理細小且多的封包,因此我們導入了 QoS 機制於主要運作的路由器上,控管這類型封包存取先後的權重。整體系統架構圖如圖一所示。
(為了方便以下實作文字說明,在此定義 ISP1 的線路 IP 為 61.62.82.255 , Gateway 為 61.62.82.254 , Netmask 為 255.255.255.0 , Broadcast 為 61.62.82.254 )

圖一、系統架構
系統架構規劃完畢, 我們部豎規劃 後端的區域網路相關線路及機器節點。由於這個區域網路中有將近百 個 的使用者,因此我們使用了兩台以上的 Layer2 Switch ,並利用 Trunk 技術將之串連起來成為一個區域網路後,開始實作本架構中最重要的中心路由器。
首先 先 製作這台機器上最重要的 OS Kernel ,在製作 Kernel 途中的 config 階段,特別注意這些選項: Advanced Router 、 Policy Routing 、 Equal Cost Multipath 、 Large Routing Tables 和其他 Iptables 和 QoS 的選項。裝好基礎系統後,只需要再安裝 Iptables and Iproute 套件,並且調整系統參數 /proc/sys/net/ipv4/ip_forward 為 1 ,以實踐後續的 NAT 、 QoS 機制。
對於 kernel ,我的習慣是不編模組,把所有東西 全編進 kernel 。另外別 忘記編完 kernel 後,要設定一下 process parameters ,下面是這次實驗所使用的:
/bin/echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_all
/bin/echo "1" > /proc/sys/net/ipv4/icmp_echo_ignore_broadcasts
/bin/echo "0" > /proc/sys/net/ipv4/conf/all/accept_source_route
/bin/echo "0" > /proc/sys/net/ipv4/conf/all/accept_redirects
/bin/echo "1" > /proc/sys/net/ipv4/icmp_ignore_bogus_error_responses
( 上面這些是一般的安全設定,大家可隨自己喜好設定。)
for i in /proc/sys/net/ipv4/conf/*; do
/bin/echo "0" > $ i/rp_filter
done
( 建議打開,不過如果是作 Asymmertric Routing ,不能打開。)
/bin/echo "0" > /proc/sys/net/ipv4/conf/all/log_martians
接著就是進行最重要的 Equal-Cost MultiPath Routing 的線路頻寬整合以及流量負載平衡的部分。這次的實驗在這個部分有加了一個 kernel patch ,主要是加了 Static routes, Alterna-tive routing... 等功能,這些 Patch 是針對 NAT 使用 Multi- PathRouting 做一些最佳化的設定,有興趣可以看一下: http://www.ssi.bg/~ja/#routes , 而後續底下的設定是配合這些 Patch 所使用的。
另外這邊最重要的一個觀念,就是 Linux 中的路由系統都會有一個預設的 Main Routing Table ,而在 Main Routing Table 或是任何自己設定的 Routing Table 中, Default Route 就是其預設規則。
設定的順序為:
(設定中心路由器的 Loopback )
ip link set lo up
ip addr add 127.0.0.1/8 brd + dev lo
(設定對內網路介面 eth0 )
ip link set eth0 up
ip addr add 192.168.0.254/16 brd + dev eth0
ip route del default table main
(依序設定對外的 4 個網路介面 IP 位置,以 eth1 為例)
ip link set eth1 up
ip addr add 61.62.82.88/24 brd 61.62.82.255 dev eth1
這邊並沒有指定預設的通訊閘,同時在系統的 Main Routing Table Default Rules 中,也沒有預設的 Routing 。接下來依序 4 個對外網路介面的 Routing Tables (以 eth1 為例):
ip rule add prio 201 from 61.62.82.88 table 201
ip route add default via 61.62.82.254 dev eth1 src 61.62.82.88 proto static table 201
ip route append prohibit default table 201 metric 1 proto static
後續的網卡設定別忘了調整 pri o 和 table 的部分。
在上一個步驟中,我們其實還沒有指定 source ip (指對外而言),可在此指定,另外,每 個 介面設定第三行的意思是指如果這個介面沒有作用,便告知連線端的 Client 這邊是「 PKT_FILTERED 」,使封包改由其他介面出去。所以當一個封包已經進行到這個步驟, Kernel 會尋找可以符合 Routing Rules 的 Table 讓這個封包得以行進下去。但如果依照我們所想要的結果,一定是每 個 Routing Table 皆會正常運作,但是這樣子設定只能從一個介面,因此為了達到多重線路的路由,還有一個步驟-設定系統的 Default Route :
ip rule add prio 222 table 222
ip route add default table 222 proto static \
nexthop via 61.62.82.254 dev eth1 \
nexthop via ( ISP2 線路 Gateway ) dev eth2 \
nexthop via ( ISP3 線路 Gateway ) dev eth3 \
nexthop via ( ISP4 線路 Gateway ) dev eth4
至此中心路由器的多重線路頻寬整合,負載平衡的功能已經實作完畢,我們繼續在此中心路由器上添加 Source NAT 機制,以讓區域網路內的 IP 足夠使用。
iptables -t nat -A POSTROUTING -o eth1 -s 192.168.0.0/16 -j SNAT --to eth1 的實體 IP
iptables -t nat -A POSTROUTING -o eth2 -s 192.168.0.0/16 -j SNAT --to eth2 的實體 IP
iptables -t nat -A POSTROUTING -o eth3 -s 192.168.0.0/16 -j SNAT --to eth3 的實體 IP
iptables -t nat -A POSTROUTING -o eth4 -s 192.168.0.0/16 -j SNAT --to eth4 的實體 IP
ADSL 先天上的不良就是上 傳頻寬過 小,加上現在的 P2P Software 又一堆,因此做頻寬管理是有必要的,不過在這邊我們的作法,並沒有限制每個人的 上傳頻寬 ,只是對各種不同類型的封包排出 priority 而已。因此我們所作的 QoS 主要是搭配 iptables 裡面的 mangle table 使用。 我們只針對上傳的 部分作控管 ,使用的 Packet Scheduler 是 HTB ,號稱處理起來效果比 CBQ 更好,從 2.4.20 以後就有加入 kernel 了,所以不用 patch kernel ,本來我們是要用這東西的:
http://www.sonicspike.net/software/download/dsl_qos_queue-0.7.tar.gz
據作者說效果比使用 iptables 更好,另外也不用 patch kernel ,不過作者好像沒有考慮到 Multiple Interfaces ,所以實際測試起來怪怪的,只好放棄。
請大家看看這些文件:
http://www.docum.org/stef.coene/qos/docs/
最後,我們再將 QoS 機制加入中心路由器功能中。我們依序設定 4 個對外網路介面的 QoS 設定(以 eth1 為例):
ip link set dev eth1 mtu 1000
tc qdisc add dev eth1 root handle 1: htb default 25
tc class add dev eth1 parent 1: classid 1:1 htb rate 364kbit
最後並作 add leaf classes 以及 attach qdisc to leaf classes 的動作,就能夠做 filter traffic into classes by fwmark ,最後再將其 MYSHAPER-OUT chain 增加到 IPtables 中的 Mangle Table 即可。
整個 QoS 機制設定完成後,我們就能根據不同用途的封包在 Iptables 中的 Mangle Type 下排定處理的權重,我們列舉以下的部分例子做為參考:
(設定 ICMP 的權重在較高的位置)
iptables -t mangle -A MYSHAPER-OUT -p udp -j MARK --set-mark 21
(設定 TCP port 在 1024 以下的權重)
iptables -t mangle -A MYSHAPER-OUT -p tcp -- dport 0:1024 -j MARK --set-mark 24
至此,整個路由架構以及中心路由 器均已設計 完畢,我們已經實作出了一個具備多重線路路由、流量負載平衡並兼具 QoS 機制的路由架構。
實際測試與結論
此架構網路約測試用一個半月,並沒有產生任何不穩定的情況,而中心路由器的 Loading 也相當穩定,我們在此實際案例中使用 1G 的 CPU 再加上 256 MB RAM 就已經可以運作的相當穩定且有效率,平均系統負荷( Loading Average ) 均在 1 以下。另外在 QoS 機制方面,根據實驗所得的結果顯示,實作前後的差異 可說是相當 明顯,對於整體網路的流暢度幫助不小。我們試驗過使用 FTP 服務對外抓檔,每 個 連線的速率大約為每秒 300 K ,同時開了 4 個連線( 3 M bps 的 ADSL 實際運作的 最 高速大約為每秒 320 K ),在測試的時間,使用 telnet 服務開啟 4 個連線對外傳輸約 1000 字元的文字檔均相當順暢,網路 延遲均在 10 毫秒 以內。針對此案例,我們採用的流量負載平衡機制雖然是依據連線 Session 來作 負載平衡,有可能遭遇單一 Session 流量過大而導致平衡機制失效的憂慮,但由於 QoS 機制的適當運用,整體線路封包在適當的權重安排下,我們從中心路由器上的 Netflow 監控上也能夠看到流量很平均的分散在 4 條對外線路上。近來開放原始碼社群,有組織地研發出依據封包( By Packet ) 來作 流量負載平衡的 ECMP 機制 Kernel Patch ,相信也可以嘗試利用在本架構上。主要的設定上差異應該只在設定系統 Default Route 的時候,在第一行的設定中指定使用 equalize 參數即可! 不過使用 By Packet 的機制,後續會有一些問題,比如路由目的地沒法紀錄你到底是從那個 IP 來;或者當封包從外部路由經由一家 ISP 進來後,回應封包卻不是走原 ISP 的 gateway 回去。因此在本架構中我們不採用 By Packet,而使用 By Session,而事實上證明在 QOS 機制的導入下,By Session 在正式運用上已經能相當足夠的滿足應用需求!
本架構中心路由器的設定技術,相信也可以應用在許多以 Linux 為基礎的嵌入式平台路由器上,對於商業廠商實作成本低廉的 Multi-Homing 且兼具 QoS 機制的網路設備 上,再加上 DDNS 技術與Linux上的VPN Solution,跟市面上現在冒出來的一堆 Multi-Homing Device 相比,其實也只差在我們沒時間去寫漂亮的 Web Control UI 而已!
本文最後附上這次設定的完整設定檔案 ,供有興趣研究的人參考。
http://peterkim.cgucccc.org/document/scripts.zip
參考文獻
[3] http://deesse.univ-lemans.fr:8003/Connected/RFC/1583/9.html
[4] http://www.ssi.bg/~ja/nano.txt
[5] http://www.ssi.bg/~ja/#routes
[6] http://www.docum.org/stef.coene/qos/docs/
[7] http://phorum.study-area.org/viewtopic.php?t=10085
欲使用 DDNS請參考:
http://www.study-area.org/tips/ddns.htm