資源描述:
《Linux TCP IP 協(xié)議棧的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)Socket Buffer》由會(huì)員上傳分享,免費(fèi)在線閱讀,更多相關(guān)內(nèi)容在應(yīng)用文檔-天天文庫(kù)。
1、LinuxTCP/IP協(xié)議棧的關(guān)鍵數(shù)據(jù)結(jié)構(gòu)SocketBuffersk_buff結(jié)構(gòu)可能是linux網(wǎng)絡(luò)代碼中最重要的數(shù)據(jù)結(jié)構(gòu),它表示接收或發(fā)送數(shù)據(jù)包的包頭信息。它在中定義,并包含很多成員變量供網(wǎng)絡(luò)代碼中的各子系統(tǒng)使用。這個(gè)結(jié)構(gòu)在linux內(nèi)核的發(fā)展過(guò)程中改動(dòng)過(guò)很多次,或者是增加新的選項(xiàng),或者是重新組織已存在的成員變量以使得成員變量的布局更加清晰。它的成員變量可以大致分為以下幾類:·Layout布局·General通用·Feature-specific功能相關(guān)·
2、Managementfunctions管理函數(shù)這個(gè)結(jié)構(gòu)被不同的網(wǎng)絡(luò)層(MAC或者其他二層鏈路協(xié)議,三層的IP,四層的TCP或UDP等)使用,并且其中的成員變量在結(jié)構(gòu)從一層向另一層傳遞時(shí)改變。L4向L3傳遞前會(huì)添加一個(gè)L4的頭部,同樣,L3向L2傳遞前,會(huì)添加一個(gè)L3的頭部。添加頭部比在不同層之間拷貝數(shù)據(jù)的效率更高。由于在緩沖區(qū)的頭部添加數(shù)據(jù)意味著要修改指向緩沖區(qū)的指針,這是個(gè)復(fù)雜的操作,所以內(nèi)核提供了一個(gè)函數(shù)skb_reserve(在后面的章節(jié)中描述)來(lái)完成這個(gè)功能。協(xié)議棧中的每一層在往下一層傳遞緩沖區(qū)前,第
3、一件事就是調(diào)用skb_reserve在緩沖區(qū)的頭部給協(xié)議頭預(yù)留一定的空間。skb_reserve同樣被設(shè)備驅(qū)動(dòng)使用來(lái)對(duì)齊接收到包的包頭。如果緩沖區(qū)向上層協(xié)議傳遞,舊的協(xié)議層的頭部信息就沒什么用了。例如,L2的頭部只有在網(wǎng)絡(luò)驅(qū)動(dòng)處理L2的協(xié)議時(shí)有用,L3是不會(huì)關(guān)心它的信息的。但是,內(nèi)核并沒有把L2的頭部從緩沖區(qū)中刪除,而是把有效荷載的指針指向L3的頭部,這樣做,可以節(jié)省CPU時(shí)間。1.網(wǎng)絡(luò)參數(shù)和內(nèi)核數(shù)據(jù)結(jié)構(gòu)就像你在瀏覽TCP/IP規(guī)范或者配置內(nèi)核時(shí)所看到的一樣,網(wǎng)絡(luò)代碼提供了很多有用的功能,但是這些功能并不是必
4、須的,比如說(shuō),防火墻,多播,還有其他一些功能。大部分的功能都需要在內(nèi)核數(shù)據(jù)結(jié)構(gòu)中添加自己的成員變量。因此,sk_buff里面包含了很多像#ifdef這樣的預(yù)編譯指令。例如,在sk_buff結(jié)構(gòu)的最后,你可以找到:structsk_buff{????.........#ifdefCONFIG_NET_SCHED????__u32????tc_index;#ifdefCONFIG_NET_CLS_ACT????__u32????tc_verd;????__u32????tc_classid;#endif#endi
5、f}它表明,tc_index只有在編譯時(shí)定義了CONFIG_NET_SCHED符號(hào)才有效。這個(gè)符號(hào)可以通過(guò)選擇特定的編譯選項(xiàng)來(lái)定義(例如:"DeviceDriversNetworkingsupportNetworkingoptionsQoSand/orfairqueueing")。這些編譯選項(xiàng)可以由管理員通過(guò)makeconfig來(lái)選擇,或者通過(guò)一些自動(dòng)安裝工具來(lái)選擇。前面的例子有兩個(gè)嵌套的選項(xiàng):CONFIG_NET_CLS_ACT(包分類器)只有在選擇支持“QoSand/orfairqueueing”時(shí)才能生
6、效。順便提一下,QoS選項(xiàng)不能被編譯成內(nèi)核模塊。原因就是,內(nèi)核編譯之后,由某個(gè)選項(xiàng)所控制的數(shù)據(jù)結(jié)構(gòu)是不能動(dòng)態(tài)變化的。一般來(lái)說(shuō),如果某個(gè)選項(xiàng)會(huì)修改內(nèi)核數(shù)據(jù)結(jié)構(gòu)(比如說(shuō),在sk_buff里面增加一個(gè)項(xiàng)tc_index),那么,包含這個(gè)選項(xiàng)的組件就不能被編譯成內(nèi)核模塊。你可能經(jīng)常需要查找是哪個(gè)makeconfig編譯選項(xiàng)或者變種定義了某個(gè)#ifdef標(biāo)記,以便理解內(nèi)核中包含的某段代碼。在2.6內(nèi)核中,最快的,查找它們之間關(guān)聯(lián)關(guān)系的方法,就是查找分布在內(nèi)核源代碼樹中的kconfig文件中是否定義了相應(yīng)的符號(hào)(每個(gè)目錄
7、都有一個(gè)這樣的文件)。在2.4內(nèi)核中,你需要查看Documentation/Configure.help文件。2.LayoutFields有些sk_buff成員變量的作用是方便查找或者是連接數(shù)據(jù)結(jié)構(gòu)本身。內(nèi)核可以把sk_buff組織成一個(gè)雙向鏈表。當(dāng)然,這個(gè)鏈表的結(jié)構(gòu)要比常見的雙向鏈表的結(jié)構(gòu)復(fù)雜一點(diǎn)。就像任何一個(gè)雙向鏈表一樣,sk_buff中有兩個(gè)指針next和prev,其中,next指向下一個(gè)節(jié)點(diǎn),而prev指向上一個(gè)節(jié)點(diǎn)。但是,這個(gè)鏈表還有另一個(gè)需求:每個(gè)sk_buff結(jié)構(gòu)都必須能夠很快找到鏈表頭節(jié)點(diǎn)。為
8、了滿足這個(gè)需求,在第一個(gè)節(jié)點(diǎn)前面會(huì)插入另一個(gè)結(jié)構(gòu)sk_buff_head,這是一個(gè)輔助節(jié)點(diǎn),它的定義如下:structsk_buff_head{??/*Thesetwomembersmustbefirst.*/???structsk_buff????*next;??????structsk_buff????*prev;?????????__u32????????qlen;??????spinlock