2.1 引言
從圖1-4中可以看出,在TCP/IP協議族中,鏈路層主要有三個目的:(1)為IP模塊發送和接收IP數據報;(2)為ARP模塊發送ARP請求和接收ARP應答;(3)為RARP發送RARP請求和接收RARP應答。TCP/IP支持多種不同的鏈路層協議,這取決于網絡所使用的硬件,如以太網、令牌環網、FDDI(光纖分布式數據接口)及RS-232串行線路等。
在本章中,我們將詳細討論以太網鏈路層協議,兩個串行接口鏈路層協議(SLIP和PPP),以及大多數實現都包含的環回(loopback)驅動程序。以太網和SLIP是本書中大多數例子使用的鏈路層。對MTU(最大傳輸單元)進行了介紹,這個概念在本書的后面章節中將多次遇到。我們還討論了如何為串行線路選擇MTU。
2.2 以太網和IEEE 802封裝
以太網這個術語一般是指數字設備公司(Digital Equipment Corp.)、英特爾公司(Intel Corp.)和Xerox公司在1982年聯合公布的一個標準。它是當今TCP/IP采用的主要的局域網技術。它采用一種稱作CSMA/CD的媒體接入方法,其意思是帶沖突檢測的載波偵聽多路接入(Carrier Sense, Multiple Access with Collision Detection)。它的速率為10 Mb/s,地址為48 bit。
幾年后,IEEE(電子電氣工程師協會)802委員會公布了一個稍有不同的標準集,其中802.3針對整個CSMA/CD網絡,802.4針對令牌總線網絡,802.5針對令牌環網絡。這三者的共同特性由802.2標準來定義,那就是802網絡共有的邏輯鏈路控制(LLC)。不幸的是,802.2和802.3定義了一個與以太網不同的幀格式。文獻[Stallings 1987]對所有的IEEE 802標準進行了詳細的介紹。
在TCP/IP世界中,以太網IP數據報的封裝是在RFC 894[Hornig 1984]中定義的,IEEE 802網絡的IP數據報封裝是在RFC 1042[Postel and Reynolds 1988]中定義的。主機需求RFC要求每臺Internet主機都與一個10 Mb/s的以太網電纜相連接:
1:必須能發送和接收采用RFC 894(以太網)封裝格式的分組。
2:應該能接收與RFC 894混合的RFC 1042(IEEE 802)封裝格式的分組。
3:也許能夠發送采用RFC 1042格式封裝的分組。如果主機能同時發送兩種類型的分組數據,那么發送的分組必須是可以設置的,而且默認條件下必須是RFC 894分組。
最常使用的封裝格式是RFC 894定義的格式。圖2-1顯示了兩種不同形式的封裝格式。圖中每個方框下面的數字是它們的字節長度。
兩種幀格式都采用48 bit(6字節)的目的地址和源地址(802.3允許使用16 bit的地址,但一般是48 bit地址)。這就是我們在本書中所稱的硬件地址。ARP和RARP協議(第4章和第5章)對32 bit的IP地址和48 bit的硬件地址進行映射。
接下來的2個字節在兩種幀格式中互不相同。在802標準定義的幀格式中,長度字段是指它后續數據的字節長度,但不包括CRC檢驗碼。以太網的類型字段定義了后續數據的類型。在802標準定義的幀格式中,類型字段則由后續的子網接入協議(Sub-network Access Protocol,SNAP)的首部給出。幸運的是,802定義的有效長度值與以太網的有效類型值無一相同,這樣,就可以對兩種幀格式進行區分。
在以太網幀格式中,類型字段之后就是數據;而在802幀格式中,跟隨在后面的是3字節的802.2LLC和5字節的802.2SNAP。目的服務訪問點(Destination Service Access Point, DSAP)和源服務訪問點(Source Service Access Point, SSAP)的值都設為0xaa。Ct rl字段的值設為3。隨后的3個字節org code都置為0。再接下來的2個字節類型字段和以太網幀格式一樣(其他類型字段值可以參見RFC 1340[Reynolds and Postel 1992])。
CRC字段用于幀內后續字節差錯的循環冗余碼檢驗(檢驗和)(它也被稱為FCS或幀檢驗序列)。
802.3標準定義的幀和以太網的幀都有最小長度要求。802.3規定數據部分必須至少為38字節,而對于以太網,則要求最少要有46字節。為了保證這一點,必須在不足的空間插入填充(pad)字節。在開始觀察線路上的分組時將遇到這種最小長度的情況。
在本書中,我們在需要的時候將給出以太網的封裝格式,因為這是最為常見的封裝格式。
2.3 尾部封裝
RFC 893[Leffler and Karels 1984]描述了另一種用于以太網的封裝格式,稱作尾部封裝(trailer encapsulation)。這是一個早期BSD系統在DEC VA X機上運行時的試驗格式,它通過調整IP數據報中字段的次序來提高性能。在以太網數據幀中,開始的那部分是變長的字段(IP首部和TCP首部)。把它們移到尾部(在CRC之前),這樣當把數據復制到內核時,就可以把數據幀中的數據部分映射到一個硬件頁面,節省內存到內存的復制過程。TCP數據報的長度是512字節的整數倍,正好可以用內核中的頁表來處理。兩臺主機通過協商使用ARP擴展協議對數據幀進行尾部封裝。這些數據幀需定義不同的以太網幀類型值。
現在,尾部封裝已遭到反對,因此我們不對它舉任何例子。有興趣的讀者請參閱RFC 893以及文獻[Leffler et al.1989]的11.8節。
2.4 SLIP:串行線路IP
SLIP的全稱是Serial Line IP。它是一種在串行線路上對IP數據報進行封裝的簡單形式,在RFC 1055[Romkey 1988]中有詳細描述。SLIP適用于家庭中每臺計算機幾乎都有的RS-232串行端口和高速調制解調器接入Internet。
下面的規則描述了SLIP協議定義的幀格式:
1:IP數據報以一個稱作END(0xc0)的特殊字符結束。同時,為了防止數據報到來之前的線路噪聲被當成數據報內容,大多數實現在數據報的開始處也傳一個END字符(如果有線路噪聲,那么END字符將結束這份錯誤的報文。這樣當前的報文得以正確地傳輸,而前一個錯誤報文交給上層后,會發現其內容毫無意義而被丟棄)。
2:如果IP報文中某個字符為END,那么就要連續傳輸兩個字節0xdb和0xdc來取代它。0xdb這個特殊字符被稱作SLIP的ESC字符,但是它的值與ASCII碼的ESC字符(0x1b)不同。
3:如果IP報文中某個字符為SLIP的ESC字符,那么就要連續傳輸兩個字節0xdb和0xdd來取代它。
圖2-2中的例子就是含有一個END字符和一個ESC字符的IP報文。在這個例子中,在串行線路上傳輸的總字節數是原IP報文長度再加4個字節。
SLIP是一種簡單的幀封裝方法,還有一些值得一提的缺陷:
1:每一端必須知道對方的IP地址。沒有辦法把本端的IP地址通知給另一端。
2:數據幀中沒有類型字段(類似于以太網中的類型字段)。如果一條串行線路用于SLIP,那么它不能同時使用其他協議。
3:SLIP沒有在數據幀中加上檢驗和(類似于以太網中的CRC字段)。如果SLIP傳輸的報文被線路噪聲影響而發生錯誤,只能通過上層協議來發現(另一種方法是,新型的調制解調器可以檢測并糾正錯誤報文)。這樣,上層協議提供某種形式的CRC就顯得很重要。在第3章和第17章中,我們將看到IP首部和TCP首部及其數據始終都有檢驗和。在第11章中,將看到UDP首部及其數據的檢驗和卻是可選的。
盡管存在這些缺點,SLIP仍然是一種廣泛使用的協議。
SLIP的歷史要追溯到1984年,Rick Adams第一次在4.2BSD系統中實現。盡管它本身的描述是一種非標準的協議,但是隨著調制解調器的速率和可靠性的提高,SLIP越來越流行。現在,它的許多產品可以公開獲得,而且很多廠家都支持這種協議。
2.5 壓縮的SLIP
由于串行線路的速率通常較低(19200 b/s或更低),而且通信經常是交互式的(如Telnet和Rlogin,二者都使用TCP),因此在SLIP線路上有許多小的TCP分組進行交換。為了傳送1個字節的數據需要20個字節的IP首部和20個字節的TCP首部,總數超過40個字節(19.2節描述了Rlogin會話過程中,當敲入一個簡單命令時這些小報文傳輸的詳細情況)。
既然承認這些性能上的缺陷,于是人們提出一個被稱作CSLIP(即壓縮SLIP)的新協議,它在RFC 1144[Jacobson 1990a]中被詳細描述。CSLIP一般能把上面的40個字節壓縮到3或5個字節。它能在CSLIP的每一端維持多達16個TCP連接,并且知道其中每個連接的首部中的某些字段一般不會發生變化。對于那些發生變化的字段,大多數只是一些小的數字和的改變。這些被壓縮的首部大大地縮短了交互響應時間。
現在大多數的SLIP產品都支持CSLIP。作者所在的子網(參見封面內頁)中有兩條SLIP鏈路,它們均是CSLIP鏈路。
2.6 PPP:點對點協議
PPP,點對點協議修改了SLIP協議中的所有缺陷。PPP包括以下三個部分:
1:在串行鏈路上封裝IP數據報的方法。PPP既支持數據為8位和無奇偶檢驗的異步模式(如大多數計算機上都普遍存在的串行接口),還支持面向比特的同步鏈接。
2:建立、配置及測試數據鏈路的鏈路控制協議(LCP:Link Control Protocol)。它允許通信雙方進行協商,以確定不同的選項。
3:針對不同網絡層協議的網絡控制協議(NCP:Network Control Protocol)體系。當前RFC定義的網絡層有IP、OSI網絡層、DECnet以及AppleTalk。例如,IP NCP允許雙方商定是否對報文首部進行壓縮,類似于CSLIP(縮寫詞NCP也可用在TCP的前面)。
RFC 1548[Simpson 1993]描述了報文封裝的方法和鏈路控制協議。RFC 1332[McGregor 1992]描述了針對IP的網絡控制協議。PPP數據幀的格式看上去很像ISO的HDLC(高層數據鏈路控制)標準。圖2-3是PPP數據幀的格式。
每一幀都以標志字符0x7e開始和結束。緊接著是一個地址字節,值始終是0xff,然后是一個值為0x03的控制字節。
接下來是協議字段,類似于以太網中類型字段的功能。當它的值為0x0021時,表示信息字段是一個IP數據報;值為0xc021時,表示信息字段是鏈路控制數據;值為0x8021時,表示信息字段是網絡控制數據。
CRC字段(或FCS,幀檢驗序列)是一個循環冗余檢驗碼,以檢測數據幀中的錯誤。
由于標志字符的值是0x7e,因此當該字符出現在信息字段中時,PPP需要對它進行轉義。在同步鏈路中,該過程是通過一種稱作比特填充(bit stuffing)的硬件技術來完成的[Tanenbaum 1989]。在異步鏈路中,特殊字符0x7d用作轉義字符。當它出現在PPP數據幀中時,那么緊接著的字符的第6個比特要取其補碼,具體實現過程如下:
1:當遇到字符0x7e時,需連續傳送兩個字符:0x7d和0x5e,以實現標志字符的轉義。
2:當遇到轉義字符0x7d時,需連續傳送兩個字符:0x7d和0x5d,以實現轉義字符的轉義。
3:默認情況下,如果字符的值小于0x20(比如,一個ASCII控制字符),一般都要進行轉義。例如,遇到字符0x01時需連續傳送0x7d和0x21兩個字符(這時,第6個比特取補碼后變為1,而前面兩種情況均把它變為0)。
這樣做的原因是防止它們出現在雙方主機的串行接口驅動程序或調制解調器中,因為有時它們會把這些控制字符解釋成特殊的含義。另一種可能是用鏈路控制協議來指定是否需要對這32個字符中的某一些值進行轉義。默認情況下是對所有的32個字符都進行轉義。
與SLIP類似,由于PPP經常用于低速的串行鏈路,因此減少每一幀的字節數可以降低應用程序的交互時延。利用鏈路控制協議,大多數的產品通過協商可以省略標志符和地址字段,并且把協議字段由2個字節減少到1個字節。如果我們把PPP的幀格式與前面的SLIP的幀格式(圖2-2)進行比較會發現,PPP只增加了3個額外的字節:1個字節留給協議字段,另2個給CRC字段使用。另外,使用IP網絡控制協議,大多數的產品可以通過協商采用Van Jacobson報文首部壓縮方法(對應于CSLIP壓縮),減小IP和TCP首部長度。
總的來說,PPP比SLIP具有下面這些優點:(1)PPP支持在單根串行線路上運行多種協議,不只是IP協議;(2)每一幀都有循環冗余檢驗;(3)通信雙方可以進行IP地址的動態協商(使用IP網絡控制協議);(4)與CSLIP類似,對TCP和IP報文首部進行壓縮;(5)鏈路控制協議可以對多個數據鏈路選項進行設置。為這些優點付出的代價是在每一幀的首部增加3個字節,當建立鏈路時要發送幾幀協商數據,以及更為復雜的實現。
盡管PPP比SLIP有更多的優點,但是現在的SLIP用戶仍然比PPP用戶多。隨著產品越來越多,產家也開始逐漸支持PPP,因此最終PPP應該取代SLIP。
2.7 環回接口
大多數的產品都支持環回接口(Loopback Interface),以允許運行在同一臺主機上的客戶程序和服務器程序通過TCP/IP進行通信。A類網絡號127就是為環回接口預留的。根據慣例,大多數系統把IP地址127.0.0.1分配給這個接口,并命名為localhost。一個傳給環回接口的IP數據報不能在任何網絡上出現。
我們想象,一旦傳輸層檢測到目的端地址是環回地址時,應該可以省略部分傳輸層和所有網絡層的邏輯操作。但是大多數的產品還是照樣完成傳輸層和網絡層的所有過程,只是當IP數據報離開網絡層時把它返回給自己。
圖2-4是環回接口處理IP數據報的簡單過程。
圖中需要指出的關鍵點是:
1:傳給環回地址(一般是127.0.0.1)的任何數據均作為IP輸入。
2:傳給廣播地址或多播地址的數據報復制一份傳給環回接口,然后送到以太網上。這是因為廣播傳送和多播傳送的定義(第12章)包含主機本身。
3:任何傳給該主機IP地址的數據均送到環回接口。
看上去用傳輸層和IP層的方法來處理環回數據似乎效率不高,但它簡化了設計,因為環回接口可以被看作是網絡層下面的另一個鏈路層。網絡層把一份數據報傳送給環回接口,就像傳給其他鏈路層一樣,只不過環回接口把它返回到IP的輸入隊列中。
在圖2-4中,另一個隱含的意思是送給主機本身IP地址的IP數據報一般不出現在相應的網絡上。例如,在一個以太網上,分組一般不被傳出去然后讀回來。某些BSD以太網的設備驅動程序的注釋說明,許多以太網接口卡不能讀回它們自己發送出去的數據。由于一臺主機必須處理發送給自己的IP數據報,因此圖2-4所示的過程是最為簡單的處理辦法。
4.4BSD系統定義了變量useloopback,并初始化為1。但是,如果這個變量置為0,以太網驅動程序就會把本地分組送到網絡,而不是送到環回接口上。它也許不能工作,這取決于所使用的以太網接口卡和設備驅動程序。
2.8 最大傳輸單元MTU
正如在圖2-1看到的那樣,以太網和802.3對數據幀的長度都有一個限制,其最大值分別是1500和1492字節。鏈路層的這個特性稱作MTU ,最大傳輸單元。不同類型的網絡大 多數都有一個上限。
如果IP層有一個數據報要傳,而且數據的長度比鏈路層的MTU還大,那么IP層就需要進行分片(fragmentation),把數據報分成若干片,這樣每一片都小于MTU。我們將在11.5節討論IP分片的過程。
圖2-5列出了一些典型的MTU值,它們摘自RFC 1191[Mogul and Deering 1990]。點到點的鏈路層(如SLIP和PPP)的MTU并非指的是網絡媒體的物理特性。相反,它是一個邏輯限制,目的是為交互使用提供足夠快的響應時間。在2.10節中,我們將看到這個限制值是如何計算出來的。
在3.9節中,我們將用netstat命令打印出網絡接口的MTU。
2.9 路徑MTU
當在同一個網絡上的兩臺主機互相進行通信時,該網絡的MTU是非常重要的。但是如果兩臺主機之間的通信要通過多個網絡,那么每個網絡的鏈路層就可能有不同的MTU。重要的不是兩臺主機所在網絡的MTU的值,重要的是兩臺通信主機路徑中的最小MTU。它被稱作路徑MTU。
兩臺主機之間的路徑MTU不一定是個常數。它取決于當時所選擇的路由。而選路不一定是對稱的(從A到B的路由可能與從B到A的路由不同),因此路徑MTU在兩個方向上不一定是一致的。
RFC 1191[Mogul and Deering 1990]描述了路徑MTU的發現機制,即在任何時候確定路徑MTU的方法。我們在介紹了ICMP和IP分片方法以后再來看它是如何操作的。在11.6節中,我們將看到ICMP的不可到達錯誤就采用這種發現方法。在11.7節中,還會看到,traceroute程序也是用這個方法來確定到達目的節點的路徑MTU。在11.8節和24.2節,將介紹當產品支持路徑MTU的發現方法時,UDP和TCP是如何進行操作的。
2.10 串行線路吞吐量計算
如果線路速率是9600 b/s,而一個字節有8bit,加上一個起始比特和一個停止比特,那么線路的速率就是960 B/s(字節/秒)。以這個速率傳輸一個1024字節的分組需要1066 ms。如果用SLIP鏈接運行一個交互式應用程序,同時還運行另一個應用程序如FTP發送或接收1024字節的數據,那么一般來說就必須等待一半的時間(533 ms)才能把交互式應用程序的分組數據發送出去。
假定交互分組數據可以在其他“大塊”分組數據發送之前被發送出去。大多數的SLIP實現確實提供這類服務排隊方法,把交互數據放在大塊的數據前面。交互通信一般有Telnet、Rlogin以及FTP的控制部分(用戶的命令,而不是數據)。
這種服務排隊方法是不完善的。它不能影響已經進入下游(如串行驅動程序)隊列的非交互數據。同時,新型的調制解調器具有很大的緩沖區,因此非交互數據可能已經進入該緩沖區了。
對于交互應用來說,等待533 ms是不能接受的。關于人的有關研究表明,交互響應時間超過100~200 ms就被認為是不好的[Jacobson 1990a]。這是發送一份交互報文出去后,直到接收到響應信息(通常是出現一個回顯字符)為止的往返時間。
把SLIP的MTU縮短到256就意味著鏈路傳輸一幀最長需要266 ms,它的一半是133 ms(這是一般需要等待的時間)。這樣情況會好一些,但仍然不完美。我們選擇它的原因(與64或128相比)是因為大塊數據提供良好的線路利用率(如大文件傳輸)。假設CSLIP的報文首部是5個字節,數據幀總長為261個字節,256個字節的數據使線路的利用率為98.1%,幀頭占了1.9%,這樣的利用率是很不錯的。如果把MTU降到256以下,那么將降低傳輸大塊數據的最大吞吐量。
在圖2-5列出的MTU值中,點對點鏈路的MTU是296個字節。假設數據為256字節,TCP和IP首部占40個字節。由于MTU是IP向鏈路層查詢的結果,因此該值必須包括通常的TCP和IP首部。這樣就會導致IP如何進行分片的決策。IP對于CSLIP的壓縮情況一無所知。
我們對平均等待時間的計算(傳輸最大數據幀所需時間的一半)只適用于SLIP鏈路(或PPP鏈路)在交互通信和大塊數據傳輸這兩種情況下。當只有交互通信時,如果線路速率是9600 b/s,那么任何方向上的1字節數據(假設有5個字節的壓縮幀頭)往返一次都大約需要12.5ms。它比前面提到的100~200 ms要小得多。需要注意的是,由于幀頭從40個字節壓縮到5個字節,使得1字節數據往返時間從85 ms減到12.5ms。
不幸的是,當使用新型的糾錯和壓縮調制解調器時,這樣的計算就更難了。這些調制解調器所采用的壓縮方法使得在線路上傳輸的字節數大大減少,但糾錯機制又會增加傳輸的時間。不過,這些計算是我們進行合理決策的入口點。
在后面的章節中,我們將用這些串行線路吞吐量的計算來驗證數據從串行線路上通過的時間。
2.11 小結
本章討論了Internet協議族中的最底層協議,鏈路層協議。我們比較了以太網和IEEE802.2/802.3的封裝格式,以及SLIP和PPP的封裝格式。由于SLIP和PPP經常用于低速的鏈路,二者都提供了壓縮不常變化的公共字段的方法。這使交互性能得到提高。
大多數的實現都提供環回接口。訪問這個接口可以通過特殊的環回地址,一般為127.0.0.1。也可以通過發送IP數據報給主機所擁有的任一IP地址。當環回數據回到上層的協議棧中時,它已經過傳輸層和IP層完整的處理過程。
我們描述了很多鏈路都具有的一個重要特性,MTU,相關的一個概念是路徑MTU。根據典型的串行線路MTU,對SLIP和CSLIP鏈路的傳輸時延進行了計算。
本章的內容只覆蓋了當今TCP/IP所采用的部分數據鏈路公共技術。TCP/IP成功的原因之一是它幾乎能在任何數據鏈路技術上運行。