摘要:本文主要介紹如何用Linux做一個功能完備的路由器,這里將主要介紹靜態路由器和動態路由器的配置,但不包括IP偽裝或者說公用一個IP地址訪問外面網絡等問題。其已經不屬于本主題討論的范圍,請參考其他如防火墻的配置等的內容。
LRP(Linux Router Project) 已經成立了有好幾年的時間了。這個計劃的目的是利用Linux操作系統將老舊的個人電腦如486當成網絡的路由器使用。利用Linux低成本建立的路由器 可能引起企業界廣泛的注意。正如StoneFly Technology的系統整合工程師Bret Berger所說的,對無法負擔兩千(美元)思科 (Cisco)路由器的使用者來說,利用486加上幾張以太網卡,當成路由器使用,是另一個選擇。而對于一些小型企業、小型ISP ,甚至是政府機構,這 是一個很好的解決方案。事實上目前國內高校很多場合正是利用了這一解決方案。
由于LRP計劃已經把Linux的源代碼精簡 化,LRP軟件可以少于2MB ,同時也可以將LRP軟件放入一張軟盤內。也就是說在沒有硬盤的情況下,LPR也可以利用軟盤,載入電腦中使用。 Virtual Design Group的軟件工程師Michael Kornegay則表示,他們已經將Linux路由器軟件安裝在一架老舊的x86 個人電腦上,再加上兩張以太網卡,沒有使用硬盤的設備,只是使用軟盤啟動,便當成陽春型的路由器與防火墻使用。
我們在這一章 里不是教大家如何制作小于2MB的LRP軟件包,而是告訴大家如何利用Linux來獲得一個性能良好、價格低廉的路由器。利用Linux構建路由器使用的 成本雖然便宜,可是在性能與效率上與真正的路由器相比,卻還是有一段距離。對于玩家們或是一些要求不高的使用者來說,這是一個不錯的選擇。
什么是路由器?
gated的配置
gated支持RIP、OSPF、IS-IS等路由協議。我們這里著重介紹RIP協議的配置方法,其他協議的配置大家可以針對協議本身然后參考相關幫助文檔做類似的配置就可以。
首先修改/etc/sysconfig/network文件,使得FORWARD_IPV4=yes。然后在/etc/目錄下創建文件名為gated.conf的文件,里面就是需要填寫的配置信息。RIP協議的配置語法如下:
rip yes | no | on | off [ {
broadcast ;
nobroadcast ;
nocheckzero ;
preference preference;
defaultmetric metric ;
query authentication [none | [[simple|md5] password]] ;
interface interface_list
[noripin] | [ripin]
[noripout] | [ripout]
[metricin metric]
[metricout metric]
[version 1]|[version 2 [multicast|broadcast]]
[[secondary] authentication [none | [[simple|md5] password]] ;
trustedgateways gateway_list ;
sourcegateways gateway_list ;
traceoptions trace_options ;
} ] ;
上面的配置語法用來啟動或者禁止RIP協議的運行,并對RIP協議某些參數進行設置。各參數的含義如下:
broadcast 指明RIP分組將被廣播。當廣播靜態路由或者由其他協議產生的RIP路由項時,這很有用。
nobroadcast 指明當然的接口上不廣播RIP分組。
nocheckzero 指明RIP不處理RIP分組中的保留域。通常RIP將拒絕保留域為非零的分組。
preference preference 設置RIP路由的preference,其缺省值是100,這個值可以被其他的給定的策略重寫。
metric metric 定義當使用RIP廣告由其他路由協議獲得的路由信息時使用的尺度(metric)。其缺省值為16(不可達)。
query authentication [none | [[simple|md5] password]] ; 設定身份認證密碼。缺省是無需認證。
interface interface_list 針對某特定的接口進行參數設定。
可以有的參數如下:
noripin 指定該接口商接收的RIP分組無效。
ripin 這是缺省的參數。與noripin相反。
noripout 被指定的接口上將無RIP分組發出。缺省值是在所有的廣播和非廣播的接口商發送送RIP分組。
ripout 這是缺省值。與noripout的含義相反。
metricin metric 指定在新添加的路由表項加入內核路由表以前增加的尺度(metric)。缺省值是1。
metricout metric 指定通過特定的接口發出的RIP前,對尺度的增加值。缺省值是0。
version 1 指定發送第一個版本的RIP協議的分組。缺省值是這個。
version 2 在指定的接口商發送第二個版本的RIP協議分組。如果IP組播可以使用,則缺省發送完全第二版本的分組,如果不支持組播,則使用與第一版本兼容的第二版本的RIP分組。
multicast 指明在特定接口上的第二版本的RIP分組使用組播發送。
broadcast 指明在特定的接口上使用廣播來發送與第一版本兼容的第二版本的RIP分組,即使該接口支持組播。
[secondary] authentication [none | [simple|md5] password] 定義身份認證的方式。只對第二版本的RIP協議有用。缺省是無身份認證。
trustedgateways gateway_list 定義RIP接收RIP更新分組的網關。gateway_list 是一個簡單的主機名或者IP地址的列表。缺省情況下,在共享網絡上的所有的路由器都被認為支持提供RIP更新信息。
sourcegateways gateway_list 定義RIP直接發送分組的路由器列表,而不通過組播或者廣播。
traceoptions trace_options 設置RIP跟蹤選項。詳細設置略。
下面是些配置示例:
配置1:
#
#
# This configuration runs RIP in quiet mode, it only listens to
# packets, no matter how many interfaces are configured.
#
rip yes {
nobroadcast ;
} ;
配置2:
# This configuration emulates routed. It runs RIP and only sends
# updates if there are more than one interfaces up and IP forwarding is
# enabled in the kernel.
#
# NOTE that RIP *will not* run if UDP checksums are disabled in
# the kernel.
#
rip yes ;
zebra介紹
這 是日本人寫的以GNU版權方式發布的軟件,開始于1996年,主要的功能是實現了 RIPv1,RIPv2,RIPng, OSPFv2, OSPFv3, BGP-4, and BGP-4+路由協議,目前是0.87版,目前支持 Linux和FreeBSD,將來會支持Solaris 7和GNU Hurd。
其中 RIPv1, RIPv2, OSPFv2是用于IPv4的自治域系統內部網絡路由協議,最好的是OSPF,他支持VLSM(變長子網掩碼)、收斂快,能 根據鏈路的負載等動態調整路由,是目前最好的所有廠商都支持的內部路由協議。跟他差不多(也許還要好)的是cisco專有的EIGRP.
BGP- 4是用于自治域系統之間的外部網絡路由協議,也是目前Internet主干上目前使用的協議,非常的靈活。在國外用的非常普遍,如果一個網絡有兩個以上出 口(連接兩個ISP)極大的可能會用他。但是在國內好象很少使用,這也跟國內的網絡比較封閉有關。假如我們跟CSTNET和CETNET使用BGP-4的 話,只要這兩個出口一個是通的,我們對外的連接不會中斷超過1分鐘。
RIPng OSPFv3, BGP-4+主要擴展了對ipv6的支持。
這個軟件配置的很多方面跟cisco的IOS配置幾乎完全相同,我們完全可以拿一臺PC機來完成一些必須用昂貴的CISCO路由器才能完成的比較復雜的路由協議處理控制功能。
GNU Zebra可以到www.zebra.org去找。
路由器上的策略控制:IP帶寬管理(QoS)
為什么要管理帶寬?
因 特網的成功主要因素是IP(Internet Protocol)協議族的簡單和穩健。現在幾乎所有的人都在向IP靠攏,甚至傳統的電訊公司也在將它們的 基于電路交換的語音網絡向IP網絡轉。然而基于IP協議的因特網這時候就遇到了一個非常大的困難。它不相ATM協議,它是平等地對待任何業務,也就是說所 有的通過IP網絡的數據都被平等地盡可能好的傳送(稱:盡力型服務)。如果我愿意多付1倍的錢,我也不能讓我的主頁下載的速度提高一倍。這時候就引入了 QoS概念,也就是服務質量保證。這種情況下,平等對待所有IP業務數據的方法就要被放棄,而試圖區分不同的用戶或業務,然后分配不同的帶寬。這就是路由 器上的帶寬的分配和管理。
這些年來,不同的技術發展很 快,IETF(Internet Engineering Task Force)已經發布了幾種標準,包括:綜合服務、區分服務、資源預留技術。這些標 準都在Linux下有了實現。但它們的使用是個綜合的問題,需要網絡其他路由器的配合(例如資源預留),所以當前在實踐中使用不是很廣,但隨著因特網業務 的不斷增加,它們會逐漸越來越多的被大家使用的。
Linux內核2.1.x及后續版本里面主要是引入了traffic control代碼,來實現IP帶寬的分配和管理。
TC的特點
TC 是Traffic Control的縮寫,中文意思即為"流量控制"。TC有很大的伸縮性。作為一個提供虛擬主機服務的ISP來說,它可以利用Linux 的流量控制來給不同的客戶不供的服務質量保證。傳統的出售虛擬主機或者提供主頁存放服務的ISP通常是提供不同的磁盤空間來作為不同檔次的服務,例如一個 月100元可以獲得100M的空間。如果使用Linux的流量控制(TC),我們就可以多提供一種有區分的不同的服務,例如你是一個提供虛擬主機服務的 ISP,你可以有如下多的不同的服務選擇:
· 服務水平1: 花費¥100/月――瀏覽者獲得250Kbps的瀏覽頁面速度。
· 服務水平2: 花費¥150/月--250Kbps,但是如果帶寬允許的話在午夜0點 到臨晨6點之間可以達到1Mbps。
· 服務水平3: 花費¥200/月--250Kbps, 但是如果帶寬允許的話可以最大達到1Mbps,不限制時間(與服務水平2區別之處)。
· 服務水平4:花費¥500/月--提供1Mbps的高速的帶寬保證。適合視頻和音頻流的服務。
由上面的例子,我們可以利用TC很方便的指定各種有控制的服務規則。上面提到的每天不同時段提供不同的服務,我們可以很容易的用crontab來定時運行一些腳本去改變帶寬分配規則來達到。這是一個比較好的例子,我們在后面將介紹一個實例。
TC的使用實例說明
下面我們提供一個利用TC來實現對在一個Linux服務器上的兩個虛擬主機實行不同的帶寬策略的例子。在該例中,我們將講述如何配置和測試TC。
編譯內核
至于如何編譯一個新的內核已經不屬于本章節討論的范圍,我們假設你已經知道如何重新編譯一個內核。
編譯內核時將以下幾個內核選項選中:"kernel/User netlink socket"和"Netlink device emulation"。這樣TC就可以利用netlink來與內核傳送信息。同時將所有的排隊算法選上,位于包括
"Fair queueing"
"CBQ packet scheduler"
"CSZ packet scheduler"
"the simples PRIO pseudoscheduler"
"RED queue"
"SFQ queue"
"TBF queue"
"QoS support"
"rate estimator"
"packet classifier API"
"routing-tables-based classifier"
"U32 classifier"
"special RSVP classifier and special RSVP classifier for IPv6"。
選中這些選項以后,按正常的編譯內核步驟編譯內核,然后安裝新內核,并用新內核重新啟動系統。
編譯TC軟件包
可以在下面的地址下載到我們需要的軟件,然后按照軟件包里的說明編譯它:
ftp://linux.wauug.org/pub/net/ip-routing/iproute2-current.tar.gz 通常我們要做的只是簡單的輸入make就可以了。
TC 的設定
圖1. CBQ 樹圖
圖 一是我們將配置的一個系統的簡單的樹形圖示范。兩個葉子節點從父節點分配帶寬,IP地址10.0.0.10(標識符1:1)和地址10.0.0.11(標 識符1:2)是接口eth0上的IP別名,它們共同分享父節點(標識符1:0)的帶寬。這個例子里面只涉及到了對一個接口上的流量控制,大家可以仿照這個 例子構造自己感興趣的控制多個接口設備的配置。
配置QoS特性的第一步就是將qdisc加入到一個接口上,例如本例子:
qdisc add dev eth0 root handle 1: ...
然后定義你需要區別的類別。不同的類別對應不同的流量控制類型。我們的例子中,使用如下的語句:
tc class add dev eth0 parent 1:0 classid X:Y ...
我 們的例子中只使用了一層深的類別樹。當然,我們可以構造多層深度的復雜的樹,基本的原則是一樣的:就是一個子節點(如圖1所示)繼承一個父節點的資源同時 進一步根據類的定義去分配父節點的資源。例如,父類1:0擁有該設備的全部帶寬,那么子節點1:1不可能獲得超過10Mbits的帶寬,當然本例子中是限 制為1Mbps。
最后定義"IP分組--類別"的映射規則,用來告訴系統的分類器,經過路由器調度的某IP分組該對應什么類型。首先,將一個分類器與輸出接口關聯起來:
filter add dev eth0 parent 1:0 protocol ip ...
然后,定義"IP分組--類別"的映射規則。本例子中,將利用IP分組的源地址來作為分類的關鍵詞。 下面的腳本完成了這個功能。關于腳本中TC等命令的參數,大家可以參考隨機的文檔,這里限于篇幅,不做介紹了。
#! /bin/sh
#path to tc and the ip utilities;
#change to reflect yours.
TC=./iproute2/tc/tc
IP=./iproute2/ip/ip
##################################################
#Addresses to be aliased
#change or add more to reflect yours
#
ALIAS1=10.0.0.10
ALIAS2=10.0.0.11
##################################################
# add ip aliasing support
#uncomment if you want to use the ip utility to
#add ip-aliasing for you
#
#$IP addr add $ALIAS1 dev eth0
#$IP addr add $ALIAS2 dev eth0
##################################################
# Attaching a device queue discipline to an
# interface a device queue discipline is
# equivalent almost to a device manager
#
#Attach CBQ to eth0
#Things you might need to change:
# bandwidth -- the bandwidth of the eth0 device
# note it must match the devices real bandwidth
# allot -- it is safe to leave it at the MTU of
# the device
# avpkt -- the average packet size that you
# suspect will be seen safe to leave at 1000
# for Ethernet with MTU of 1514 bytes
# mpu -- minimum packet size
#
$TC qdisc add dev eth0 root handle 1: cbq
bandwidth 10Mbit allot 1514 cell 8 avpkt 1000
mpu 64
##################################################
# Attaching class queue disciplines
# bounded -- it is bound to the rate allocated;
# can borrow even if there is a lot of idle
# bandwidth just sitting there isolated -- cannot
# share its bandwidth to other classes prio is the
# priority assigned 0 being the highest and 7 the
# lowest weight -- safer to leave at 1
# queue discipline setup. Classid 1:1 will have a
# rate of 1Mbps which is bounded.
#
$TC class add dev eth0 parent 1:0 classid 1:1 cbq
bandwidth 10Mbit rate 1Mbit avpkt 1000 prio 5
bounded isolated allot 1514 weight 1 maxburst 21
#rate 1Mbit avpkt 1000 prio 5 bounded allot 1514
#weight 1 maxburst 21
# Classid 1:2 will have a rate of 3Mbps which is
# bounded.
$TC class add dev eth0 parent 1:0 classid 1:2 cbq
bandwidth 10Mbit rate 3Mbit avpkt 1000 prio 5
bounded allot 1514 weight 1 maxburst 21
##################################################
# Define the filter to be attached to eth0
# Create with hash table of 256 slots with ID 1:
#
$TC filter add dev eth0 parent 1:0 protocol ip
prio 5 handle 1: u32 divisor 256
##################################################
# define the criteria for mapping incoming packets
# to classes. Add to the 5th slot of hash table a
# rule to select virtual address ALIAS1 direct it
# to class 1:1
#
$TC filter add dev eth0 parent 1:0 prio 5 u32
ht 1:6: match ip src $ALIAS1 flowid 1:1
# Add to 6th slot of hash table rule to select
# ALIAS2 direct it to class 1:2
$TC filter add dev eth0 parent 1:0 prio 5 u32
ht 1:6: match ip src $ALIAS2 flowid 1:2
## Lookup hash table, if it is not fragmented
## frame. Use protocol as hash key
#
$TC filter add dev eth0 parent 1:0 prio 5 handle
::1 u32 ht 800:: match ip nofrag
offset mask 0x0F00 shift 6
hashkey mask 0x00ff0000 at 8 link 1:
#
#some more examples of how to use u32
# Add to 4th slot of hash table rule to select
# tcp/telnet to 193.233.7.75 direct it to class
# 1:4 and prescribe to fall to best effort,
# if traffic violates TBF (32kbit,5K)
#$TC filter add dev eth1 parent 1:0 prio 5 u32
# ht 1:4: match ip dst 193.233.7.75
# match tcp dst 0x17 0xffff
# flowid 1:4
# police rate 32kbit buffer 5kb/8 mpu 64
# mtu 1514 index 1
## Add to 1st slot of hash table rule to select
## icmp to 193.233.7.75 direct it to class 1:3
## and prescribe to fall to best effort,
## if traffic violate TBF (10kbit,5K)
#$TC filter add dev eth1 parent 1:0 prio 5 u32
# ht 1:4: match ip dst 193.233.7.75
# match tcp dst 0x17 0xffff
# flowid 1:4
# police rate 32kbit buffer 5kb/8 mpu 64
# mtu 1514 index 1
## Add to 1st slot of hash table rule to select
## icmp to 193.233.7.75 direct it to class 1:3
## and prescribe to fall to best effort,
## if traffic violate TBF (10kbit,5K)
#$TC filter add dev eth1 parent 1:0 prio 5 u32
# ht 1:: sample ip protocol 1 0xff
# match ip dst 193.233.7.75 flowid 1:3
# police rate 10kbit buffer 5kb/8 mpu 64
# mtu 1514 index 2
##################################################
#Look at all that we created:
#
echo "---- qdisc parameters ----------"
$TC qdisc ls dev eth0
echo "---- Class parameters ----------"
$TC class ls dev eth0
echo "---- filter parameters ----------"
$TC filter ls dev eth0
測試
我們的例子當中,是有在同一個Linux服務器上有兩個虛擬WWW服務器,我們的設定是采用了IP別名,將兩個地址同時綁在一個接口上。我們可以用ftp來 測試。首先用ftp連接10.0.0.10服務器,我們可以獲得大概1Mbps的速率;然后ftp另外的地址10.0.0.11,我們可以獲得大概 3Mbps的速率。