- 論壇徽章:
- 1
|
TCP/IP詳解(四)
習題
9.1 為什么你認為存在兩類ICMP改變路由報文——網(wǎng)絡(luò)和主機?
9.2 在9 .4節(jié)開頭列出的svr4主機上的路由表中,到主機slip(140.252.13.65)的特定路由是必需的嗎?如果把這一項從路由表中刪除會有什么變化?
9.3 考慮有一電纜連接4.2BSD主機和4.3BSD主機。假定網(wǎng)絡(luò)號是140.1。4.2BSD主機把主機號為全0的地址識別的廣播地址(140.1.0.0)。另外,4.2BSD主機在默認條件下要盡力轉(zhuǎn)發(fā)接收到的數(shù)據(jù)報,盡管它們只有一個接口。
請描述當4.2BSD主機收到一份目的地址為140.1.255.255的IP數(shù)據(jù)報時會發(fā)生什么事。
9.4 繼續(xù)前一個習題,假定有人在子網(wǎng)140.1上的某個系統(tǒng)ARP高速緩存中增加了一項(用arp命令)內(nèi)容,指定IP地址140.1.255.255對應(yīng)的以太網(wǎng)地址為全1(以太網(wǎng)廣播地址)。請描述此時發(fā)生的情況。
9.5 檢查你所使用的系統(tǒng)上的路由表,并解釋每一項內(nèi)容。
9-6
10 動態(tài)選路協(xié)議
10.1 引言
在前面各章中,我們討論了靜態(tài)選路。在配置接口時,以默認方式生成路由表項(對于直接連接的接口),并通過route命令增加表項(通常從系統(tǒng)自引導(dǎo)程序文件),或是通過ICMP改變路由生成表項(通常是在默認方式出錯的情況下)。
在網(wǎng)絡(luò)很小時,與其它網(wǎng)絡(luò)只有單個連接點且沒有多余路由時(若主路由失敗時,可以使用備用路由),采用這種方法是可行的。如果上述三種情況不能全部滿足的話,通常使用動態(tài)選路。
本章討論動態(tài)選路協(xié)議,它用于路由器間的通信。我們主要討論RIP,即選路信息協(xié)議(Routing Infromation Protocol),大多數(shù)TCP/IP實現(xiàn)都提供的這個應(yīng)用廣泛的協(xié)議。然后我們討論兩種新的選路協(xié)議,OSPF和BGP。本章的最后研究了一種名叫無分類域間選路的新的選路技術(shù),現(xiàn)在Internet上正在開始采用該協(xié)議以保持B類網(wǎng)絡(luò)的數(shù)量。
10.2 動態(tài)選路
當相鄰路由器之間進行通信,以告知對方每個路由器當前所連接的網(wǎng)絡(luò),這時就出現(xiàn)了動態(tài)選路。路由器之間必須采用選路協(xié)議進行通信,這種選路協(xié)議有很多種。路由器上有一個進程稱為路由守護程序(routing daemon),它運行選路協(xié)議,并與其相鄰的一些路由器進行通信。正如圖9.1所示,路由守護程序根據(jù)它從相鄰路由器接收到的信息,更新內(nèi)核中的路由表。
動態(tài)選路并不改變我們在9.2節(jié)中所描述的內(nèi)核在IP層的選路方式。我們這種選路方式稱為選路機制(routing mechanism)。內(nèi)核搜索路由表,查找主機路由、網(wǎng)絡(luò)路由以及默認路由的方式并沒有改變。僅僅是放置到路由表中的信息改變了——當路由隨時間變化時,路由是由路由守護程序動態(tài)地增加或刪除,而不是來自于自引導(dǎo)程序文件中的route命令。
正如我們前面所描述的那樣,路由守護程序?qū)⑦x路策略(routing policy)加入到系統(tǒng)中,選擇路由并加入到內(nèi)核的路由表中。如果守護程序發(fā)現(xiàn)前往同一信宿存在多條路由,那么它(以某種方法)將選擇最佳路由并加入內(nèi)核路由表中。如果路由守護程序發(fā)現(xiàn)一條鏈路已經(jīng)斷開(可能是路由器崩潰或電話線路不好),它可以刪除受影響的路由或增加另一條路由以繞過該問題。
在像Internet這樣的系統(tǒng)中,目前采用了許多不同的選路協(xié)議。Internet是以一組自治系統(tǒng)AS(Autonomous sys tem)的方式組織的,每個自治系統(tǒng)通常由單個實體管理。常常將一個公司或大學校園定義為一個自治系統(tǒng)。NSFNET的Internet骨干網(wǎng)形成一個自治系統(tǒng),這是因為骨干網(wǎng)中的所有路由器都在單個的管理控制之下。
每個自治系統(tǒng)可以選擇該自治系統(tǒng)中各個路由器之間的選路協(xié)議。這種協(xié)議我們稱之為內(nèi)部網(wǎng)關(guān)協(xié)議IGP(Interior Gateway Protocol)或域內(nèi)選路協(xié)議(intradomain routing protocol)。最常用的IGP是選路信息協(xié)議RIP。一種新的IGP是開放最短路徑優(yōu)先OSPF(Open Shortest Path First)協(xié)議。它意在取代RIP。另一種1986年在原來NSFNET骨干網(wǎng)上使用的IGP協(xié)議——HELLO,現(xiàn)在已經(jīng)不用了。
(下面是原書p.128①的譯文)
新的RFC [Almquist 1993]規(guī)定,實現(xiàn)任何動態(tài)選路協(xié)議的路由器必須同時支持OSPF和RIP,還可以支持其它IGP協(xié)議。
外部網(wǎng)關(guān)協(xié)議EGP(Exterier Gateway Protocol)或域內(nèi)選路協(xié)議的分隔選路協(xié)議用于不同自治系統(tǒng)之間的路由器。在歷史上,(令人容易混淆)改進的EGP有著一個與它名稱相同的協(xié)議:EGP。新EGP是當前在NSFNET骨干網(wǎng)和一些連接到骨干網(wǎng)的區(qū)域性網(wǎng)絡(luò)上使用的是邊界網(wǎng)關(guān)協(xié)議BGP(Border Gateway Protocol)。BGP意在取代EGP。
10.3 Unix選路守護程序
Unix系統(tǒng)上常常運行名為routed 路由守護程序。幾乎在所有的TCP/IP實現(xiàn)中都提供該進程。該程序只使用RIP進行通信,我們將在下一節(jié)中討論該協(xié)議。這是一種用于小型到中型網(wǎng)絡(luò)中的協(xié)議。
另一個程序是gated。IGP和EGP都支持它。[Fedor 1998]描述了早期開發(fā)的gated。圖10.1對routed和兩種不同版本的gated所支持的不同選路協(xié)議進行了比較。大多數(shù)運行路由守護程序的系統(tǒng)都可以運行routed,除非它們需要支持gated所支持的其它協(xié)議。
圖10.1 routed和gated所支持的選路協(xié)議
我們在下一節(jié)中描述RIP 版本1,在10.5中描述它與RIP版本2的不同點,10.6節(jié)描述OSPF,在10.7節(jié)描述BGP。
10.4 RIP:選路信息協(xié)議
本節(jié)對RIP進行了描述,這是因為它是最廣為使用(也是最受攻擊)的選路協(xié)議。對于RIP的正式描述文件是RFC 1058 [Hedrick 1988a],但是該RFC是在該協(xié)議實現(xiàn)數(shù)年后才出現(xiàn)的。
報文格式
RIP報文包含中在UDP數(shù)據(jù)報中,如圖10.2所示。(我們在第11章中對UDP進行更為詳細的描述。)
圖10.2 封裝在UDP數(shù)據(jù)報中的RIP報文
圖10.3給出了使用IP地址時的RIP報文格式。
命令字段為1表示請求,2表示回答。還有兩個舍棄不用的命令(3和4),兩個非正式的命令:輪詢(5)和輪詢表項(6)。請求表示要求其它系統(tǒng)發(fā)送其全部或部分路由表。回答則包含發(fā)送者全部或部分路由表。
版本字段通常為1,而第2版RIP(10.5節(jié))將此字段設(shè)置為2。
緊跟在后面的20字節(jié)指定地址系列(address family)(對于IP地址來說,其值是2),IP地址以及相應(yīng)的度量。我們在本節(jié)的后面可以看出,RIP的度量是以跳計數(shù)的。
采用這種20字節(jié)格式的RIP報文可以通告多達25條路由。上限25是用來保證RIP報文的總長度為20×25 + 4 = 504,小于512字節(jié)。由于每個報文最多攜帶25個路由,因此為了發(fā)送整個路由表,經(jīng)常需要多個報文。
正常運行
讓我們來看一下采用RIP協(xié)議的routed程序正常運行的結(jié)果。RIP常用的UDP端口號是520。
•初始化:在啟動一個路由守護程序時,它先判斷啟動了哪些接口,并在每個接口上發(fā)送一個請求報文,要求其它路由器發(fā)送完整路由表。在點對點鏈路中,該請求是發(fā)送給其它終點的。如果網(wǎng)絡(luò)支持廣播的話,這種請求是以廣播形式發(fā)送的。目的UDP端口號是520(這是其它路由器的路由守護程序端口號)。
這種請求報文的命令字段為1,但地址系列字段設(shè)置為0,而度量字段設(shè)置為16。這是一種要求另一端完整路由表的特殊請求報文。
•接收到請求。如果這個請求是我們剛才提到的特殊請求,那么路由器就將完整的路由表發(fā)送給請求者。否則的話,就處理請求中的每一個表項:如果我們有連接到指明地址的路由,則將度量(metric)設(shè)置成我們的值,否則將度量置為16。(度量為16是一種稱為“無窮大”的特殊值,它意味著我們沒有到達目的的路由。)然后發(fā)回響應(yīng)。
•接收到響應(yīng)。使響應(yīng)生效,可能會更新路由表?赡軙黾有卤眄棧瑢σ延械谋眄椷M行修改,或是將已有表項刪除。
•定期選路更新。每過30秒,所有或部分路由器會將其完整路由表發(fā)送給相鄰路由器。發(fā)送路由表可以是廣播形式的(如在以太網(wǎng)上),或是發(fā)送給點對點鏈路的其它終點的。
•觸發(fā)更新。每當一條路由的度量發(fā)生變化時,就對它進行更新。不需要發(fā)送完整路由表,而只需要發(fā)送那些發(fā)生變化的表項。
每條路由都有與之相關(guān)的定時器。如果運行RIP的系統(tǒng)發(fā)現(xiàn)一條路由在3分鐘內(nèi)未更新,就將該路由的度量設(shè)置成無窮大(16),并標注為刪除。這意味著我們已經(jīng)在6個30秒更新時間里沒收到通告該路由的路由器的更新了。再過60秒,將從本地路由表中刪除該路由,以保證該路由的失效已被傳播開。
度量
RIP所使用的度量是以跳(hop)計算的。所有直接連接接口的跳數(shù)為1?紤]圖10.4所示的路由器和網(wǎng)絡(luò)。我們畫出的4條虛線是廣播RIP報文。
圖10.4 路由器和網(wǎng)絡(luò)示例
路由器R1通過發(fā)送廣播到N1通告它與N2之間的跳數(shù)是1。(發(fā)送給N1的廣播中通告它與N1之間的路由是無用的。)它同時也通過發(fā)送廣播給N2通告它與N1之間的跳數(shù)為1。同樣,R2通告它與N2的度量為1,與N3的度量為1。
如果相鄰路由器通告它與其它網(wǎng)絡(luò)路由的跳數(shù)為1,那么我們與那個網(wǎng)絡(luò)的度量就是2,這是因為為了發(fā)送報文到該網(wǎng)絡(luò),我們必須經(jīng)過那個路由器。在我們的例子中,R2到N1的度量是2,與R1到N3的度量一樣。
由于每個路由器都發(fā)送其路由表給鄰站,因此,可以判斷在同一個自治系統(tǒng)AS內(nèi)到每個網(wǎng)絡(luò)的路由。如果在該AS內(nèi)從一個路由器到一個網(wǎng)絡(luò)有多條路由,那么路由器將選擇跳數(shù)最小的路由,而忽略其它路由。
跳數(shù)的最大值是15,這意味著RIP只能用在主機間最大跳數(shù)值為15的AS內(nèi)。度量為16表示到無路由到達該IP地址。
問題
這種方法看起來很簡單,但它有一些缺陷。首先,RIP沒有子網(wǎng)地址的概念。例如,如果標準的B類地址中16 bit的主機號不為0,那么RIP無法區(qū)分非零部分是一個子網(wǎng)號,或者是一個主機地址。有一些實現(xiàn)中通過接收到的RIP信息,來使用接口的網(wǎng)絡(luò)掩碼,而這有可能出錯。
其次,在路由器或鏈路發(fā)生故障后,需要很長的一段時間才能穩(wěn)定下來。這段時間通常需要幾分鐘。在這段建立時間里,可能會發(fā)生路由環(huán)路。在實現(xiàn)RIP時,必須采用很多微妙的措施來防止路由環(huán)路的出現(xiàn),并使其盡快建立。RFC 1058 [Hedrick 1988a]中指出了很多實現(xiàn)RIP的細節(jié)。
采用跳數(shù)作為路由度量忽略了其它一些應(yīng)該考慮的因素。同時,度量最大值為15則限制了可以使用RIP的網(wǎng)絡(luò)的大小。
例子
我們將使用ripquery程序來查詢一些路由器中的路由表,該程序可以從gated中得到。ripquery程序通過發(fā)送一個非正式請求(圖10.3中命令字段為5的“poll”)給路由器,要求得到其完整的路由表。如果在5秒內(nèi)未收到響應(yīng),則發(fā)送標準的RIP請求(command字段為1)。(我們前面提到過的,將地址系列字段置為0,度量字段置為16的請求,要求其它路由器發(fā)送其完整路由表。)
圖10.5給出了我們將從sun主機上查詢其路由表的兩個路由器。如果我們在主機 sun上執(zhí)行ripquery程序,以得到其下一站路由器netb的選路信息,那么我們可以得到下面的結(jié)果:
sun % ripquery -n netb
504 bytes from netb (140.252.1.183): 第一份報文包含504字節(jié)
這里刪除了許多行
140.252.1.0, metric 1 圖10.5上面的以太網(wǎng)
140.252.13.0, metric 1 圖10.5下面的以太網(wǎng)
244 bytes from netb (140.252.1.183): 第二份報文包含剩下的244字節(jié)
下面刪除了許多行
正如我們所猜想的那樣,netb告訴我們子網(wǎng)的度量為1。另外,與netb相連的位于機端的以太網(wǎng)(140.252.1.0)的metric也是1。(-n參數(shù)表示直接打印IP地址而不需要去查看其域名。)在本例中,將netb配置成認為所有位于140.252.13子網(wǎng)的主機都與其直接相連——即,netb并不知道哪些主機真正與140.252.13子網(wǎng)相連。由于與140.252.13子網(wǎng)只有一個連接點,因此,通告每個主機的度量實際上沒有太大意義。
圖10.5 我們將要查詢其路由表內(nèi)容的兩個路由器netb和gateway
圖10.6給出了使用tcpdump交換的報文。我們采用-i s10參數(shù)指定SLIP接口。
圖10.6 運行ripquery程序的tcpdump輸出結(jié)果
第一個請求發(fā)出一個RIP輪詢命令(第1行)。這個請求在5秒后超時,發(fā)出一個常規(guī)的RIP請求(第2行)。第1行和第2行最后的24表示請求報文的長度:4個字節(jié)的RIP首部(包括命令和版本),然后是單個20字節(jié)的地址和度量。
第3行是第一個回答報文。該行最后的25表示包含了25個地址和度量對,我們在前面已經(jīng)計算過,其字節(jié)數(shù)為504。這是上面的ripquery程序所打印出來的結(jié)果。我們?yōu)閠cpdump程序指定-s600選項,以讓它從網(wǎng)絡(luò)中讀取600個字節(jié)。這樣,它可以接收整個UDP數(shù)據(jù)報(而不是報文的前半部),然后打印出RIP響應(yīng)的內(nèi)容。我們將該輸出結(jié)果省略了。
第4行是來自路由器的第二個響應(yīng)報文,它包含后面的12個地址和度量對。我們可以計算出,該報文的長度為12×20 + 4=244,這正是ripquery程序前面所打印出來的結(jié)果。
如果我們越過netb路由器,到gateway,那么可以預(yù)測到我們子網(wǎng)(140.252.13.0)的度量為2。我們可以運行下面的命令來進行驗證:
sun % ripquery -n gateway
504 bytes from gateway (140.252.1.4):
這里刪除了許多行
140.252.1.0, metric 1 圖10.5上面的以太網(wǎng)
140.252.13.0, metric 1 圖10.5下面的以太網(wǎng)
這里,位于圖10.5上面的以太網(wǎng)(140.252.1.0)的度量依然是1,這是因為該以太網(wǎng)直接與gateway和netb相連。而我們的子網(wǎng)140.252.13.0正如預(yù)想的一樣,其度量為2。
另一個例子
我們現(xiàn)在察看以太網(wǎng)上所有非主動請求的RIP更新,以看一看RIP定期給其鄰站發(fā)送的信息。圖10.7是noao.edu網(wǎng)絡(luò)的多種排列情況。為了簡化,我們不用本文其它地方所采用的路由器表示方式,而以Rn來代表路由器,其中n是子網(wǎng)號。我們以虛線表示點對點鏈路,并給出了這些鏈路對端的IP地址。
圖10.7 noao.edu 140.252的多個網(wǎng)絡(luò)
我們在主機solaris上運行Solaris 2.x的snoop程序,它與tcpdump相類似。我們可以在不需要超用戶權(quán)限的條件下運行該程序,但它只捕獲廣播報文、多播報文,以及發(fā)送給主機的報文。圖10.8給出了在60秒內(nèi)所捕獲的報文。在這里,我們將大部分正式的主機名以Rn來表示。
圖10.8 solaris在60秒內(nèi)所捕獲到的RIP廣播報文
-P 標志以非混雜模式捕獲報文,-tr 打印出相應(yīng)的時戳,而udp port 520 只捕獲信源或信宿端口號為520的UDP數(shù)據(jù)報。
來自R6,R4,R2,R7,R8和R3的前6個報文,每個報文只通告一個網(wǎng)絡(luò)。查看這些報文,我們可以發(fā)現(xiàn)R2通告前往140.252.6.0的跳數(shù)為1的一條路由,R4通告前往140.252.4.0的跳數(shù)為1的一條路由,等等。
但是,gateway路由器卻通告了15條路由。我們可以通過運行 snoop程序時加上-v參數(shù)來查看RIP報文的全部內(nèi)容。(這個標志輸出全部報文的全部內(nèi)容:以太網(wǎng)首部,IP首部,UDP首部,以及RIP報文。我們只保留了RIP信息而刪除了其它信息。)圖10.9給出了輸出結(jié)果。
把這些子網(wǎng)140.252.1上通告報文經(jīng)過的路由與圖10.7中的拓撲結(jié)構(gòu)進行比較。
使人迷惑不解的一個問題是為什么圖10.8輸出結(jié)果中,R10通告其有4個網(wǎng)絡(luò)而在圖10.7中顯示的只有3個。如果我們查看帶snoop的RIP報文,就會得到以下通告路由:
RIP: Address Metric
RIP: 140.251.0.0 16 (not reachable)
RIP: 140.252.9.0 1
RIP: 140.252.10.0 1
RIP: 140.252.11.0 1
前往B類網(wǎng)絡(luò)140.251的路由是假的,不應(yīng)該通告它。(它屬于其它機構(gòu)而不是noao.edu。)
圖10.9 來自gateway的RIP響應(yīng)
圖10.8中,對于 R10發(fā)送的RIP報文,snoop輸出“BROADCAST”符號,它表示目的IP地址是有限的廣播地址255.255.255.255(12.2節(jié)),而不是其它路由器用來指向子網(wǎng)的廣播地址(140.252.1.255)。
10.5 RIP協(xié)議版本2
RFC 1388 [Malkin 1993a]中對RIP定義進行了擴充,通常稱其結(jié)果RIP-2。這些擴充并不改變協(xié)議本身,而是利用圖10.3中的一些標注為“必須為0”的字段來傳遞一些額外的信息。如果RIP忽略這些必須為0的字段,那么,RIP和RIP-2可以互操作。
圖10.10重新給出了由RIP-2定義的圖。對于RIP-2來說,其版本字段為2。
選路域(routing domain)是一個選路守護程序的標識符,它指出了這個數(shù)據(jù)報的所有者。在一個Unix實現(xiàn)中,它可以是選路守護程序的進程號。該域允許管理者在單個路由器上運行多個RIP實例,每個實例在一個選路域內(nèi)運行。
選路標記(routing tag)是為了支持外部網(wǎng)關(guān)協(xié)議而存在的。它攜帶著一個EGP和BGP的自治系統(tǒng)號。
每個表項的子網(wǎng)掩碼應(yīng)用于相應(yīng)的IP地址上。下一站IP地址指明發(fā)往目的IP地址的報文該發(fā)往哪里。該字段為0意味著發(fā)往目的地址的報文應(yīng)該發(fā)給發(fā)送RIP報文的系統(tǒng)。
圖10.10 RIP-2報文格式
RIP-2提供了一種簡單的鑒別機制。可以指定RIP報文的前20字節(jié)表項地址系列為0xffff,路由標記為2。表項中的其余16字節(jié)包含一個明文口令。
最后,RIP-2除了廣播(第12章)外,還支持多播。這可以減少不收聽RIP-2報文的主機的負載。
10.6 OSPF:開放最短路徑優(yōu)先
OSPF是除RIP外的另一個內(nèi)部網(wǎng)關(guān)協(xié)議。它克服了RIP的所有限制。RFC 1247 [Moy 1991]中對第2版OSPF進行了描述。
與采用距離向量的RIP協(xié)議不同的是,OSPF是一個鏈路狀態(tài)協(xié)議。距離向量的意思是,RIP發(fā)送的報文包含一個距離向量(跳數(shù))。每個路由器都根據(jù)它所接收到鄰站的這些距離向量來更新自己的路由表。
在一個鏈路狀態(tài)協(xié)議中,路由器并不與其鄰站交換距離信息。它采用的是每個路由器主動地測試與其鄰站相連鏈路的狀態(tài),將這些信息發(fā)送給它的其它鄰站,而鄰站將這些信息在自治系統(tǒng)中傳播出去。每個路由器接收這些鏈路狀態(tài)信息,并建立起完整的路由表。
從實際角度來看,二者的不同點是鏈路狀態(tài)協(xié)議總是比距離向量協(xié)議收斂更快。收斂的意思是在路由發(fā)生變化后,例如在路由器關(guān)閉或鏈路出故障后,可以穩(wěn)定下來。[Perlman 1992]的9.3節(jié)對這兩種類型的選路協(xié)議的其它方面進行了比較。
OSPF與RIP(以及其它選路協(xié)議)的不同點在于,OSPF直接使用IP。也就是說,它并不使用UDP或TCP。對于IP首部的protocol字段,OSPF有其自己的值(圖3.1)。
另外,作為一種鏈路狀態(tài)協(xié)議而不是距離向量協(xié)議,OSPF還有著一些優(yōu)于RIP的特點。
1. OSPF可以對每個IP服務(wù)類型計算(圖3.2)計算各自的路由集。這意味著對于任何目的,可以有多個路由表表項,每個表項對應(yīng)著一個IP服務(wù)類型。
2. 給每個接口指派一個無維數(shù)的費用?梢酝ㄟ^吞吐率、往返時間、可靠性或其它性能來進行指派?梢越o每個IP服務(wù)類型指派一個單獨的費用。
3. 當對同一個目的地址存在著多個相同費用的路由時,OSPF在這些路由上平均分配流量。我們稱之為流量平衡。
4. OSPF支持子網(wǎng):子網(wǎng)掩碼與每個通告路由相送連。這樣就允許將一個任何類型的IP地址分割成多個不同大小的子網(wǎng)。(我們在3.7節(jié)中給出了這樣的一個例子,稱之為變長度子網(wǎng)。)到一個主機的路由是通過全1子網(wǎng)掩碼進行通告的。默認路由是以IP地址為0.0.0.0,網(wǎng)絡(luò)掩碼為全0進行通告的。
5. 路由器之間的點對點鏈路不需要每端都有一個IP地址。我們稱之為無編號網(wǎng)絡(luò)。這樣可以節(jié)省IP地址——現(xiàn)在非常緊缺的一種資源。
6. 采用了一種簡單鑒別機制?梢圆捎妙愃朴赗IP-2機制(10.5節(jié))的方法指定一個明文口令。
7. OSPF采用多播(第12章),而不是廣播形式,以減少不參與OSPF的系統(tǒng)負載。
隨著大部分廠商支持OSPF,在很多網(wǎng)絡(luò)中OSPF將逐步取代RIP。
10.7 BGP:邊界網(wǎng)關(guān)協(xié)議
BGP是一種不同自治系統(tǒng)之間網(wǎng)關(guān)進行通信的外部網(wǎng)關(guān)協(xié)議。BGP是ARPANET所使用的老EGP的取代品。RFC1267 [Lougheed and Rekhter 1991] 對第3版的BGP進行了描述。
RFC 1268 [Rekhter and Gross 1991] 描述了如何在Internet中使用BGP。下面對于BGP的大部分描述都來自于這兩個RFC文檔。同時,1993年正在開發(fā)第4版的BGP(見RFC 1467 [Topolcic 1993]),以支持我們將在10.8節(jié)中所描述的CIDR。
BGP系統(tǒng)與其它BGP系統(tǒng)之間交換網(wǎng)絡(luò)可到達信息。這些信息包括數(shù)據(jù)到達這些網(wǎng)絡(luò)所必須經(jīng)過的自治系統(tǒng)AS中的所有路徑。這些信息足以構(gòu)造一幅自治系統(tǒng)連接圖。然后,可以根據(jù)連接圖刪除選路環(huán),制訂選路策略。
首先,我們將一個自治系統(tǒng)中的IP數(shù)據(jù)報分成本地流量和通過流量。在自治系統(tǒng)中,本地流量是起始或終止于該自治系統(tǒng)的流量。也就是說,其信源IP地址或信宿IP地址所指確定的主機位于該自治系統(tǒng)中。其它的流量則稱為通過流量。在Internet中使用BGP的一個目的就是減少通過流量。
可以將自治系統(tǒng)分為以下幾種類型:
1. 殘樁自治系統(tǒng)(stub AS),它與其它自治系統(tǒng)只有單個連接。stub AS只有本地流量。
2. 多接口自治系統(tǒng)(multihomed AS),它與其它自治系統(tǒng)有多個連接,但拒絕傳送通過流量。
3. 轉(zhuǎn)送自治系統(tǒng)(transit AS),它與其它自治系統(tǒng)有多個連接,在一些策略準則之下,它可以傳送本地流量和通過流量。
這樣,可以將Internet的總拓撲結(jié)構(gòu)看成是由一些殘樁自治系統(tǒng)、多接口自治系統(tǒng)以及轉(zhuǎn)送自治系統(tǒng)的任意互連。殘樁自治系統(tǒng)和多接口自治系統(tǒng)不需要使用BGP——它們通過運行EGP在自治系統(tǒng)之間交換可到達信息。
BGP允許使用基于策略的選路。由自治系統(tǒng)管理員制訂策略,并通過配置文件將策略指定給BGP。制訂策略并不是協(xié)議的一部分,但指定策略允許BGP實現(xiàn)在存在多個可選路徑時選擇路徑,并控制信息的重發(fā)送。選路策略與政治、安全或經(jīng)濟因素有關(guān)。
BGP與RIP和OSPF的不同之處在于BGP使用TCP作為其傳輸層協(xié)議。兩個運行BGP的系統(tǒng)之間建立一條TCP連接,然后交換整個BGP路由表。從這個時候開始,在路由表發(fā)生變化時,再發(fā)送更新信號。
BGP是一個距離向量協(xié)議,但是與(通告到目的地址跳數(shù)的)RIP不同的是,BGP列舉了到每個目的地址的路由(自治系統(tǒng)到達目的地址的序號)。這樣就排除了一些距離向量協(xié)議的問題。采用16 bit數(shù)字表示自治系統(tǒng)標識。
BGP通過定期發(fā)送keepalive報文給其鄰站來檢測TCP連接對端的鏈路或主機失敗。兩個報文之間的時間間隔建議值為30秒。應(yīng)用層的keepalive報文與TCP的keepalive選項(第23章)是獨立的。
10.8 CIDR:無類型域間選路(Classless Interdomain Routing)
在第3章中,我們指出了B類地址的缺乏,因此現(xiàn)在的多個網(wǎng)絡(luò)站點只能采用多個C類網(wǎng)絡(luò)號,而不采用單個B類網(wǎng)絡(luò)號。盡管分配這些C類地址解決了一個問題(B類地址的缺乏),但它卻帶來了另一個問題:每個C類網(wǎng)絡(luò)都需要一個路由表表項。無類型域間選路(CIDR)是一個防止Internet路由表膨脹的方法。它也稱為超網(wǎng)(supernetting),在RFC 1518 [Rekher and Li 1993] 和RFC 1519 [Fuller et al. 1993]中對它進行了描述,而[Ford, Rekhter, and Braun 1993]是它的綜述。CIDR有一個InternetArchitecture Board's blessing [Huitema 1993]。RFC 1467 [Topolcic 1993] 對Internet中CIDR開發(fā)狀況進行了小結(jié)。
CIDR的基本觀點是采用一種分配多個IP地址的方式,使其能夠?qū)⒙酚杀碇械脑S多表項總和(summarization)成更少的數(shù)目。例如,如果給單個站點分配16個C類地址,以一種可以用總和的方式來分配這16個地址,這樣,所有這16個地址可以參照Internet上的單個路由表表項。同時,如果有8個不同的站點是通過同一個Internet服務(wù)提供商的同一個連接點接入Internet的,且這8個站點分配的8個不同IP地址可以進行總和,那么,對于這8個站點,在Internet上,只需要單個路由表表項。
要使用這種總和,必須滿足以下三種特性。
1. 為進行選路要對多個IP地址進行總和時,這些IP地址必須具有相同的高位地址比特。
2. 路由表和選路算法必須擴展成根據(jù)32 bitIP地址和32 bit掩碼做出選路決策的。
3. 必須擴展選路協(xié)議使其除了32 bit地址外,還要有32 bit掩碼。OSPF(10.6節(jié))和RIP-2(10.5節(jié))都能夠攜帶第4版BGP所提出的32 bit掩碼。
例如,RFC 1466 [Gerich 1993] 建議歐洲新的C類地址的范圍是194.0.0.0到195.255.255.255。以16進制表示,這些地址的范圍是0xc2000000到0xc3ffffff。它代表了65536個不同的C類網(wǎng)絡(luò)號,但他們地址的高7 bit是相同的。在歐洲以外的國家里,可以采用IP地址為0xc2000000和32 bit0xfe000000 (254.0.0.0) 為掩碼的單個路由表表項來對所有這些65536個C類網(wǎng)絡(luò)號選路到單個點上。C類地址的后面各比特位(即在194或195后面各比特)也可以進行層次分配,例如以國家或服務(wù)提供商分配,以允許在歐洲路由器之間,使用除了這32 bit掩碼的高7 bit外的其它比特進行概括。
CIDR同時還使用一種技術(shù),使最佳匹配總是最長的匹配:即在32 bit掩碼中,它具有最大值。我們繼續(xù)采用上一段中所用的例子,歐洲的一個服務(wù)提供商可能會采用一個與其它歐洲服務(wù)提供商不同的接入點。如果給該提供商分配的地址組是從194.0.16.0到194.0.31.255 (16個C類網(wǎng)絡(luò)號),那么可能只有這些網(wǎng)絡(luò)的路由表項的IP地址是194.0.16.0,掩碼為255.255.240.0 (0xfffff000)。發(fā)往194.0.22.1地址的數(shù)據(jù)報將同時與這個路由表表項與其它歐洲C類地址的表項進行匹配。但是由于掩碼255.255.240比254.0.0.0更“長”,因此將采用具有更長掩碼的路由表表項。
“無類型”的意思是現(xiàn)在的選路決策是基于整個32 bitIP地址的掩碼操作。而不管其IP地址是A類、B類或是C類,都沒有什么區(qū)別。
CIDR的最初是針對新的C類地址提出的。這種變化將使Internet路由表增長的速度緩慢下來,但對于現(xiàn)存的選路則沒有任何幫助。這是一個短期解決方案。作為一個長期解決方案,如果將CIDR應(yīng)用于所有IP地址,并根據(jù)各洲邊界和服務(wù)提供商對已經(jīng)存在的IP地址進行重新分配(且所有現(xiàn)有主機重新進行編址。,那么[Ford, Rekhter, and Braun 1993] 是宣稱,目前包含10,000網(wǎng)絡(luò)表項的路由表將會減少成只有200個表項。
10.9 小結(jié)
有兩種基本的選路協(xié)議,即用于同一自治系統(tǒng)各路由器之間的內(nèi)部網(wǎng)關(guān)協(xié)議(IGP)和用于不同自治系統(tǒng)內(nèi)路由器通信的外部網(wǎng)關(guān)協(xié)議(EGP)。
最常用的IGP是路由信息協(xié)議(RIP),而OSPF是一個正在得到廣泛使用的新IGP。一種新近滸的EGP是邊界網(wǎng)關(guān)協(xié)議(BGP)。在本章中,我們考慮了RIP及其交換的報文類型。第2版是RIP是其最近的一個改進版,它支持子網(wǎng),還有一些其它改進技術(shù)。我閃同時也對OSPF,BGP和無類型域間選路(CIDR)進行了描述,CIDR是一種新技術(shù),采用它可以減小Internet路由表的大小。
你可能還會遇到一些其它的OSI選路協(xié)議。域間選路協(xié)議(IDRP)最開始時,是一個為了使用OSI地址而不是IP地址,而進行修改的BGP版本。Intermediate sys tem to Intermediate sys tem 協(xié)議(IS-IS)是OSI的標準IGP?梢杂盟鼇磉x路CLNP(無連接網(wǎng)絡(luò)協(xié)議),這是一種與IP類似的OSI協(xié)議。IS-IS和OSPF相似。
動態(tài)選路仍然是一個網(wǎng)間互連的研究熱點。對使用的選路協(xié)議和運行的路由守護程序進行選擇,是一項復(fù)雜的工作。[Perlman 1992]提供了許多細節(jié)。
習題:
10.1 在圖10.9中哪些路由是從路由器kpno進入gateway的?
10.2 假設(shè)一個路由器要使用RIP通告30個路由,這需要一個包含25條路由和另一個包含5條路由的數(shù)據(jù)報。如果每過一個小時,第一個包含25條路由的數(shù)據(jù)報丟失一次,那么其結(jié)果如何?
10.3 OSPF報文格式中有一個校驗和字段,而RIP報文則沒有此項,這是為什么?
10.4 像OSPF這樣的負載平衡,對于傳輸層的影響是什么?
10.5 查閱RFC 1058 關(guān)于實現(xiàn)RIP的其它資料。在圖10.8中,140.252.1網(wǎng)絡(luò)的每個路由器只通告它所提供的路由,而它并不能通過其它路由器的廣播中知道任何其它路由。這種技術(shù)的名稱是什么?
10.6 在3.4節(jié)中,我們說過除了圖10.7中所示的8個路由器外,140.252.1子網(wǎng)上還有超過100個主機。那么這100個主機是如何處理每30秒到達它們的8個廣播信息呢(圖10.8)?
10-1
11 UDP:用戶數(shù)據(jù)報協(xié)議
11.1 引言
UDP是一個簡單的面向數(shù)據(jù)報的運輸層協(xié)議:進程的每個輸出操作都正好產(chǎn)生一個UDP數(shù)據(jù)報,并組裝成一份待發(fā)送的IP數(shù)據(jù)報。這與面向流字符的協(xié)議不同,如TCP,應(yīng)用程序產(chǎn)生的全體數(shù)據(jù)與真正發(fā)送的單個IP數(shù)據(jù)報可能沒有什么聯(lián)系。
UDP數(shù)據(jù)報封裝成一份IP數(shù)據(jù)報的格式如圖11.1所示。
圖11.1 UDP封裝
RFC 768 [Postel 1980] 是UDP的正式規(guī)約。
UDP不提供可靠性:它把應(yīng)用程序傳給IP層的數(shù)據(jù)發(fā)送出去,但是并不保證它們能到達目的地。由于缺乏可靠性,我們似乎覺得要避免使用UDP而使用一種可靠協(xié)議如TCP。我們在第17章討論完TCP后將再回到這個話題,看看什么樣的應(yīng)用程序可以使用UDP。
應(yīng)用程序必須關(guān)心IP數(shù)據(jù)報的長度。如果它超過網(wǎng)絡(luò)的MTU(2.8節(jié)),那么就要對IP數(shù)據(jù)報進行分片。如果需要,源端到目的端之間的每個網(wǎng)絡(luò)都要進行分片,并不只是發(fā)送端主機連接第一個網(wǎng)絡(luò)才這樣做。(我們在2.9節(jié)中已定義了路徑MTU的概念。)在11.5節(jié)中,我們將討論IP分片機制。
11.2 UDP首部
UDP首部的各字段如圖11.2所示。
圖11.2 UDP首部
端口號表示發(fā)送進程和接收進程。在圖1.8中,我們畫出了TCP和UDP用目的端口號來分用來自IP層的數(shù)據(jù)的過程。由于IP層已經(jīng)把IP數(shù)據(jù)報分配給TCP或UDP(根據(jù)IP首部中協(xié)議字段值),因此TCP端口號由TCP來查看,而UDP端口號由UDP來查看。TCP端口號與UDP端口號是相互獨立的。
(下面是原書p.144①的譯文)
盡管相互獨立,如果TCP和UDP同時提供某種知名服務(wù),兩個協(xié)議通常選擇相同的端口號。這純粹是為了使用方便,而不是協(xié)議本身的要求。
UDP長度字段指的是UDP首部和UDP數(shù)據(jù)的字節(jié)長度。該字段的最小值為8字節(jié)。(發(fā)送一份0字節(jié)的UDP數(shù)據(jù)報是OK。)這個UDP長度是有冗余的。IP數(shù)據(jù)報長度指的是數(shù)據(jù)報全長(圖3.1),因此UDP數(shù)據(jù)報長度是全長減去IP首部的長度(該值在首部長度字段中指定,如圖3.1)。
11.3 UDP檢驗和
UDP檢驗和覆蓋UDP首部和UDP數(shù)據(jù)。回想IP首部的檢驗和,它只覆蓋IP的首部----并不覆蓋IP數(shù)據(jù)報中的任何數(shù)據(jù)。
UDP和TCP在首部中都有覆蓋它們首部和數(shù)據(jù)的檢驗和。UDP的檢驗和是可選的,而TCP的檢驗和是必需的。
盡管UDP檢驗和的基本計算方法與我們在3.2節(jié)中描述的IP首部檢驗和計算方法相類似(16 bit字的二進制反碼和),但是它們之間存在不同的地方。首先,UDP數(shù)據(jù)報的長度可以為奇數(shù)字節(jié),但是檢驗和算法是把若干個16 bit字相加。解決方法是必要時在最后增加填充字節(jié)0,這只是為了檢驗和的計算。(也就是說,可能增加的填充字節(jié)不被傳送。)
其次,UDP數(shù)據(jù)報和TCP段都包含一個12字節(jié)長的偽首部,它是為了計算檢驗和而設(shè)置的。偽首部包含IP首部一些字段。其目的是讓UDP兩次檢查數(shù)據(jù)是否已經(jīng)正確到達目的地(例如,IP沒有接受地址不是本主機的數(shù)據(jù)報,以及IP沒有把應(yīng)傳給另一高層的數(shù)據(jù)報傳給UDP)。UDP數(shù)據(jù)報中的偽首部格式如圖11.3所示。
圖11.3 UDP檢驗和計算過程中使用的各個字段
在該圖中,我們特地舉了一個奇數(shù)長度的數(shù)據(jù)報例子,因而在計算檢驗和時需要加上填充字節(jié)。注意,UDP數(shù)據(jù)報的長度在檢驗和計算過程中出現(xiàn)兩次。
如果檢驗和的計算結(jié)果為0,它存入的值為全1(65535),相當于它的算術(shù)二進制反碼。如果傳送的檢驗和為0,說明發(fā)送端沒有計算檢驗和。
如果發(fā)送端沒有計算檢驗和而接收端檢測到檢驗和有差錯,那么UDP數(shù)據(jù)報就要被悄悄地丟棄。不產(chǎn)生任何差錯報文。(當IP層檢測到IP首部檢驗和有差錯時也這樣做。)
UDP檢驗和是一個端到端的檢驗和。它由發(fā)送端計算,然后由接收端驗證。其目的是為了發(fā)現(xiàn)UDP首部和數(shù)據(jù)在發(fā)送端到接收端之間發(fā)生的任何改動。
盡管UDP檢驗和是可選的,但是它們應(yīng)該始終利用它。在80年代,一些計算機產(chǎn)商在默認條件下關(guān)閉UDP檢驗和的功能,以提高使用UDP協(xié)議的NFS(Network File sys tem)的速度。在單個局域網(wǎng)中這可能是可以接受到,但是在數(shù)據(jù)報通過路由器時,通過對鏈路層數(shù)據(jù)幀進行循環(huán)冗余檢驗(如以太網(wǎng)或令牌環(huán)數(shù)據(jù)幀)可以檢測到大多數(shù)的差錯,導(dǎo)致傳輸失敗。不管相信與否,路由器中也存在軟件和硬件差錯,以致于修改數(shù)據(jù)報中的數(shù)據(jù)。如果關(guān)閉端到端的UDP檢驗和功能,那么這些差錯在UDP數(shù)據(jù)報中就不能被檢測出來。另外,一些數(shù)據(jù)鏈路層協(xié)議(如SLIP)沒有任何形式的數(shù)據(jù)鏈路檢驗和。
(下面是原書p.146①的譯文)
Host Requirements RFC聲明,UDP檢驗和選項在默認條件下是打開的。它還聲明,如果發(fā)送端已經(jīng)計算了檢驗和,那么接收端必須檢驗接收到的檢驗和(如接收到檢驗和不為0)。但是,許多系統(tǒng)沒有遵守這一點,只是在出口檢驗和選項被打開時才驗證接收到的檢驗和。
tcpdump輸出
很難知道某個特定系統(tǒng)是否打開了UDP檢驗和選項。應(yīng)用程序通常不可能得到接收到的UDP首部中的檢驗和。為了得到這一點,作者在tcpdump程序中增加了一個選項,以打印出接收到的UDP檢驗和。如果打印出的值為0,說明發(fā)送端沒有計算檢驗和。
我們測試網(wǎng)絡(luò)上三個不同系統(tǒng)的輸出如圖11.4所示(參見封面二)。運行我們自編的sock程序(附錄C),發(fā)送一份包含9個字節(jié)數(shù)據(jù)的UDP數(shù)據(jù)報給標準回顯服務(wù)器。
圖11.4 tcpdump輸出,觀察其他主機是否打開UDP檢驗和選項
我們從這里可以看出,三個系統(tǒng)中有兩個打開了UDP檢驗和選項。
還要注意的是,在這個簡單例子中,送出的數(shù)據(jù)報與收到的數(shù)據(jù)報具有相同的檢驗和值(第3和第4行,第5和第6行)。從圖11.3我們可以看出,兩個IP地址進行了交換,正如兩個端口號一樣。偽首部和UDP首部中的其他字段都是相同的,就像數(shù)據(jù)回顯一樣。這再次表明UDP檢驗和(事實上,TCP/IP協(xié)議簇中所有的檢驗和)是簡單的16 bit和。它們檢測不出交換兩上16 bit的差錯。
(下面是原書p.147①的譯文)
作者在14.2節(jié)中在八個域名服務(wù)器中各進行了一次DNS查詢。DNS主要使用UDP,結(jié)果只有兩臺服務(wù)器打開了UDP檢驗和選項。
一些統(tǒng)計結(jié)果
文獻[Mogul 1992]提供了在一個繁忙的NFS(Network File sys tem)服務(wù)器上所發(fā)生的不同檢驗和差錯的統(tǒng)計結(jié)果,時間持續(xù)了40天。統(tǒng)計數(shù)字結(jié)果如圖11.5所示。
圖11.5 檢測到不同檢驗和差錯的分組統(tǒng)計結(jié)果
最后一列是每一行的大概總數(shù),因為以太網(wǎng)和IP層還使用有其他的協(xié)議。例如,不是所有的以太網(wǎng)數(shù)據(jù)幀都是IP數(shù)據(jù)報,至少以太網(wǎng)還要使用ARP協(xié)議。不是所有的IP數(shù)據(jù)報都是UDP或TCP數(shù)據(jù),因為ICMP也用IP傳送數(shù)據(jù)。
注意,TCP發(fā)生檢驗和差錯的比例與UDP相比要高得多。這很可能是因為在該系統(tǒng)中的TCP連接經(jīng)常是“遠程”連接(經(jīng)過許多路由器,網(wǎng)橋等中間設(shè)備),而UDP一般為本地通信。
從最后一行可以看出,不要完全相信數(shù)據(jù)鏈路(如以太網(wǎng),令牌環(huán)等)的CRC檢驗。你應(yīng)該始終打開端到端的檢驗和功能。而且,如果你的數(shù)據(jù)很有價值,也不要完全相信UDP或TCP的檢驗和,因為這些都只是簡單的檢驗和,不能檢測出所有可能發(fā)生的差錯。
11.4 一個簡單的例子
用我們自己編寫的sock程序生成一些可以通過tcpdump觀察的UDP數(shù)據(jù)報:
bsdi % sock -v -u -i -n4 svr4 discard
connected on 140.252.13.35.1108 to 140.252.13.34.9
bsdi % sock -v -u -i -n4 -w0 svr4 discard
connected on 140.252.13.35.1110 to 140.252.13.34.9
第一次執(zhí)行這個程序時我們指定verbose模式(-v)來觀察ephemeral端口號,指定UDP(-u)而不是默認的TCP,并且指定源模式(-i)來發(fā)送數(shù)據(jù),而不是讀寫標準的輸入和輸出。-n4選項指明輸出4份數(shù)據(jù)報(默認條件下為1024),目的主機為svr4。我們在1.12節(jié)描述了丟棄服務(wù)。每次寫操作的輸出長度取默認值1024。
第二次運行該程序時我們指定-w0,意思是寫長度為0數(shù)據(jù)報。兩個命令的tcpdump輸出結(jié)果如圖11.6所示。
圖11.6 向一個方向發(fā)送UDP數(shù)據(jù)報時的tcpdump輸出
輸出顯示有四份1024字節(jié)的數(shù)據(jù)報,接著有四份長度為0的數(shù)據(jù)報。每份數(shù)據(jù)報間隔幾毫秒。(輸入第二個命令花了41秒的時間。)
在發(fā)送第一份數(shù)據(jù)報之前,發(fā)送端和接收端之間沒有任何通信。(在第17章,我們將看到TCP在發(fā)送數(shù)據(jù)的第一個字節(jié)之前必須與另一端建立連接。)另外,當收到數(shù)據(jù)時,接收端沒有任何確認。在這個例子中,發(fā)送端并不知道另一端是否已經(jīng)收到這些數(shù)據(jù)報。
最后要指出的是,每次運行程序時,源端的UDP端口號都發(fā)生變化。第一次是1108,然后是110。在1 .9節(jié)我們已經(jīng)提過,客戶程序使用ephemeral端口號一般在1024到5000之間,正如我們現(xiàn)在看到的這樣。
11.5 IP分片
正如我們在2.8節(jié)描述的那樣,物理網(wǎng)絡(luò)層一般要限制每次發(fā)送數(shù)據(jù)幀的最大長度。任何時候IP層接收到一份要發(fā)送的IP數(shù)據(jù)報時,它要判斷向本地哪個接口發(fā)送數(shù)據(jù)(路由選擇),并查詢該接口獲得其MTU。IP把MTU與數(shù)據(jù)報長度進行比較,如果需要則進行分片。分片可以發(fā)生在原始發(fā)送端主機上,也可以發(fā)生在中間路由器上。
當把一份IP數(shù)據(jù)報分片以后,只有到達目的地才進行重新組裝。(這里的重新組裝與其他網(wǎng)絡(luò)協(xié)議不同,它們要求在下一站就進行進行重新組裝,而不是在最終的目的地。)重新組裝由目的端的IP層來完成,其目的是使分片和重新組裝過程對運輸層(TCP和UDP)是透明的,除了某些可能的越級操作外。已經(jīng)分片過的數(shù)據(jù)報有可能會再次進行分片(可能不止一次)。IP首部中包含的數(shù)據(jù)為分片和重新組裝提供了足夠的信息。
回憶IP首部(圖3.1),下面這些字段用于分片過程。對于發(fā)送端發(fā)送的每份IP數(shù)據(jù)報來說,其標識字段都包含一個唯一值。該值在數(shù)據(jù)報片時被復(fù)制到每個片中。(我們現(xiàn)在已經(jīng)看到這個字段的用途。)標志字段用其中一個比特來表示“更多的片”。除了最后一片外,其他每個組成數(shù)據(jù)報的片都要把該比特置1。片偏移字段指的是該片偏移原始數(shù)據(jù)報開始處的位置。另外,當數(shù)據(jù)報被分片后,每個片的總長度值要改為該片的長度值。
最后,標志字段中有一個比特稱作“不分片”位。如果將這一比特置1,IP將不對數(shù)據(jù)報進行分片。相反把數(shù)據(jù)報丟棄并發(fā)送一個ICMP差錯報文(“需要進行分片但設(shè)置了不分片比特”,圖6 .3)給發(fā)起端。在下一節(jié)我們將看到出現(xiàn)這個差錯的例子。
當IP數(shù)據(jù)報被分片后,每一片都成為一個分組,具有自己的IP首部,并在選擇路由時與其他分組獨立。這樣,當數(shù)據(jù)報的這些片到達目的端時有可能會失序,但是在IP首部中有足夠的信息讓接收端能正確組裝這些數(shù)據(jù)報片。
盡管IP分片過程看起來是透明的,但有一點讓人不想使用它:即使只丟失一片數(shù)據(jù)也要重傳整個數(shù)據(jù)報。為什么會發(fā)生這種情況呢?因為IP層本身沒有超時重傳的機制——由更高層來負責超時和重傳。(TCP有超時和重傳機制,但UDP沒有。一些UDP應(yīng)用程序本身也執(zhí)行超時和重傳。)當來自TCP報文段的某一片丟失后,TCP在超時后會重發(fā)整個TCP報文段,該報文段對應(yīng)于一份IP數(shù)據(jù)報。沒有辦法只重傳數(shù)據(jù)報中的一個數(shù)據(jù)報片。事實上,如果對數(shù)據(jù)報分片的是中間路由器,而不是發(fā)起的端系統(tǒng),那么發(fā)起的端系統(tǒng)就無法知道數(shù)據(jù)報是如何被分片的。就這個原因,經(jīng)常要避免分片。文獻[Kent and Mogul 1987]對避免分片進行了論述。
使用UDP很容易導(dǎo)致IP分片。(在后面我們將看到,TCP試圖避免分片,但對于應(yīng)用程序來說幾乎不可能強迫TCP發(fā)送一個需要進行分片的長報文段。)我們可以用sock程序來增加數(shù)據(jù)報的長度,直到分片發(fā)生。在一個以太網(wǎng)上,數(shù)據(jù)幀的最大長度是1500字節(jié)(圖2.1),其中1472字節(jié)留給數(shù)據(jù),假定IP首部為20字節(jié),UDP首部為8字節(jié)。我們分別以數(shù)據(jù)長度為1471, 1472, 1473和1474字節(jié)運行sock程序。最后兩次應(yīng)該發(fā)生分片:
bsdi % sock -u -i -nl -w1471 svr4 discard
bsdi % sock -u -i -nl -w1472 svr4 discard
bsdi % sock -u -i -nl -w1473 svr4 discard
bsdi % sock -u -i -nl -w1474 svr4 discard
相應(yīng)的tcpdump輸出如圖11.7所示。
圖11.7 觀察UDP數(shù)據(jù)報分片
前兩份UDP數(shù)據(jù)報(第1行和第2行)能裝入以太網(wǎng)數(shù)據(jù)幀,沒有被分片。但是對應(yīng)于寫1473字節(jié)的IP數(shù)據(jù)報長度為1501,就必須進行分片(第3行和第4行)。同理,寫1474字節(jié)產(chǎn)生的數(shù)據(jù)報長度為1502,它也需要進行分片(第5行和第6行)。
當IP數(shù)據(jù)報被分片后,tcpdump打印出其他的信息。首先,frag 26304(第3行和第4行)和frag 26313(第5行和第6行)指的是IP首部中標識字段的值。
分片信息中的下一個數(shù)字,即第三行中位于冒號和@號之間的1480,是除IP首部外的片長。兩份數(shù)據(jù)報第一片的長度均為1480:UDP首部占8字節(jié),用戶數(shù)據(jù)占1472字節(jié)。(加上IP首部的20字節(jié)分組長度正好為1500字節(jié)。)第一份數(shù)據(jù)報的第二片(第4行)只包含1字節(jié)數(shù)據(jù)----剩下的用戶數(shù)據(jù)。第二份數(shù)據(jù)報的第二片(第6行)包含剩下的2字節(jié)用戶數(shù)據(jù)。
在分片時,除最后一片外,其他每一片中的數(shù)據(jù)部分(除IP首部外的其余部分)必須是8字節(jié)的整數(shù)倍。在本例中,1480是8的整數(shù)倍。
位于@符號后的數(shù)字是從數(shù)據(jù)報開始處計算的片偏移值。兩份數(shù)據(jù)報第一片的偏移值均為0(第3行和第5行),第二片的偏移值為1480(第4行和第6行)。跟在偏移值后面的加號對應(yīng)于IP首部中3 bit標志字段中的“更多片”比特。設(shè)置這一比特的目的是讓接收端知道在什么時候完成所有的分片組裝。
最后,注意第4行和第6行(不是第一片)省略了協(xié)議名(UDP),源端口號和目的端口號。協(xié)議名是可以打印出來的,因為它在IP首部并被復(fù)制到各個片中。但是,端口號在UDP首部,只能在第一片中被發(fā)現(xiàn)。
發(fā)送的第三份數(shù)據(jù)報(用戶數(shù)據(jù)為1473字節(jié))分片情況如圖11.8所示。需要重申的是,任何運輸層首部只出現(xiàn)在第一片數(shù)據(jù)中。
另外需要解釋幾個術(shù)語:IP數(shù)據(jù)報是指IP層端到端的傳輸單元(在分片之前和重新組裝之后),分組是指在IP層和鏈路層之間傳送的數(shù)據(jù)單元。一個分組可以是一個完整的IP數(shù)據(jù)報,也可以是IP數(shù)據(jù)報的一個分片。
圖11.8 UDP分片例子
11.6 ICMP不可到達差錯(需要分片)
發(fā)生ICMP不可到達差錯的另一種情況是,當路由器收到一份需要分片的數(shù)據(jù)報,而在IP首部又設(shè)置了不分片(DF)的標志比特。如果某個程序需要判斷到達目的端的路途中最小MTU是多少——稱作路徑MTU發(fā)現(xiàn)機制(2.9節(jié)),那么這個差錯就可以被該程序使用。
這種情況下的ICMP不可到達差錯報報文格式如圖11.9。這里的格式與圖6.10不同,因為在第二個32 bit字中,16-31 bit可以提供下一站的MTU,而不再是0。
圖11.9 需要分片但又設(shè)置不分片標志比特時的ICMP不可到達差錯報文格式
如果路由器沒有提供這種新的ICMP差錯報文格式,那么下一站的MTU就設(shè)為0。
(下面是原書p.151①的譯文)
新版的路由器需求RFC [Almquist 1993]聲明,在發(fā)生這種ICMP不可到達差錯時,路由器必須生成這種新格式的報文。
例子
關(guān)于分片作者曾經(jīng)遇到一個問題,ICMP差錯試圖判斷從路由器netb到主機sun之間的拔號SLIP鏈路的MTU。我們知道從sun到netb的鏈路的MTU:當SLIP被安裝到主機sun時,這是SLIP配置過程中的一部分,加上我們在3.9節(jié)中已經(jīng)通過netstat命令觀察過,F(xiàn)在,我們想從另一個方向來判斷它的MTU。(在第25章,我們將討論如何用SNMP來判斷。)在點到點的鏈路中,不要求兩個方向的MTU為相同值。
所采用的技術(shù)是在主機solaris上運行ping程序到主機bsdi,增加數(shù)據(jù)分組長度,直到看見進入的分組被分片為止。如圖11.10所示。
圖11.10 用來判斷從netb到sun的SLIP鏈路MTU的系統(tǒng)
在主機sun上運行tcpdump觀察SLIP鏈路,看什么時候發(fā)生分片。開始沒有觀察到分片,一切都很正常直到ping分組的數(shù)據(jù)長度從500增加到600字節(jié)。可以看到接收到的回顯請求(仍然沒有分片),但不見回顯回答。
為了跟蹤下去,也在主機bsdi上運行tcpdump,觀察它接收和發(fā)送的報文。輸出如圖11.11所示。
圖11.11 當IP數(shù)據(jù)報長度為600字節(jié)從solaris主機ping到bsdi主機時的tcpdump輸出
首先,每行中的標記(DF)說明在IP首部中設(shè)置了不分片比特。這意味著Solaris 2.2 一般把不分片比特置1,作為實現(xiàn)路徑MTU發(fā)現(xiàn)機制的一部分。
第1行顯示的是回顯請求通過路由器netb到達sun主機,沒有進行分片,并設(shè)置了DF比特,因此我們知道還沒有達到netb的SLIP MTU。
接下來,在第2行注意DF標志被復(fù)制到回顯回答報文中。這就帶來了問題。回顯回答與回顯請求報文長度相同(超過600字節(jié)),但是sun外出的SLIP接口MTU為552。因此回顯回答需要進行分片,但是DF標志比特又被設(shè)置了。這樣,sun就產(chǎn)生一個ICMP不可到達差錯報文返回給bsdi(報文在bsdi處被丟棄)。
這就是我們在主機solaris上沒有看到任何回顯回答的原因。這些回答永遠不能通過sun。分組的路徑如圖11.12所示。
圖11.12 例子中的分組交換
最后,在圖11.11中的第3行和第6行中,mtu=0表示主機sun沒有在ICMP不可到達報文中返回出口MTU值,如圖11.9所示。(在25.9節(jié)中,我們將重新回到這個問題,用SNMP判斷netb上的SLIP接口MTU值為1500。)
11.7 用Traceroute確定路徑MTU
盡管大多數(shù)的系統(tǒng)不支持路徑MTU發(fā)現(xiàn)功能,我們可以很容易地修改traceroute程序(第8章),用它來確定路徑MTU。我們要做的是發(fā)送分組,并設(shè)置“不分片”標志比特。我們發(fā)送的第一個分組的長度正好與出口MTU相等,每次收到ICMP“不能分片”差錯時(我們在上一節(jié)討論的)我們減小分組的長度。如果路由器發(fā)送的ICMP差錯報文是新格式,包含出口的MTU,那么我們就用該MTU值來發(fā)送,否則就用下一個最小的MTU值來發(fā)送。正如RFC 1191 [Mogul and Deering 1990]聲明的那樣,MTU值的個數(shù)是有限的,因此在我們的程序中有一些由近似值構(gòu)成的表,取下一個最小MTU值來發(fā)送。
首先,我們嘗試判斷從主機sun到主機slip的路徑MTU,知道SLIP鏈路的MTU為296。
(見原書p.154的①)
在這個例子中,路由器bsdi沒有在ICMP差錯報文中返回出口MTU,因此我們選擇另一個MTU近似值。TTL為2的第1行輸出打印的主機名為bsdi,但這是因為它是返回ICMP差錯報文的路由器。TTL為2的最后一行正是我們所要找的。
在bsdi上修改ICMP代碼使它返回出口MTU值并不困難,如果我們那樣做并再次運行該程序,得到如下輸出結(jié)果:
(見原書p.154的②)
這時,在找到正確的MTU值之前我們不用逐個嘗試8個不同的MTU值——路由器返回了正確的MTU值。
全球互連網(wǎng)
作為一個實驗,我們多次運行修改以后的traceroute程序,目的端為世界各地的主機?梢缘竭_十五個國家(包括南極洲),使用了多個跨大西洋和跨太平洋的鏈路。但是,在這樣做之前,作者所在子網(wǎng)與路由器netb之間的拔號SLIP鏈路MTU(圖11.12)增加到1500,與以太網(wǎng)相同。
在18次運行當中,只有其中2次發(fā)現(xiàn)的路徑MTU小于1500。其中一個跨大西洋的鏈路MTU值為572(其近似值甚至在RFC 1191也沒有被列出),而路由器返回的是新格式的ICMP差錯報文。另外一條鏈路,在日本的兩個路由器之間,不能處理1500字節(jié)的數(shù)據(jù)幀,并且路由器沒有返回新格式的ICMP差錯報文。把MTU值設(shè)成1006則可以正常工作。
從這個實驗我們可以得出結(jié)論,現(xiàn)在許多但不是所有的廣域網(wǎng)都可以處理大于512字節(jié)的分組。利用路徑MTU發(fā)現(xiàn)機制,應(yīng)用程序就可以充分利用更大的MTU來發(fā)送報文。
11.8 采用UDP的路徑MTU發(fā)現(xiàn)
下面讓我們對使用UDP的應(yīng)用程序與路徑MTU發(fā)現(xiàn)機制之間的交互作用進行研究。我們看一看如果應(yīng)用程序?qū)懥艘粋對于一些中間鏈路來說太長的數(shù)據(jù)報時會發(fā)生什么情況。
例子
由于我們所使用的支持路徑MTU發(fā)現(xiàn)機制的唯一系統(tǒng)就是Solaris 2.x,因此,我們將采用它作為源站發(fā)送一份650字節(jié)數(shù)據(jù)報經(jīng)slip。由于我們的slip主機位于MTU為296的SLIP鏈路后,因此,任何長于268字節(jié)(296-20-8)且“不分片”比特置為1的UDP數(shù)據(jù)都會使bsdi路由器產(chǎn)生ICMP“不能分片”差錯報文。圖11.13給出了拓撲結(jié)構(gòu)和MTU。
圖11.13 使用UDP進行路徑MTU發(fā)現(xiàn)的系統(tǒng)
可以用下面的命令行來產(chǎn)生650字節(jié)UDP數(shù)據(jù)報,每兩個UDP數(shù)據(jù)報之間的間隔是5秒:
solaris % sock -u -I -n10 -w650 -p5 slip discard
圖11.14是tcpdump的輸出結(jié)果。在運行這個例子時,將bsdi設(shè)置成在ICMP“不能分片”差錯中,不返回下一跳MTU信息。
在發(fā)送的第一個數(shù)據(jù)報中將DF比特置1(第1行),其結(jié)果是從bsdi路由器發(fā)回的我們可以猜測的結(jié)果(第2行)。令不不解的是,發(fā)送一個DF比特置1的數(shù)據(jù)報(第3行),其結(jié)果是同樣的ICMP差錯(第4行)。我們預(yù)計這個數(shù)據(jù)報在發(fā)送時應(yīng)該將DF比特置0。
第5行結(jié)果顯示,IP已經(jīng)知道了發(fā)往該目的地址的數(shù)據(jù)報不能將DF比特置1,因此,IP進而將數(shù)據(jù)報在源站主機上進行分片。這與前面的例子中,IP發(fā)送經(jīng)過UDP的數(shù)據(jù)報,允許具有較小MTU的路由器(在本例中是bsdi)對它進行分片的情況不一樣。由于ICMP“不能分片”報文并沒有指出下一跳的MTU,因此看來IP猜測MTU為576就行了。第一次分片(第5行)包含544字節(jié)的UDP數(shù)據(jù),8字節(jié)UDP首部以及20字節(jié)IP首部,因此,總IP數(shù)據(jù)報長度是572字節(jié)。第2次分片(第6行)包含剩余的106字節(jié)UDP數(shù)據(jù)和20字節(jié)IP首部。
圖11.14 使用UDP路徑MTU發(fā)現(xiàn)
不幸的是,第7行的下一個數(shù)據(jù)報將其DF比特置1,因此bsdi將它丟棄并返回ICMP差錯。這時發(fā)生了IP定時器超時,通知IP查看是不是因為路徑MTU增大了而將DF比特再一次置1。我們可以從第19行和20行看出這個結(jié)果。將第7行與19行進行比較,看來IP每過30秒就將DF比特置1,以查看路徑MTU是否增大了。
(下面是原書p.156①的譯文)
這個30秒的定時器值看來太短。RFC 1191建議其值取10分鐘?梢酝ㄟ^修改ip_ire_pathmtu_interval(E.4節(jié))參數(shù)來改變該值。同時,Solaris 2.2無法對單個UDP應(yīng)用或所有UDP應(yīng)用關(guān)閉該路徑MTU發(fā)現(xiàn)。只能通過修改ip_path_mtu_discovery參數(shù),在系統(tǒng)一級上開放或關(guān)閉它。正如我們在這個例子里所能看到的那樣,如果允許路徑MTU發(fā)現(xiàn),那么當UDP應(yīng)用程序?qū)懭肟赡鼙环制瑪?shù)據(jù)報時,該數(shù)據(jù)報將被丟棄。
solaris的IP層所假設(shè)的最大數(shù)據(jù)報長度(576字節(jié))是不正確的。在圖11.13中,我們看到,實際的MTU值是296字節(jié)。這意味著經(jīng)solaris分片的數(shù)據(jù)報還將被bsdi分片。圖11.15給出了在目的主機(slip)上所收集到的tcpdump對于第一個到達數(shù)據(jù)報的輸出結(jié)果(圖11.14的第5行和第6行)。
圖11.15 從solaris到達slip的第一個數(shù)據(jù)報
在本例中,solaris不應(yīng)該對外出數(shù)據(jù)報分片,它應(yīng)該將DF比特置0,讓具有最小MTU的路由器來完成分片工作。
現(xiàn)在我們運行同一個例子,只是對路由器bsdi進行修改使其在ICMP“不能分片”差錯中返回下一跳MTU。圖11.16給出了tcpdump輸出結(jié)果的前6行。
圖11.16 使用UDP的路徑MTU發(fā)現(xiàn)
與圖11.14一樣,前兩個數(shù)據(jù)報同樣是將DF比特置1后發(fā)送出去的。但是在知道了下一跳MTU后,只產(chǎn)生了3個數(shù)據(jù)報片,而圖11.15中的bsdi路由器則產(chǎn)生了4個數(shù)據(jù)報片。
11.9 UDP和ARP之間的交互作用
使用UDP,我們可以看到UDP與ARP典型實現(xiàn)之間的有趣的(而常常未被人提及)交互作用。
我們用sock程序來產(chǎn)生一個包含8192字節(jié)數(shù)據(jù)的UDP數(shù)據(jù)報。我們預(yù)測這將會在以太網(wǎng)上產(chǎn)生6個數(shù)據(jù)報片(見習題11.3)。我們同時也確保在運行該程序前,ARP緩存是清空的,這樣,在發(fā)送第一個數(shù)據(jù)報片前必須交換ARP請求和回答。
bsdi % arp -a驗證ARP高速緩存是空的
bsdi % sock -u -i -nl -w8192 svr4 discard
我們預(yù)計在發(fā)送第一個數(shù)據(jù)報片前會先發(fā)送一個ARP請求。IP還會產(chǎn)生5個數(shù)據(jù)報片,這樣就提出了我們必須用tcpdump來回答的兩個問題:在接收到ARP回答前,其余數(shù)據(jù)報片是否已經(jīng)做好了發(fā)送準備?如果是這樣的話,那么在ARP等待回答時,它會如何處理發(fā)往給定目的的多個報文?圖11.17給出了tcpdump的輸出結(jié)果。
圖11.17 在以太網(wǎng)上發(fā)送8192字節(jié)UDP數(shù)據(jù)報時的報文交換
在這個輸出結(jié)果中有一些令人吃驚的結(jié)果。首先,在第一個ARP回答返回以膠,總共產(chǎn)生了6個ARP請求。我們認為其原因是IP很快地產(chǎn)生了6個數(shù)據(jù)報片,而每個數(shù)據(jù)報片都引發(fā)了一個ARP請求。
第二,在接收到第一個ARP回答時(第7行),只發(fā)送最后一個數(shù)據(jù)報片(第9行)!看來似乎將前5個數(shù)據(jù)報片全都丟棄了。實際上,這是ARP的正常操作。在大多數(shù)的實現(xiàn)中,在等待一個ARP回答時,只將最后一個報文發(fā)送給特定目的主機。
(下面是原書p.158①的譯文)
Host Requirements RFC要求實現(xiàn)中必須防止這種類型的ARP洪泛(ARP flooding,即以高速率重復(fù)發(fā)送到同一個IP地址的ARP請求)。建議最高速率是每秒一次。而這里卻在4.3 ms內(nèi)發(fā)出了6個ARP請求。
Host Requirements RFC規(guī)定,ARP應(yīng)該保留至少一個報文,而這個報文必須是最后一個報文。這正是我們在這里所看到的結(jié)果。
另一個無法解釋的不正常的現(xiàn)象是,svr4發(fā)回7個,而不是6個ARP回答。
最后要指出的是,在最后一個ARP回答返回后,繼續(xù)運行tcpdump程序5分鐘,以看看svr4是否會返回ICMP“組裝超時”差錯。并沒有發(fā)送ICMP差錯。(我們在圖8.2中給出了該消息的格式。code字段為1表示在重新組裝數(shù)據(jù)報時發(fā)生了超時。)
在第一個數(shù)據(jù)報片出現(xiàn)時,IP層必須啟動一個定時器。這里“第一個”表示給定數(shù)據(jù)報的第一個到達數(shù)據(jù)報片,而不是第一個數(shù)據(jù)報片(數(shù)據(jù)報片偏移為0)。正常的定時器值為30或60秒。如果在定時器超時而該數(shù)據(jù)報的所有數(shù)據(jù)報片未能全部到達,那么將這些數(shù)據(jù)報片丟棄。如果不這么做的話,那些永遠不會到達的數(shù)據(jù)報片(正如我們在本例中所看到的那樣)遲早會引起接收端緩存滿。
這里我們沒看到ICMP消息的原因有兩個。首先,大多數(shù)從Berkeley衍生的實現(xiàn)從不產(chǎn)生該差錯!這些實現(xiàn)會設(shè)置定時器,也會在定時器溢出時將數(shù)據(jù)報片丟棄,但是不生成ICMP差錯。第二,并未接收到包含UDP首部的偏移量為0的第一個數(shù)據(jù)報片。(這是被ARP所丟棄的5個報文的第1個。)除非接收到第一個數(shù)據(jù)報片,否則并不要求任何實現(xiàn)產(chǎn)生ICMP差錯。其原因是因為沒有運輸層首部的話,ICMP差錯的接收者無法區(qū)分出是哪個進程所發(fā)送的數(shù)據(jù)報被丟棄。這里假設(shè)上層(TCP或使用UDP的應(yīng)用程序)最終會超時并重傳。
在本節(jié)中,我們使用IP數(shù)據(jù)報片來查看UDP與ARP之間的交互作用。如果發(fā)送端迅速發(fā)送多個UDP數(shù)據(jù)報的話,也可以看到這個交互過程。我們選擇采用分片的方法,是因為IP可以生成報文的速度,比一個用戶進程生成多個數(shù)據(jù)報的速度更快。
盡管本例看來不太可能,但它確實經(jīng)常發(fā)生。NFS發(fā)送的UDP數(shù)據(jù)報長度超過8192字節(jié)。在以太網(wǎng)上,這些數(shù)據(jù)報以我們所指出的方式進行分片,如果適當?shù)腁RP緩存入口發(fā)生超時,那么你就可以看到我們這里所顯示的現(xiàn)象。NFS將超時并重傳,但是由于ARP的有限隊列,第一個IP數(shù)據(jù)報仍可能被丟棄。
11.10 最大UDP數(shù)據(jù)報長度
理論上,IP數(shù)據(jù)報的最大長度是65535字節(jié),這是由IP首部(圖3.1節(jié))16比特總長度字段所限制的。去除20字節(jié)的IP首部和8個字節(jié)的UDP首部,UDP數(shù)據(jù)報中用戶數(shù)據(jù)的最長長度為65507字節(jié)。但是,大多數(shù)實現(xiàn)所提供的長度比這個最大值小。
我們將遇到兩個限制因素。第一,應(yīng)用程序可能會受到其程序接口的限制。socket API提供了一個可供應(yīng)用程序調(diào)用的函數(shù),以設(shè)置接收和發(fā)送緩存的長度。對于UDP socket,這個長度與應(yīng)用程序可以讀寫的最大UDP數(shù)據(jù)報的長度直接相關(guān)的,F(xiàn)在的大部分系統(tǒng)都默認提供了可讀寫大于8192字節(jié)的UDP數(shù)據(jù)報。(使用這個默認值是因為8192是NFS讀寫用戶數(shù)據(jù)數(shù)的默認值。)
第二個限制來自于TCP/IP的內(nèi)核實現(xiàn)?赡艽嬖谝恍⿲崿F(xiàn)特性(或差錯),使IP數(shù)據(jù)報長度小于65535字節(jié)。
(下面是原書p.159①的譯文)
作者使用sock程序?qū)Σ煌琔DP數(shù)據(jù)報長度進行了試驗。在SunOS 1.1.3下使用環(huán)回接口的最大IP數(shù)據(jù)報長度是32767字節(jié)。比它大的值都會發(fā)生差錯。但是從BSD/386到SunOS 4.1.3的情況下,Sun所能接收到最大IP數(shù)據(jù)報長度為32786字節(jié)(即32758字節(jié)用戶數(shù)據(jù))。在Solaris 2.2下使用環(huán)回接口,最大可收發(fā)IP數(shù)據(jù)報長度為65535字節(jié)。從Solaris 2.2到AIX 3.2.2發(fā)送的最大IP數(shù)據(jù)報長度可以是65535字節(jié)。很顯然,這個限制與源端和目的端的實現(xiàn)有關(guān)。
我們在3.2節(jié)中提過,要求主機必須能夠接收最短為576字節(jié)的IP數(shù)據(jù)報。在許多UDP應(yīng)用程序的設(shè)計中,其應(yīng)用程序數(shù)據(jù)被限制成512字節(jié)或更小,因此比這個限制值小。例如,我們在10.4節(jié)中看到,路徑信息協(xié)議總是發(fā)送每份數(shù)據(jù)報小于512字節(jié)的數(shù)據(jù)。我們還會在其它UDP應(yīng)用程序如DNS(第14章),TFTP(第15章),BOOTP(第16章)以及SNMP(第25章)遇到這個限制。
數(shù)據(jù)報截斷
由于IP能夠發(fā)送或接收特定長度的數(shù)據(jù)報并不意味著接收應(yīng)用程序可以讀取該長度的數(shù)據(jù)。因此,UDP編程接口允許應(yīng)用程序指定每次返回的最大字節(jié)數(shù)。如果接收到的數(shù)據(jù)報長度大于應(yīng)用程序所能處理的長度,那么會發(fā)生什么情況呢?
不幸的是,該問題的答案取決于編程接口和實現(xiàn)。
(下面是原書p.160①的譯文)
典型的Berkeley版socket API對數(shù)據(jù)報進行截斷,并丟棄任何多余的數(shù)據(jù)。應(yīng)用程序何時能夠知道則與版本有關(guān)。(4.3BSD Reno及其后的版本可以通知應(yīng)用程序數(shù)據(jù)報被截斷。)
SVR4下的socket API(包括Solaris 2.x) 并不截斷數(shù)據(jù)報。超出部分數(shù)據(jù)在后面的讀取中返回。它也不通知應(yīng)用程序從單個UDP數(shù)據(jù)報中多次進行讀取操作。
TLI API不丟棄數(shù)據(jù)。相反地,它返回一個標志表明可以獲得更多的數(shù)據(jù),而應(yīng)用程序后面的讀操作將返回數(shù)據(jù)報的其余部分。
在我們討論TCP時,我們發(fā)現(xiàn)它為應(yīng)用程序提供連續(xù)的字節(jié)流,而沒有任何信息邊界。TCP以應(yīng)用程序讀操作時所要求的長度來傳送數(shù)據(jù),因此,在這個接口下,不會發(fā)生數(shù)據(jù)丟失。
11.11 ICMP源站抑制差錯
我們同樣也可以使用UDP產(chǎn)生ICMP“源站抑制(source quench)”差錯。當一個系統(tǒng)(路由器或主機)接收數(shù)據(jù)報的速度比其處理速度快時,可能產(chǎn)生這個差錯。注意限定詞“可能”。即使一個系統(tǒng)已經(jīng)沒有緩存并丟棄數(shù)據(jù)報,也不要求它一定要發(fā)送源站抑制報文。
圖11.18給出了ICMP源站抑制差錯報文的格式。我們有一個很好的方案可以在我們的測試網(wǎng)絡(luò)里產(chǎn)生該差錯報文。我們可以從bsdi通過必須經(jīng)過撥號SLIP鏈路的以太網(wǎng),將數(shù)據(jù)報發(fā)送給路由器sun。由于SLIP鏈路的速度大約只有以太網(wǎng)的千分之一,因此,我們很容易就可以使其緩存用完。下面的命令行從主機bsdi通過路由器sun發(fā)送100個1024字節(jié)長數(shù)據(jù)報給solaris。我們將數(shù)據(jù)報發(fā)送給標準的丟棄服務(wù),這樣,這些數(shù)據(jù)報將被忽略:
bsdi % sock -u -I -w1024 -n100 solaris discard
圖11.18 ICMP源站抑制差錯報文格式
圖11.19給出了與此命令行相對應(yīng)的tcpdump輸出結(jié)果
圖11.19 來自路由器sun的ICMP源站抑制
在這個輸出結(jié)果中,我們刪除了很多行,這只是一個模型。接收前26個數(shù)據(jù)報時未發(fā)生差錯;我們只給出了第一個數(shù)據(jù)報的結(jié)果。然而,從我們的第27個數(shù)據(jù)報開始,我們每發(fā)送一份數(shù)據(jù)報,就會接收到一份源站抑制差錯報文。總共有26 +(74×2)=174行輸出結(jié)果。
從我們2.10節(jié)的并行線吞吐率計算結(jié)果可以知道,以9600 b/s速率傳送1024字節(jié)數(shù)據(jù)報只需要1秒時間。(由于從sun到netb的SLIP鏈路的MTU為552字節(jié),因此在我們的例子中,20 + 8 + 1024字節(jié)數(shù)據(jù)報將進行分片,因此,其時間會稍長一些。)但是我們可以從圖11.19的時間中看出,sun路由器在不到1秒時間內(nèi)就處理完所有的100個數(shù)據(jù)報,而這時,第一份數(shù)據(jù)報還未通過SLIP鏈路。因此我們用完其緩存就不足不奇了。
(下面是原書p.161①的譯文)
盡管RFC 1009 [Braden and Postel 1987] 要求路由器在沒有緩存時產(chǎn)生源站抑制差錯報文,但是新的Router Requirements RFC [Almquist 1993] 對此作了修改,提出路由器不應(yīng)該產(chǎn)生源站抑制差錯報文。由于源站抑制要消耗網(wǎng)絡(luò)帶寬且對于擁塞來說是一種無效而不公平的調(diào)整,因此現(xiàn)在人們對于源站抑制差錯的態(tài)度是不支持的。
在本例中,還需要指出的是,我們的sock程序要么沒有接收到源站抑制差錯報文,或者接收到卻將它們忽略了。結(jié)果是如果采用UDP協(xié)議,那么BSD實現(xiàn)通常忽略其接收到的源站抑制報文。(正如我們在21.10節(jié)所討論的那樣,TCP接受源站抑制差錯報文,并將放慢在該連接上的數(shù)據(jù)傳輸速度。)其部分原因在于,在接收到源站抑制差錯報文時,導(dǎo)致源站抑制的進程可能已經(jīng)中止了。實際上,如果我們使用Unix 的time程序來測定我們的sock程序所運行的時間,其結(jié)果是它只運行了大約0.5秒時間。但是從圖11.19中我們可以看到,在發(fā)送第一份數(shù)據(jù)報過后0.71秒才接收到一些源站抑制,而此時該進程已經(jīng)中止。其原因是我們的程序?qū)懭肓?00個數(shù)據(jù)報然后中止了。但是所有的100個數(shù)據(jù)報都已發(fā)送出去——有一些數(shù)據(jù)報在輸出隊列中。
這個例子重申了UDP是一個非可靠的協(xié)議,它說明了端到端的流量控制。盡管我們的sock程序成功地將100個數(shù)據(jù)報寫入其網(wǎng)絡(luò),只有26個數(shù)據(jù)報真正發(fā)送到了目的端。其它74個數(shù)據(jù)報可能被中間路由器所丟棄。除非我們在應(yīng)用程序中建立一些回答機制,否則發(fā)送端并不知道接收端是否收到了這些數(shù)據(jù)。
11.12 UDP服務(wù)器的設(shè)計
使用UDP的一些蘊含對于設(shè)計和實現(xiàn)服務(wù)器產(chǎn)生影響。通常,客戶端的設(shè)計和實現(xiàn)比服務(wù)器端的要容易一些,這就是我們?yōu)槭裁匆懻摲⻊?wù)器的設(shè)計,而不是討論客戶端的設(shè)計的原因。典型的服務(wù)器與操作系統(tǒng)進行交互作用,而且大多數(shù)需要同時處理多個客戶。
通常一個客戶啟動后直接與單個服務(wù)器通信,然后就結(jié)束了。而對于服務(wù)器來說,它啟動后處于休眠狀態(tài),等待客戶請求的到來。對于UDP來說,當客戶數(shù)據(jù)報到達時,服務(wù)器蘇醒過來,數(shù)據(jù)報中可能包含來自客戶的某種形式的請求消息。
在這里我們所感興趣的并不是客戶和服務(wù)器的編程方面([Stevens 1990]對這些方面的細節(jié)進行了討論),而是UDP那些影響使用該協(xié)議的服務(wù)器的設(shè)計和實現(xiàn)方面的協(xié)議特性。(我們在 18.11節(jié)中對TCP服務(wù)器的設(shè)計進行了描述。)盡管我們所描述的一些特性取決于所使用UDP的實現(xiàn),但對于大多數(shù)實現(xiàn)來說,這些特性是公共的。
客戶IP地址及端口號
來自客戶的是UDP數(shù)據(jù)報。IP首部包含源端和目的端IP地址,UDP首部包含了源端和目的端的UDP端口號。當一個應(yīng)用程序接收到UDP數(shù)據(jù)報時,操作系統(tǒng)必須告訴它是誰發(fā)送了這份消息,即源IP地址和端口號。
這個特性允許一個交互UDP服務(wù)器對多個客戶進行處理。給每個發(fā)送請求的客戶發(fā)回回答。
目的IP地址
一些應(yīng)用程序需要知道數(shù)據(jù)報是發(fā)送給誰的,即目的IP地址。例如,Host Requirements RFC規(guī)定,TFTP服務(wù)器必須忽略接收到的發(fā)往廣播地址的數(shù)據(jù)報。(我們分別在第12章和第15章對廣播和TFTP進行描述。)
這要求操作系統(tǒng)從接收到的UDP數(shù)據(jù)報中將目的IP地址交給應(yīng)用程序。不幸的是,并非所有的實現(xiàn)都提供這個功能。
(下面是原書p.163①的譯文)
socket API以IP_RECVDSTADDR socket選項提供了這個功能。對于本文中使用的系統(tǒng),只有BSD/386,4.4BSD和AIX 3.2.2支持該選項。SVR4,SunOS 4.x和Solaris 2.x都不支持該選項。
UDP輸入隊列
我們在1.8節(jié)中說過,大多數(shù)UDP服務(wù)器是交互服務(wù)器。這意味著,單個服務(wù)器進程對單個UDP端口上(服務(wù)器上的名知端口)的所有客戶請求進行處理。
通常程序所使用的每個UDP端口都與一個有限大小的輸入隊列相聯(lián)系。這意味著,來自不同客戶的差不多同時到達的請求將由UDP自動排隊。接收到的UDP數(shù)據(jù)報以其接收順序交給應(yīng)用程序(在應(yīng)用程序要求交送下一個數(shù)據(jù)報時)。
然而,排隊溢出造成內(nèi)核中的UDP模塊丟棄數(shù)據(jù)報的可能性是存在的。我們可以進行以下試驗。我們在作為UDP服務(wù)器的bsdi主機上運行sock程序:
bsdi % sock -s -u -v -E -R256 -P30 6666
from 140.252.13.33, to 140.252.13.63: 1111111111 從sun發(fā)送到廣播地址
from 140.252.13.34, to 140.252.13.35: 4444444444444 從svr4發(fā)送到單目地址
我們指明以下標志:-s表示作為服務(wù)器運行,-u表示UDP,-v表示打印客戶的IP地址,-E表示打印目的IP地址(該系統(tǒng)支持這個功能)。另外,我們將這個端口的UDP接收緩存設(shè)置為256字節(jié)(-R),其每次應(yīng)用程序讀取的大小也是這個數(shù)(-r)。標志 -P30 表示創(chuàng)建UDP端口后,先暫停30秒后再讀取第一個數(shù)據(jù)報。這樣,我們就有時間在另兩臺主機上啟動客戶程序,發(fā)送一些數(shù)據(jù)報,以查看接收隊列是如何工作的。
服務(wù)器一開始工作,處于其30秒的暫停時間內(nèi),我們就在sun主機上啟動一個客戶,并發(fā)送三個數(shù)據(jù)報:
sun % sock -u -v 140.252.13.63 6666 到以太網(wǎng)廣播地址
connected on 140.252.13.33.1252 to 140.252.13.63.6666
1111111111 11字節(jié)的數(shù)據(jù)(新行)
222222222 10字節(jié)的數(shù)據(jù)(新行)
3333333333312字節(jié)的數(shù)據(jù)(新行)
目的地址是廣播地址(140.252.13.63)。我們同時也在主機svr4上啟動第2個客戶,并發(fā)送另外三個數(shù)據(jù)報:
svr4 % sock -u -v bsdi 6666
connected on 0.0.0.0.1042 to 140.252.13.35.6666
4444444444444 14字節(jié)的數(shù)據(jù)(新行)
555555555555555 16字節(jié)的數(shù)據(jù)(新行)
66666666 9字節(jié)的數(shù)據(jù)(新行)
首先,我們早些時候在bsdi上所看到的結(jié)果表明,應(yīng)用程序只接收到2個數(shù)據(jù)報:來自sun的第一個全1報文,和來自svr4的第一個全4報文。其它4個數(shù)據(jù)報看來全被丟棄。
圖11.20給出的tcpdump輸出結(jié)果表明,所有6個數(shù)據(jù)報都發(fā)送給了目的主機。兩個客戶的數(shù)據(jù)報以交替順序鍵入:第一個來自sun,然后是來自svr4的,以此類推。我們同時也可以看出,全部6個數(shù)據(jù)報大約在12秒內(nèi)發(fā)送完畢,也就是在服務(wù)器休眠的30秒內(nèi)完成的。
圖11.20 兩個客戶發(fā)送UDP數(shù)據(jù)報的tcpdump輸出結(jié)果
我們還可以看到,服務(wù)器的-E選項使其可以知道每個數(shù)據(jù)報的目的IP地址。如果需要的話,它可以選擇如何處理其接收到的第一個數(shù)據(jù)報,這個數(shù)據(jù)報的地址是廣播地址。
我們可以從本例中看到以下幾個要點。首先,應(yīng)用程序并不知道其輸入隊列何時溢出。只是由UDP對超出數(shù)據(jù)報進行丟棄處理。同時,從tcpdump輸出結(jié)果,我們看到,沒有發(fā)回任何信息告訴客戶其數(shù)據(jù)報被丟棄。這里不存在象ICMP源站抑制這樣發(fā)回發(fā)送端的消息。最后,看來UDP輸出隊列是FIFO(先進先出)的,而我們在11.9節(jié)中所看到的ARP輸入?yún)s是LIFO(后進先出)的。
限制本地IP地址
大多數(shù)UDP服務(wù)器在創(chuàng)建UDP端點時都使其本地IP地址具有通配符(wildcard)的特點。這就表明進入的UDP數(shù)據(jù)報如果其目的地為服務(wù)器端口,那么在任何本地接口均可接收到它。例如,我們以端口號777啟動一個UDP服務(wù)器:
sun % sock -u -s 7777
然后,我們用netstat命令觀察端點的狀態(tài):
sun % netstat -a -n -f inet
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
udp 0 0 *.7777 *.*
這里,我們刪除了許多行,只保留了其中我們感興趣的東西。-a選項表示報告所有網(wǎng)絡(luò)端點的狀態(tài)。-n選項表示以點數(shù)格式打印IP地址而不用DNS把地址轉(zhuǎn)換成名字,打印數(shù)字端口號而不是服務(wù)名稱。-f inet選項表示只報告TCP和UDP端點。
本地地址以*.7777格式打印,星號表示任何本地IP地址。
當服務(wù)器創(chuàng)建端點時,它可以把其中一個主機本地IP地址包括廣播地址指定為端點的本地IP地址。只有當目的IP地址與指定的地址相匹配時,進入的UDP數(shù)據(jù)報才能被送到這個端點。用我們的sock程序,如果我們在端口號之前指定一個IP地址,那么該IP地址就成為該端點的本地IP地址。例如:
sun % sock -u -s 140.252.1.29 7777
就限制服務(wù)器在SLIP接口(140.252.1.29)處接收數(shù)據(jù)報。netstat輸出結(jié)果顯示如下:
Proto Recv-Q Send-Q Local Address Foreign Address (state)
udp 0 0 140.252.1.29.7777 *.*
如果我們試圖在以太網(wǎng)上的主機bsdi以地址140.252.13.35向該服務(wù)器發(fā)送一份數(shù)據(jù)報,那么將返回一個ICMP端口不可到達差錯。服務(wù)器永遠看不到這份數(shù)據(jù)報。這種情形如圖11.21所示。
圖11.21 服務(wù)器本地地址綁定導(dǎo)致拒絕接收UDP數(shù)據(jù)報
有可能在相同的端口上啟動不同的服務(wù)器,每個服務(wù)器具有不同的本地IP地址。但是,一般必須告訴系統(tǒng)應(yīng)用程序重用相同的端口號沒有問題。
(下面是原書p.165①的譯文)
使用sockets API時,必須指定SO_REUSEADDR socket選項。在我們的sock程序中是通過-A選項來完成的。
在我們的主機sun上,我們可以在同一個端口號(8888)上啟動5個不同的服務(wù)器:
(見原書p.165的②)
除了第一個以外,其他的服務(wù)器都必須以-A選項啟動,告訴系統(tǒng)可以重用同一個端口號。5個服務(wù)器的netstat輸出結(jié)果如下所示:
(見原書p.165的③)
在這種情況下,到達服務(wù)器的數(shù)據(jù)報中,只有帶星號的本地IP地址其目的地址為140.252.1.255,因為其他4個服務(wù)器占用了其他所有可能的IP地址。
如果存在一個含星號的IP地址,那么就隱含了一種優(yōu)先級關(guān)系。如果為端點指定了特定IP地址,那么在匹配目的地址時始終優(yōu)先匹配該IP地址。只有在匹配不成功時才使用含星號的端點。
限制外部IP地址
在前面所有的netstat結(jié)果輸出中,外部IP地址和外部端口號都顯示為*.* ,其意思是該端點將接受來自任何IP地址和任何端口號的UDP數(shù)據(jù)報。大多數(shù)系統(tǒng)允許UDP端點對外部地址進行限制。
這說明端點將只能接收特定IP地址和端口號的UDP數(shù)據(jù)報。我們的sock程序用-f 選項來指定外部IP地址和端口號:
sun % sock -u -s -f 140.252.13.35.4444 5555
這樣就設(shè)置的外部IP地址140.252.13.35(即主機bsdi)和外部端口號4444 。服務(wù)器的有名端口號為5555。如果我們運行netstat命令,我們發(fā)現(xiàn)本地IP地址也被設(shè)置了,盡管我們沒有指定。
Proto Recv-Q Send-Q Local Address Foreign Address (state)
udp 0 0 140.252.13.33.5555 140.252.13.35.4444
這是在伯克利派生系統(tǒng)中指定外部IP地址和端口號帶來的副作用:如果在指定外部地址時沒有選擇本地地址,那么將自動選擇本地址址。它的值就成為選擇到達外部IP地址路由時將選擇的接口IP地址。事實上,在這個例子中,sun在以太網(wǎng)上的IP地址與外部地址140.252.13.33相連。
圖11.22總結(jié)了UDP服務(wù)器本身可以創(chuàng)建的三類地址綁定。
(以下是圖11.22中的部分譯文)
本地地址
外部地址
描述
localIP.lport
foreignIP.fport
只限于一個客戶
localIP.lport
*.*
限于到達一個本地接口的數(shù)據(jù)報:localIP
*.lport
*.*
接收發(fā)送到lport的所有數(shù)據(jù)報
圖11.22 為UDP服務(wù)器指定本地和外部IP地址及端口號
在所有情況下,lport指的是服務(wù)器有名端口號,localIP必須是本地接口的IP地址。表中這三行的排序是UDP模塊在判斷用哪個端點接收數(shù)據(jù)報時所采用的順序。最為確定的地址(第一行)首先被匹配,最不確定的地址(最后一行IP地址帶有兩個星號)最后進行匹配。
每個端口有多個接收者
盡管在RFC中沒有指明,但大多數(shù)的系統(tǒng)在某一時刻只允許一個程序端點與某個本地IP地址及UDP端口號相關(guān)聯(lián)。當目的地為該IP地址及端口號的UDP數(shù)據(jù)報到達主機時,就復(fù)制一份傳給該端點。端點的IP地址可以含星號,正如我們前面討論的那樣。
例如,在SunOS 4.1.3中,我們啟動一個端口號為9999的服務(wù)器,本地IP地址含有星號:
sun % sock -u -s 9999
接著,如果我們啟動另一個具有相同本地地址和端口號的服務(wù)器,那么它將不運行,盡管我們指定了-A選項:
sun % sock -u -s 9999 我們預(yù)計它會失敗
can't bind local address: Address already in use
sun % sock -u -s -A 9999 因此這次嘗試-A參數(shù)
can't bind local address: Address already in use
在一個支持多播的系統(tǒng)上(第12章),這種情況將發(fā)生變化。多個端點可以使用同一個IP地址和UDP端口號,盡管應(yīng)用程序通常必須告訴API是可行的(如,用我們的-A標志來指明SO_REUSEADDR socket選項)。
(下面是原書p.167①的譯文)
4.4BSD支持多目傳送,需要應(yīng)用程序設(shè)置一個不同的socket選項(SO_REUSEPORT)以允許多個端點共享同一個端口。另外,每個端點必須指定這個選項,包括使用該端口的第一個端點。
當UDP數(shù)據(jù)報到達的目的IP地址為廣播地址或多播地址,而且在目的IP地址和端口號處有多個端點,那么就向每個端點傳送一份數(shù)據(jù)報復(fù)制。(端點的本地IP地址可以含有星號,它可匹配任何目的IP地址。)但是,如果UDP數(shù)據(jù)報到達的是一個單目地址,那么只向其中一個端點傳送一份數(shù)據(jù)報復(fù)制。選擇哪個端點傳送數(shù)據(jù)取決于各個不同的系統(tǒng)實現(xiàn)。
11.13 小結(jié)
UDP是一個簡單協(xié)議。它的正式規(guī)約是RFC 768 [Postel 1980],只包含三頁內(nèi)容。它向用戶進程提供的服務(wù)位于IP層之上,包括端口號和可選的檢驗和。我們用UDP來檢查檢驗和,并觀察分片是如何進行的。
接著,我們的討論了ICMP不可到達差錯,它是新的路徑MTU發(fā)現(xiàn)功能中的一部分(2.9節(jié))。我們用Traceroute和UDP來觀察路徑MTU發(fā)現(xiàn)過程。我們還查看了UDP和ARP之間的接口,大多數(shù)的ARP實現(xiàn)在等待ARP回答時只保留最近傳送給目的端的數(shù)據(jù)報。
當系統(tǒng)接收IP數(shù)據(jù)報的速率超過這些數(shù)據(jù)報被處理的速率時,系統(tǒng)可能發(fā)送ICMP源站抑制差錯報文。使用UDP時很容易產(chǎn)生這樣的ICMP差錯。
習題
11.1 在11.5節(jié)中,我們向UDP數(shù)據(jù)報中寫入1473字節(jié)用戶數(shù)據(jù)時導(dǎo)致以太網(wǎng)數(shù)據(jù)報片的發(fā)生。在采用以太網(wǎng)IEEE802封裝格式時,導(dǎo)致分片的最小用戶數(shù)據(jù)長度為多少?
11.2 閱讀RFC 791[Postel 1981a],理解為什么除最后一片外,其他片中的數(shù)據(jù)長度均要求為8字節(jié)整數(shù)倍?
11.3 假定有一個以太網(wǎng)和一份8192字節(jié)的UDP數(shù)據(jù)報,那么需要分成多少個數(shù)據(jù)報片,每個數(shù)據(jù)報片的偏移和長度為多少?
11.4 繼續(xù)前一習題,假定這些數(shù)據(jù)報片要經(jīng)過一條MTU為552的SLIP鏈路。必須記住每一個數(shù)據(jù)報片中的數(shù)據(jù)(除IP首部外)為8字節(jié)整數(shù)倍。那么又將分成多少個數(shù)據(jù)報片,每個數(shù)據(jù)報片的偏移和長度為多少?
11.5 一個用UDP發(fā)送數(shù)據(jù)報的應(yīng)用程序,它把數(shù)據(jù)報分成4個數(shù)據(jù)報片。假定第1片和第2片到達目的端,而第3片和第4片丟失了。應(yīng)用程序在10秒鐘后超時重發(fā)該UDP數(shù)據(jù)報,并且被分成相同的4片(相同的偏移和長度)。假定這一次接收主機重新組裝的時間為60秒,那么當重發(fā)的第3片和第4片到達目的端時,原先收到的第1片和第2片還沒有被丟棄。接收端能否把這4片數(shù)據(jù)重新組裝成一份IP數(shù)據(jù)報?
11.6 你是如何知道圖11.15中的片實際上與圖11.14中第5行和第6行相對應(yīng)?
11.7 主機gemini開機33天后,netstat程序顯示48,000,000份IP數(shù)據(jù)報中由于首部檢驗和差錯被丟棄129份,在30,000,000個TCP段中由于TCP檢驗和差錯而被丟棄20個。但是,在大約18,000,000份UDP數(shù)據(jù)報中,因為UDP檢驗和差錯而被丟棄的數(shù)據(jù)報一份也沒有。請說明兩個方面的原因。(提示:參見圖11.4 。)
11.8 我們在討論分片時沒有提及任何關(guān)于IP首部中的選項——它們是否也要被復(fù)制到每個數(shù)據(jù)報片中,或者只留在第一個數(shù)據(jù)報片中?我們已經(jīng)討論過下面這些IP選項:記錄路由(7.3節(jié)),時間戳(7.4節(jié)),嚴格和寬松的源站選路(8.5節(jié))。你希望分片如何處理這些選項?對照RFC 791檢查你的答案。
11.9 在圖1.8中,我們說UDP數(shù)據(jù)報是根據(jù)目的UDP端口號進行分配的。這正確的嗎?
11-1
12
廣播和多播
12.1 引言
在第1章中我們提到有三種IP地址:單播地址、廣播地址和多播地址。本章將更詳細地介紹廣播和多播。
廣播和多播僅應(yīng)用于UDP,它們對需將報文同時傳往多個接收者的應(yīng)用來說十分重要。TCP是一個面向連接的協(xié)議,它意味著分別運行于兩主機(由IP地址確定)內(nèi)的兩進程(由端口號確定)間存在一條連接。
考慮包含多個主機的共享信道網(wǎng)絡(luò)如以太網(wǎng)。每個以太網(wǎng)幀包含源主機和目的主機的以太網(wǎng)地址(48 bit)。通常每個以太網(wǎng)幀僅發(fā)往單個目的主機,目的地址指明單個接收接口,因而稱為單播(unicast)。在這種方式下,任意兩個主機的通信不會干擾網(wǎng)內(nèi)其他主機(可能引起爭奪共享信道的情況除外)。
然而,有時一個主機要向網(wǎng)上的其他主機發(fā)送幀,這就是廣播。通過ARP和RARP可以看到這一過程。多播(multicast) 處于單播和廣播之間:幀僅傳送給屬于多播組的多個主機。
為了弄清廣播和多播,需要了解主機對由信道傳送過來幀的過濾過程。圖12.1說明了這一過程。
首先,網(wǎng)卡查看由信道傳送過來的幀,確定是否接收該幀,若接收后就將它傳往設(shè)備驅(qū)動程序。通常網(wǎng)卡僅接收那些目的地址為網(wǎng)卡物理地址或廣播地址的幀。另外,多數(shù)接口均被設(shè)置為混合模式,這種模式能接收每個幀的一個復(fù)制。作為一個例子,tcpdump使用這種模式。
圖12.1 協(xié)議棧各層對收到幀的過濾過程
目前,大多數(shù)的網(wǎng)卡經(jīng)過配置都能接收目的地址為多播地址或某些子網(wǎng)多播地址的幀。對于以太網(wǎng),當?shù)刂分凶罡咦止?jié)的最低位設(shè)置為1時表示該地址是一個多播地址,用十六進制可表示為01:00:00:00:00:00。(以太網(wǎng)廣播地址ff:ff:ff:ff:ff:ff可看作是以太網(wǎng)多播地址的特例。)
如果網(wǎng)卡收到一個幀,這個幀將被傳送給設(shè)備驅(qū)動程序。(如果幀檢驗和錯,網(wǎng)卡將丟棄該幀。)設(shè)備驅(qū)動程序?qū)⑦M行另外的幀過濾。首先,幀類型中必須指定要使用的協(xié)議(IP,ARP等等)。其次,進行多播過濾來檢測該主機是否屬于多播地址說明的多播組。
設(shè)備驅(qū)動程序隨后將數(shù)據(jù)幀傳送給下一層,比如,當幀類型指定為IP數(shù)據(jù)報時,就傳往IP層。IP根據(jù)IP地址中的源地址和目的地址進行更多的過慮檢測,如果正常,將數(shù)據(jù)報傳送給下一層(如TCP或UDP)。
每次UDP收到由IP傳送來的數(shù)據(jù)報,就根據(jù)目的端口號,有時還有源端口號進行數(shù)據(jù)報過濾。如果當前沒有進程使用該目的端口號,就丟棄該數(shù)據(jù)報并產(chǎn)生一個ICMP不可達報文。(TCP根據(jù)它的端口號作相似的過慮。)如果UDP數(shù)據(jù)報存在檢驗和錯,將被丟棄。
使用廣播的問題在于它增加了對廣播數(shù)據(jù)不感興趣主機的處理負荷。拿一個使用UDP廣播應(yīng)用作為例子,如果網(wǎng)內(nèi)有50個主機,但僅有20個參與該應(yīng)用,每次這20個主機中的一個發(fā)送UDP廣播數(shù)據(jù)時,其余30個主機不得不處理這些廣播數(shù)據(jù)報,而直到UDP層,收到的UDP廣播數(shù)據(jù)報才會被丟棄。這30個主機丟棄UDP廣播數(shù)據(jù)報是因為這些主機沒有使用這個目的端口。
多播的出現(xiàn)減少了對應(yīng)用不感興趣主機的處理負荷。使用多播,主機可加入一個或多個多播組。這樣,網(wǎng)卡將獲悉該主機屬于哪個多播組,然后僅接收主機所在多播組的那些多播幀。
12.2 廣播
在圖3.9中,我們知道了四種IP廣播地址,下面對它們進行更詳細的介紹。
受限的廣播
受限的廣播地址是255.255.255.255。該地址用于主機配置過程中IP數(shù)據(jù)報中目的地址,此時,主機可能還不知道它所在網(wǎng)絡(luò)的網(wǎng)絡(luò)掩碼,甚至連它的IP地址也不知道。
在任何情況下,路由器都不轉(zhuǎn)發(fā)目的地址為受限的廣播地址的數(shù)據(jù)報,這樣的數(shù)據(jù)報僅出現(xiàn)在本地網(wǎng)絡(luò)中。
一個未解的問題是:如果一個主機是多接口的,當一個進程向本網(wǎng)廣播地址發(fā)送數(shù)據(jù)報時,為實現(xiàn)廣播,是否應(yīng)該將數(shù)據(jù)報發(fā)送到每個相連的接口上?如果不是這樣,想對主機所有接口廣播的應(yīng)用必須確定主機中支持廣播的所有接口,然后向每個接口發(fā)送一個數(shù)據(jù)報復(fù)制。
大多數(shù)BSD系統(tǒng)將255.255.255.255看作是配置后第一個接口的廣播地址,并且不提供向所屬具備廣播能力接口傳送數(shù)據(jù)報的功能。不過,routed(見10.3)和rwhod(BSD rwho客戶的服務(wù)器)是向每個接口發(fā)送UDP數(shù)據(jù)報的兩個應(yīng)用程序。這兩個應(yīng)用程序均有相似的啟動過程來確定主機中的所有接口,并了解哪些接口具備廣播能力。同時,將對應(yīng)于那種接口的指向網(wǎng)絡(luò)的廣播地址作為向該接口發(fā)送的數(shù)據(jù)報的目的地址。
Host Requirements RFC沒有進一步涉及多接口主機是否應(yīng)當向其所有的接口發(fā)送受限的廣播。
指向網(wǎng)絡(luò)的廣播
指向網(wǎng)絡(luò)的廣播地址是主機號字段均為1的地址。A類網(wǎng)絡(luò)廣播地址為netid.255.255.255,其中netid為A類網(wǎng)絡(luò)的網(wǎng)絡(luò)號。
一個路由器必須轉(zhuǎn)發(fā)指向網(wǎng)絡(luò)的廣播,但它也必須有一個不進行轉(zhuǎn)發(fā)的選擇。
指向子網(wǎng)的廣播
指向子網(wǎng)的廣播地址為主機號碼字段均為1且有特定子網(wǎng)號的地址。作為子網(wǎng)直接廣播地址的IP地址需要了解子網(wǎng)的掩碼。例如,如果路由器收到發(fā)往128.1.2.255的數(shù)據(jù)報,當B類網(wǎng)絡(luò)128.1的子網(wǎng)掩碼為255.255.255.0時,該地址就是指向子網(wǎng)的廣播地址;但如果該子網(wǎng)的掩碼為255.255.254.0,該地址就不是指向子網(wǎng)的廣播地址。
指向所有子網(wǎng)的廣播
指向所有子網(wǎng)的廣播也需要了解目的網(wǎng)絡(luò)的子網(wǎng)掩碼,以便與指向網(wǎng)絡(luò)的廣播地址區(qū)分開。指向所有子網(wǎng)的廣播地址的子網(wǎng)號字段及主機號字段均為1。例如,如果目的子網(wǎng)掩碼為255.255.255.0,那么IP地址128.1.255.255是一個指向所有子網(wǎng)的廣播地址。然而,如果網(wǎng)絡(luò)沒有劃分子網(wǎng),這就是一個指向網(wǎng)絡(luò)的廣播。
當前的看法[Almquist 1993]是這種廣播是陳舊過時的,更好的方式是使用多播而不是對所有子網(wǎng)的廣播。
[Almquist 1993] 解釋了RFC 922需要一個向所有子網(wǎng)的廣播來傳送給所有子網(wǎng),但當前的路由器沒有這么做。這很幸運,因為一個已經(jīng)錯誤配置的主機沒有它的主機掩碼會把它的本地廣播傳送到所有子網(wǎng)。例如,如果IP地址為128.1.2.3的主機沒有設(shè)置子網(wǎng)掩碼,它的廣播地址在正常情況下的默認值是128.1.255.255。但如果子網(wǎng)掩碼被設(shè)置為255.255.255.0,那么由錯誤配置的主機發(fā)出的廣播將指向所有的子網(wǎng)。
1983年問世的4.2BSD是第一個影響廣泛的TCP/IP的實現(xiàn),它使用主機號全0作為廣播地址。一個最早有關(guān)廣播IP地址參考是IEN 212 [Gurwitz and Hinden 1982],它提出用主機號中的1比特來表示IP廣播地址。(IENs 是互聯(lián)網(wǎng)試驗注釋,基本上是RFC的前身。)RFC 894 [Hornig 1984]認為4.2BSD使用不標準的廣播地址,但RFC 906 [Finlayson 1984] 注意到對廣播地址還沒有Internet標準。他還在RFC 906加了一個腳注承認缺少標準的廣播地址,并強烈推薦將主機號全1作為廣播地址。盡管1986年的4.3BSD采用主機號全1表示廣播地址,但直到90年代早期操作系統(tǒng)(突出的是SunOS 4.x)還繼續(xù)使用非標準的廣播地址。
12.3 廣播的例子
廣播是怎樣傳送的?路由器及主機又如何處理廣播?很遺憾,這是難于回答的問題,因為它依賴于廣播的類型、應(yīng)用的類型、TCP/IP實現(xiàn)方法以及有關(guān)路由器的配置。
首先,應(yīng)用程序必須支持廣播。如果執(zhí)行
sun % ping 255.255.255.255
/usr/etc/ping: unknown host 255.255.255.255
打算進行在本地電纜上的廣播,但它無法進行,原因在于該應(yīng)用程序(ping)中存在一個程序設(shè)計上的問題。大多數(shù)應(yīng)用程序收到點分十進制的IP地址或主機名后,會調(diào)用函數(shù)inet_addr(3)來把它們轉(zhuǎn)化為32 bit的二進制IP地址。假定要轉(zhuǎn)化的是一個主機名,如果轉(zhuǎn)化失敗,該庫函數(shù)將返回-1來表明存在某種差錯(例如是字符而不是數(shù)字或串中有小數(shù)點),但本網(wǎng)廣播地址(255.255.255.255)也被當作存在差錯而返回-1。大多數(shù)程序均假定接收到的字符串是主機名,然后查找域名系統(tǒng)DNS(第14章),失敗后輸出差錯信息如“未知主機”。
如果我們修復(fù)ping程序中這個欠缺,結(jié)果也并不總是令人滿意的。在6個不同系統(tǒng)的測試中,僅有一個像預(yù)期的那樣產(chǎn)生了一個本網(wǎng)廣播數(shù)據(jù)報。大多數(shù)則在路由表中查找IP地址255.255.255.255,而該地址被用作默認路由器地址,因此向默認路由器單播一個數(shù)據(jù)報。最終該數(shù)據(jù)報被丟棄。
指向子網(wǎng)的廣播是我們應(yīng)該使用的。在6.3節(jié)中,我們向測試網(wǎng)絡(luò)(見封2)中IP地址為 140.252.13.63 的以太網(wǎng)發(fā)送數(shù)據(jù)報,并接收以太網(wǎng)中所有主機的回答。與子網(wǎng)廣播地址關(guān)聯(lián)的每個接口是用于命令ifconfig(見3.8節(jié))的值。如果我們ping那個地址,預(yù)期的結(jié)果是:
(見原書p.173①)
IP通過目的地址(140.252.13.63)來確定這是指向子網(wǎng)的廣播地址,然后向鏈路層的廣播地址發(fā)送該數(shù)據(jù)報。
我們在6.3提及的這種類型廣播的接收對象為包括發(fā)送主機在內(nèi)的局域網(wǎng)中的所有主機,因此可以看到除了收到網(wǎng)內(nèi)其他主機的答復(fù)外,還收到了來自發(fā)送主機(sun)的答復(fù)。
在這個例子中,我們也顯示了 |
|