【文章內(nèi)容簡介】
簡單的錯誤回報、流量控制等功能,在內(nèi)核源碼中的實現(xiàn)文件包含了以ip_為前綴的一系列文件及 、 。再上是兩個傳輸層的協(xié)議,包括面向連接的 TCP 協(xié)議和無連接的 UDP 協(xié)議,在內(nèi)核源碼中的實現(xiàn)文件是以 tcp_為前綴的一系列文件及 。最上層是豐富的應(yīng)用層協(xié)議,內(nèi)核源碼中并不包含此基于無線控制器的接口管理8部f t p t e l n e t s m t ph t t pT C P U D P…t f t p b o o t t p…n f sr c px d rd n sI P / I C M P / I G M PN e t w o r k I n e r f a c eA R P / R A R P圖 TCP/IP 協(xié)議棧分內(nèi)容的具體實現(xiàn)文件,而是由具體的應(yīng)用程序根據(jù) RFC 標準對其加以實現(xiàn)。所以對 TCP/IP 協(xié)議棧按層次構(gòu)件化的任務(wù)主要集中在三層上:ARP/RARP 層,IP/ICMP/IGMP 層,TCP/UDP 層。圖 描述了 Linux 對 TCP/IP 協(xié)議族的實現(xiàn)機制。 網(wǎng)絡(luò)應(yīng)用B S D 套接口I N E T 套接口T C P U D PI P 層A R PP P P S L I P S o c k e t用戶數(shù)據(jù)界面接口界面協(xié)議分層網(wǎng)絡(luò)驅(qū)動圖 Linux 對 TCP/IP 協(xié)議族實現(xiàn)Linux 支持 BSD 的套接字和全部的 TCP/IP 協(xié)議,是通過網(wǎng)絡(luò)協(xié)議將其視為一組相連的軟件層來實現(xiàn)的,BSD 套接字(BSD Socket)由通用的套接字管理軟件支持,該軟件是 INET 套接字層,用來管理基于 IP 的 TCP 與 UDP 端口到端口的互聯(lián)問題 [8]。從協(xié)議分層來看,IP 是網(wǎng)絡(luò)層協(xié)議, TCP 是一個可靠的端口到端第二章 相關(guān)技術(shù)背景 9口的傳輸層協(xié)議,它是利用 IP 層進行傳接報文的,同時也是面向連接的,通過建立一條虛擬電路在不同的網(wǎng)路間傳輸報文,保證所傳輸報文的無丟失性和無重復(fù)性。用戶數(shù)據(jù)報文協(xié)議(User Datagram Protocol, UDP)也是利用 IP 層傳輸報文,但它是一個非面向連接的傳輸層協(xié)議,利用 IP 層傳輸報文時,當目的方網(wǎng)際協(xié)議層收到 IP 報文后,必須識別出該報文所使用的上層協(xié)議(即傳輸層協(xié)議) ,因此,在 IP 報頭上中,設(shè)有一個“協(xié)議”域(Protocol) 。通過該域的值,即可判別其上層協(xié)議類型。對于 TCP 傳輸,傳輸節(jié)點間先要建立連接,然后通過該連接傳輸已排好序的報文,以保證傳輸?shù)恼_性,IP 層中的代碼用于實現(xiàn)網(wǎng)際協(xié)議,這些代碼將 IP頭增加到傳輸數(shù)據(jù)中,同時也把收到的 IP 報文正確的傳送到 TCP 層或 UDP 層。TCP 是一個面向連接協(xié)議,而 UDP 則是一個非面向連接協(xié)議,當一個 UDP 報文發(fā)送出去后,Linux 并不知道也不去關(guān)心它是否成功地到達了目的主機。IP 層之下,是支持所有 Linux 網(wǎng)絡(luò)應(yīng)用的網(wǎng)絡(luò)設(shè)備層,例如點到點協(xié)議 (Point to Point Protocol,PPP )和以太網(wǎng)層。網(wǎng)絡(luò)設(shè)備并非總代表物理設(shè)備,其中有一些(例如回送設(shè)備)則是純粹的軟件設(shè)備,網(wǎng)絡(luò)設(shè)備與標準的 Linux 設(shè)備不同,它們不是通過 mknod 命令創(chuàng)建的,必須是底層軟件找到并進行了初始化之后,這些設(shè)備才被創(chuàng)建并可用。因此只有當啟動了正確設(shè)置的以太網(wǎng)設(shè)備驅(qū)動程序的內(nèi)核后,才會有/dev/eth0 文件,ARP 協(xié)議位于 IP 層和支持地址解析的協(xié)議層之間。 Linux驅(qū)動Linux 設(shè)備驅(qū)動程序在 Linux 的內(nèi)核源代碼中占有很大的比例,源代碼的長度日益增加,主要是驅(qū)動程序的增加。在 Linux 內(nèi)核的不斷升級過程中,驅(qū)動程序的結(jié)構(gòu)還是相對穩(wěn)定。在 到 的變動里,驅(qū)動程序的編寫做了一些改變,但是從 的驅(qū)動到 的移植只需做少量的工作。 Linux 系統(tǒng)的設(shè)備分為字符設(shè)備(char device),塊設(shè)備(block device)和網(wǎng)絡(luò)設(shè)備(work device)三種。字符設(shè)備是指存取時沒有緩存的設(shè)備。塊設(shè)備的讀寫都有緩存來支持,并且塊設(shè)備必須能夠隨機存取(random access),字符設(shè)備則沒有這個要求。典型的字符設(shè)備包括鼠標、鍵盤、串行口等。塊設(shè)備主要包括硬盤軟盤設(shè)備,CDROM 等。一個文件系統(tǒng)要安裝進入操作系統(tǒng)必須在塊設(shè)備上 [9]。每個設(shè)備文件都有其文件屬性(c/b) ,表示是字符設(shè)備還是塊設(shè)備。另外每個文件都有 2 個設(shè)備號,第一個是主設(shè)備號,標識驅(qū)動程序;第二個是從設(shè)備號,標識使用同一個設(shè)備驅(qū)動程序的、不同的硬件設(shè)備。設(shè)備文件的主設(shè)備號必須與設(shè)備驅(qū)動程序在登記時申請的主設(shè)備號一致,否則用戶進程將無法訪問驅(qū)動程序?;跓o線控制器的接口管理10系統(tǒng)調(diào)用時是操作系統(tǒng)內(nèi)核與應(yīng)用程序之間的接口,設(shè)備驅(qū)動程序是操作系統(tǒng)內(nèi)核與機器硬件之間的接口 [10]。設(shè)備驅(qū)動程序是內(nèi)核的一部分,它完成以下功能:1. 對設(shè)備初始化和釋放2. 把數(shù)據(jù)從內(nèi)核傳送到硬件和從硬件讀取數(shù)據(jù)3. 讀取應(yīng)用程序傳送給設(shè)備文件的數(shù)據(jù)和回送應(yīng)用程序請求的數(shù)據(jù)4. 檢測和處理設(shè)備出現(xiàn)的錯誤圖 完整地表現(xiàn)了 Linux 驅(qū)動和系統(tǒng)之間的關(guān)系。應(yīng)用層系統(tǒng)調(diào)用接口虛擬文件系統(tǒng)設(shè)備接口緩存 網(wǎng)絡(luò)子層網(wǎng)絡(luò)設(shè)備驅(qū)動塊設(shè)備驅(qū)動字符設(shè)備驅(qū)動硬件圖 Linux 設(shè)備驅(qū)動模塊圖Linux 的設(shè)備驅(qū)動程序可以分為 3 個主要組成部分 [11]:1. 自動配置和初始化子程序,負責監(jiān)測所有驅(qū)動的硬件設(shè)備是否存在和能否正常工作。如果該設(shè)備正常,則對這個設(shè)備及其相關(guān)的設(shè)備驅(qū)動程序需要的軟件狀態(tài)進行初始化。這部分驅(qū)動程序僅在初始化時被調(diào)用一次。2. 服務(wù)于 I/O 請求的子程序,又稱為驅(qū)動程序的上半部分。調(diào)用這部分程序是由于系統(tǒng)調(diào)用的結(jié)果。這部分程序在執(zhí)行時,系統(tǒng)仍認為是與進行調(diào)用的進程屬于同一個進程,只是由用戶態(tài)變成了核心態(tài),具有進行此系統(tǒng)調(diào)用的用戶程序的運行環(huán)境,因而可以在其中調(diào)用 sleep()等與進程運行環(huán)境有關(guān)的函數(shù)。3. 中斷服務(wù)子程序,又稱為驅(qū)動程序的下半部分。在 Linux 系統(tǒng)中,并不是直接從中斷向量表中調(diào)用設(shè)備驅(qū)動程序的中斷服務(wù)子程序,而是由 Linux 系統(tǒng)來接收硬件中斷,再由系統(tǒng)調(diào)用中斷服務(wù)子程序。中斷可以在任何一個進程運行時產(chǎn)生,因而在中斷服務(wù)程序被調(diào)用時,不能依賴于任何進程的狀態(tài),也就不能調(diào)用任何與進程運行環(huán)境有關(guān)的函數(shù)。因為設(shè)備驅(qū)動程序一般支持同一類型的若干設(shè)備,所以一般在系統(tǒng)調(diào)用中斷服務(wù)子程序時,都帶有一個或多個參數(shù),以唯一第二章 相關(guān)技術(shù)背景 11標識請求服務(wù)的設(shè)備。在 Linux 中,幾乎所有的內(nèi)容都是文件,對設(shè)備驅(qū)動的訪問也是以文件操作的方式實現(xiàn) [12]。無論是字符設(shè)備還是塊設(shè)備,用戶對設(shè)備的操作都是通過虛擬文件系統(tǒng)(VFS) 轉(zhuǎn)化為設(shè)備驅(qū)動與硬件操作程序的交互。即使是訪問網(wǎng)絡(luò)設(shè)備的socket 接口,也是通過 VFS 實現(xiàn)的。Linux 通過 VFS 為用戶提供了一個統(tǒng)一的設(shè)備訪問接口,使用戶能夠透明地訪問設(shè)備驅(qū)動程序。所有的硬件設(shè)備都可以使用和操作系統(tǒng)調(diào)用接口來打開、關(guān)閉、讀寫和 I/O 控制,而驅(qū)動程序的主要任務(wù)就是實現(xiàn)這些系統(tǒng)調(diào)用函數(shù)。Linux 系統(tǒng)中的所有硬件設(shè)備都使用一種特殊的設(shè)備文件來表示。每個設(shè)備文件都有兩個設(shè)備號:一個是主設(shè)備號,它用來標識該設(shè)備的種類,也標識該設(shè)備使用的驅(qū)動程序;另一個是次設(shè)備號,用來標識使用同一設(shè)備驅(qū)動程序的不同硬件設(shè)備。實現(xiàn)一個嵌入式 Linux 設(shè)備驅(qū)動的大致流程如下: 1. 定義主、次設(shè)備號,也可以動態(tài)獲取。2. 實現(xiàn)驅(qū)動初始化和清除函數(shù),如果驅(qū)動程序采用模塊方式,則要實現(xiàn)模塊初始化和清除函數(shù)。3. 設(shè)計所要實現(xiàn)的文件操作,定義 file_operations 結(jié)構(gòu)。4. 實現(xiàn)所需的文件操作調(diào)用,如 read、write 等。5. 實現(xiàn)中斷服務(wù)函數(shù),并用 request_irq 向內(nèi)核注冊。中斷并不是每個設(shè)備驅(qū)動所需要。6. 將驅(qū)動編譯到內(nèi)核或編譯成模塊,用 insmod 命令加載。 7. 生成設(shè)備節(jié)點文件。file_operation 結(jié)構(gòu)中的成員幾乎全部是函數(shù)指針,它們是系統(tǒng)調(diào)用函數(shù)的真正處理函數(shù),所以實質(zhì)上就是函數(shù)跳轉(zhuǎn)表。每個進程對設(shè)備的操作都會根據(jù)major、 minor 設(shè)備號,轉(zhuǎn)換成對 file_operation 結(jié)構(gòu)的訪問。常用的操作包括以下幾種:1. lseek,移動文件指針的位置,只能用于可以隨機存取的設(shè)備。2. read,進行讀操作,參數(shù) buf 為存放讀取結(jié)果的緩沖區(qū), count 為所要讀取的數(shù)據(jù)長度。返回值為負表示讀取操作發(fā)生錯誤;否則,返回實際讀取的字節(jié)數(shù)。對于字符型,要求讀取的字節(jié)數(shù)和返回的實際讀取字節(jié)數(shù)都必須是inodei_blksize 的倍數(shù)。3. write,進行寫操作,與 read 類似。4. readdir,取得下一個目錄入口點,只有與文件系統(tǒng)相關(guān)的設(shè)備程序才使用。5. select,進行選擇操作。如果驅(qū)動程序沒有提供 select 入口,select 操作會認為設(shè)備已經(jīng)準備好進行任何 I/O 操作?;跓o線控制器的接口管理126. ioctl,進行讀、寫以外的其他操作,參數(shù) cmd 為自定義的命令。7. mmap,用于把設(shè)備的內(nèi)容映射到地址空間,一般只有塊設(shè)備驅(qū)動程序使用。8. open,打開設(shè)備準備進行 I/O 操作。返回 0 表示打開成功,返回負數(shù)表示失敗。如果驅(qū)動程序沒有提供 open 入口,則只要 /dev/driver 文件存在就認為打開成功。9. release,即 close 操作。在用戶自己的驅(qū)動程序中,首先要根據(jù)驅(qū)動程序的功能,完成 file_operation結(jié)構(gòu)中函數(shù)實現(xiàn)。不需要的函數(shù)接口可以直接在 file_operation 結(jié)構(gòu)中初始化為NULL。file_operation 變量會在驅(qū)動程序初始化時注冊到系統(tǒng)內(nèi)部。當操作系統(tǒng)對設(shè)備操作時,會調(diào)用驅(qū)動程序注冊的 file_operation 結(jié)構(gòu)中的函數(shù)指針。對于網(wǎng)絡(luò)設(shè)備來說在 Linux 里有專門的處理。Linux 的網(wǎng)絡(luò)系統(tǒng)主要是基于BSD unix 的 socket 機制。在系統(tǒng)和驅(qū)動程序之間定義有專門的數(shù)據(jù)結(jié)構(gòu)(sk_buff)進行數(shù)據(jù)的傳遞。系統(tǒng)里支持對發(fā)送數(shù)據(jù)和接收數(shù)據(jù)的緩存,提供流量控制機制,提供對多協(xié)議的支持。所有的 Linux 網(wǎng)絡(luò)驅(qū)動程序都遵循通用的接口。設(shè)計時采用的是面向?qū)ο蟮姆椒āR粋€設(shè)備就是一個對象(device 結(jié)構(gòu)) ,它內(nèi)部有自己的數(shù)據(jù)和方法。每一個設(shè)備的方法被調(diào)用時的第一個參數(shù)都是這個設(shè)備對象本身。這樣這個方法就可以存取自身的數(shù)據(jù)(類似面向?qū)ο蟪绦蛟O(shè)計時的 this 引用) 。 一個網(wǎng)絡(luò)設(shè)備最基本的方法有初始化、發(fā)送和接收。網(wǎng)絡(luò)驅(qū)動的收發(fā)報文流程圖如圖 。 D e l i v e r p a c k e t sd e v _ q u e u e _ x m i t ( )R e c e i v e p a c k e t s n e t i f _ r x ( )M e t h o d s a n d v a r i a b l e s ( i n i t i a l i z e , o p e n , c l o s e , h a r d _ x m i t , i n t e r r u p t , h a n d l e r , c o n f i g , r e s o u r c e s , s t a t u s . . . )S e n d t o h a r d w a r eR e c e i v c e f r o m h a r d w a r eH a r d w a r e m e d i a圖 網(wǎng)絡(luò)驅(qū)動收發(fā)報文流程圖初始化程序完成硬件的初始化,完成 device 中變量的初始化和系統(tǒng)資源的申請。發(fā)送程序是在驅(qū)動程序的上層協(xié)議層有數(shù)據(jù)要發(fā)送時自動調(diào)用的。一般驅(qū)動程序中不對發(fā)送數(shù)據(jù)進行緩存,而是直接使用硬件的發(fā)送功能把數(shù)據(jù)發(fā)送出去。接收數(shù)據(jù)一般是通過硬件中斷來通知的。在中斷處理程序里,把硬件幀信息填入第二章 相關(guān)技術(shù)背景 13一個 skbuff 結(jié)構(gòu)中,然后調(diào)用 if_rx()傳遞給上層處理。 Linux開源項目1998 年 4 月 7 日,由 Tim O`Reilly 出面,組織并主持了一次“自由軟件峰會”,討論“自由軟件”的稱謂問題。最終使用“Open Source”(“開源” )這個詞。2022 年 Gartner 發(fā)表一份研究報告,認為在未來幾年,幾乎所有企業(yè)都將使用開源軟件。 Gartner 集團在一份名為“The State of Open Source 2022”的研究報告中預(yù)測:到 2022 年, (全球)90%以上的企業(yè)都將使用開源軟件 [13]。 路由管理之 QuaggaQuagga[14]是開源的路由軟件,為 Linux 平臺上實現(xiàn)了 OSPF 版本 2,OSPF 本版 3,RIP 版本 1 和版本 2,RIPng 以及 BGP4 等路由協(xié)議。Quagga 是由Kunihiro Ishiguro 開發(fā)的 GNU Zebra 的衍生而來。 Quagga 樹的目標是建立很多緊密聯(lián)系在 Quagga 周圍的組織,而不是像 GNU Zebra 現(xiàn)在的集中控制處理一樣。Quagga 體系結(jié)構(gòu)包括兩個功能模塊,一個是 Vtysh,一個是 Zebra。Zebra[15]。Zebra 是一種 TCP/IP 路由軟件,它支持 BGPBGP