資源描述:
《linux網(wǎng)絡(luò)協(xié)議棧筆記》由會員上傳分享,免費在線閱讀,更多相關(guān)內(nèi)容在應(yīng)用文檔-天天文庫。
1、轉(zhuǎn)】Linux內(nèi)核網(wǎng)絡(luò)協(xié)議棧筆記1:協(xié)議棧分層/層次結(jié)構(gòu)大家都知道TCP/IP協(xié)議棧現(xiàn)在是世界上最流行的網(wǎng)絡(luò)協(xié)議棧,恐怕它的普及的最重要的原因就是其清晰的層次結(jié)構(gòu)以及清晰定義的原語和接口。不僅使得上層應(yīng)用開發(fā)者可以無需關(guān)心下層架構(gòu)或者內(nèi)部機制,從而相對透明的操作網(wǎng)絡(luò)。這個明顯的層次結(jié)構(gòu)也可以在Linux內(nèi)核的網(wǎng)絡(luò)協(xié)議棧中觀察到。主要的參考文獻(xiàn)是:Linux網(wǎng)絡(luò)棧剖析(中文版)/AnatomyofLinuxnetworkingstack(英文原版)byTimJones.以及:Linux內(nèi)核2.4.x的網(wǎng)絡(luò)接口結(jié)構(gòu)另外一些參考資料可
2、以從這個頁面找到:http://www.ecsl.cs.sunysb.edu/elibrary/linux/network/(紐約州立大學(xué)石溪分校的頁面)Linux內(nèi)核網(wǎng)絡(luò)協(xié)議棧采用了如下的層次結(jié)構(gòu):內(nèi)核中的五層分別是(從上到下):系統(tǒng)調(diào)用接口(詳見Jones的另一篇文章:使用Linux系統(tǒng)調(diào)用的內(nèi)核命令)協(xié)議無關(guān)接口(BSDsocket層)網(wǎng)絡(luò)協(xié)議(或者簡稱網(wǎng)絡(luò)層。這是一個協(xié)議的集合,從鏈路層到傳輸層的協(xié)議都包括在內(nèi)。不同的協(xié)議在/net文件夾下除core以外的子目錄下,例如基于IP的協(xié)議簇都在/net/ipv4目錄下,以太網(wǎng)
3、協(xié)議在/net/ethernet目錄下)驅(qū)動無關(guān)接口(又稱通用設(shè)備層--genericdevicelayer/驅(qū)動接口層/設(shè)備操作層--devicehandlinglayer。屬于網(wǎng)絡(luò)協(xié)議棧最核心的部分,文件位于內(nèi)核/net/core文件夾下,所以又叫網(wǎng)絡(luò)核心層。其中包括了核心的數(shù)據(jù)結(jié)構(gòu)skbuff文件中的sk_buff/dev.c文件中net_device,這些數(shù)據(jù)結(jié)構(gòu)將在下篇文章中介紹)設(shè)備驅(qū)動程序(在/driver/net文件夾內(nèi))不像OSI或者TCP/IP協(xié)議棧,事實上并沒有一個命名標(biāo)準(zhǔn),因此在這里,這些層次的名稱并不是
4、通用的,但是其語義是清晰的,而且在大多數(shù)其他的文章里只是個別字上的差別。分層詳細(xì)介紹可以參考Jones的文章。我們這里所說的初始化過程指的是從硬件加電啟動,到可以從網(wǎng)絡(luò)接收或發(fā)送數(shù)據(jù)包之前的過程。在Linux系統(tǒng)中,網(wǎng)卡擁有雙重身份:structpci_dev和structnet_device。pci_dev對象代表通用硬件的性質(zhì),是作為一個標(biāo)準(zhǔn)的PCI的設(shè)備插入了PCI的卡槽,由驅(qū)動程序進(jìn)行管理;另一方面,net_device對象代表網(wǎng)絡(luò)傳輸?shù)男再|(zhì),與內(nèi)核的網(wǎng)絡(luò)協(xié)議棧交互,進(jìn)行數(shù)據(jù)傳輸。因此我們也必須通過兩個方面來進(jìn)行初始化,
5、但是后者是我們的重點。而且我們并不關(guān)心內(nèi)核與硬件的交互細(xì)節(jié),例如寄存器讀寫與I/O映射等。內(nèi)核在初始化時,也會初始化一些與網(wǎng)絡(luò)相關(guān)的數(shù)據(jù)結(jié)構(gòu);而且對應(yīng)我們前面的日志所提及的內(nèi)核網(wǎng)絡(luò)協(xié)議棧層次結(jié)構(gòu)(點這里),內(nèi)核也需要一定的初始化工作來建立這種層次結(jié)構(gòu)。筆者認(rèn)為初始化最重要的就是重要數(shù)據(jù)結(jié)構(gòu)(通常用粗體標(biāo)注)。因此也希望讀者能夠記住重要的數(shù)據(jù)結(jié)構(gòu)的作用。下面我們將分層,自底向上的分析整個初始化過程:(一)驅(qū)動程序?qū)颖疚闹幸砸粋€realtek8139系列網(wǎng)卡作為例子,因為其驅(qū)動只有一個c文件(/drivers/net/8139too
6、.c),比較容易分析。讀者也可以參考e1000網(wǎng)卡的另一篇文章(點這里)。內(nèi)核版本基于2.6.11。驅(qū)動程序加載/注冊主要包括以下的步驟:(a)將設(shè)備驅(qū)動程序(pci_driver)添加到內(nèi)核驅(qū)動程序鏈表中;(b)調(diào)用每個驅(qū)動中的probe函數(shù)(其中重要一步就是初始化net_device對象)。下面進(jìn)行詳細(xì)分解。通常,在Linux中使用insmod命令加載一個驅(qū)動程序模塊,例如8139too.o目標(biāo)文件。加載之后,Linux會默認(rèn)執(zhí)行模塊中的module_init(rtl8139_init_module)宏函數(shù),其中的參數(shù)rtl
7、8139_init_module是一個函數(shù)指針,指向在具體的驅(qū)動程序8139too.o中聲明的rtl8139_init_module函數(shù)。這個函數(shù)定義如下:staticint__initrtl8139_init_module(void){returnpci_module_init(&rtl8139_pci_driver);}pci_module_init是一個宏定義,實際上就等于pci_register_driver函數(shù)。(在2.6.30內(nèi)核版本中,直接變成了returnpci_register_driver(&rtl8139_
8、pci_driver))。pci_register_driver函數(shù)的注釋說明了它的作用:registeranewpcidriver.Addsthedriverstructuretothelistofregistereddrivers。也就是把如下的這樣一個驅(qū)動