linux 內核網絡系統的源碼剖析第一節

我們知道,linux系統是一個龐大而複雜的系統,代碼行數可想而知,雖然linux內核的代碼是公開的代碼,但是起初,我對閱讀linux內核的代碼是畏懼的,畏懼它的龐大,畏懼它的複雜,閱讀起來會有很多的困難,但是我這個人是想挑戰高難度的,所以,我下定決心試試,閱讀以下linux內核的源代碼。

Linux內核是由很多的子系統組成的,包括進程管理、內存管理、文件系統、網絡系統等,所以需要一個一個的學習,那麼從此刻起,我將和大家分享我學習網絡子系統的總結,帶著大家一起走進linux內核網絡系統的世界。

隨著互聯網的高速發展,我們人人一個手機,通過手機觀看世界上的每一個美好的瞬間,那麼,人們能夠在互聯網上互相交流,看電影、玩遊戲等,事實上是網絡協議的發明起了關鍵性的作用。

1. 網絡體系的介紹

1.1 網絡協議的簡介

對於開發的人員,在設計代碼時,會經常考慮擴展性、模塊化等特點,那麼網絡協議的設計,也是遵循了這樣的思想,一些制定標準的人,將網絡設計成了分層的模型,分層的模型帶來的好處,就是每一層只考慮本層的業務,這樣就保證了擴展性。

Linux所採取的分層模型是OSI模型,將網絡分成了四層,如下所示:

linux 內核網絡系統的源碼剖析第一節

網絡模型

鏈路層提供了設備驅動程序,也就是網卡的驅動相關的程序,設備驅動用來支持物理層的設備。

物理層就是傳輸數據的介質,一般用的最多的就是以太網。

網絡層是向上面傳輸層提供數據,或者從傳輸層接收數據的一個模塊,網絡層最主要處理的報文就是IP報文。

傳輸層大家應該非常不陌生了,它主要為應用層提供數據,以及從應用層接收數據的模塊,它主要處理 TCP 和 UDP 報文,這層的業務比較複雜,可以說是整個協議棧最複雜的模塊之一。

應用層負責處理應用層數據,例如:HTTP、FTP、SMTP、HTTPS等。

1.2 Linux 網絡協議棧的架構簡介

下圖顯示了linux 網絡協議棧的架構,我們可以看出linux是遵循OSI模型進行的架構設計,最上面的為應用層,工作在用戶空間,中間的部分就是我們即將要講的工作在內核空間的網絡協議棧,網絡協議棧中,是靠套接口緩存區進行的數據傳遞,也就是我們常說的skb,有關skb的結構,我會下篇文章詳細述說,網絡協議棧的頂部是系統調用的實現,它是用戶態與內核態傳輸數據的一個模塊,系統調用的下面是套接口層,我們管它叫協議無關層,它提供了一種通用的方法來使用傳輸層,這種通用的設計方法我們可以學一學,這在我們以後的項目中會用到,傳輸層就是具體的協議的實現了,包括TCP和UDP,鄰居子系統主要的作用就是獲取下一跳的mac地址,主要的協議是arp。

linux 內核網絡系統的源碼剖析第一節

linux協議棧網絡分層模型

1.3 Linux 網絡子系統的系統調用的介紹

在linux系統中,用戶態切換到內核態的方式有好幾種,其中最常見的就是系統調用,用戶態進入內核態的方法和cpu的架構有關,對於i386架構的cpu,當進程調用一個系統調用時,系統會產生int 0x80的軟中斷,通過產生的軟中斷用戶態進入內核態,用戶態進程將系統調用號傳入內核,在內核中,有一個系統調用的總的入口,我們成為system_call函數,system_call函數會根據系統調用號作為索引,調用sys_call_table中的函數,這樣最終的系統調用的函數就被執行了。

下圖是套接口層,網絡層,傳輸層的關係圖:

linux 內核網絡系統的源碼剖析第一節

linux套接口系統調用模型

通過上圖,我們可以看到,linux套接口實際上是協議無關層,只是判斷proto,根據proto的值,來調用不同的函數,例如,proto是tcp的話,就會調用tcp_sendmesg函數,來發送數據包,這種抽象的設計是值得我們去學習的。

2. Linux網絡子系統之SKB

Linux 網絡子系統在處理數據包時,會將數據存在某個結構中,然後再對數據進行處理,而這個結構就是套接口緩存,也就是skb,linux內核對緩存有特殊的設計要求:

1) 由於網絡中的報文的長度變化多樣,所以skb要有絕對的能力處理可變長的報文。

2) Skb 要具備在頭尾能夠對數據進行添加和移除,因為skb要在不同的網絡層次之間進行數據的傳遞。

在不同的網絡層次之間進行數據的傳遞時,要儘量的避免數據的copy,因為內存的copy也是比較消耗cpu資源的。

2.1 套接口緩存skb

Linux內核的skb的設計正是遵循了上述的設計要求而設計的,skb用於在網絡層協議層之間進行數據傳遞的一個數據結構,可以用在不同的網絡協議層,例如:數據鏈路層、網絡層(IP層)、傳輸層(TCP/UDP),skb在不同的層次之間進行傳遞時,有些變量會進行修改,例如,四層向三層傳遞數據前,會添加四層的首部,同理,三層向二層傳遞數據前,會添加三層的首部,添加首部要比在不同的層次之間複製skb的效率高,但是添加首部的操作比較複雜,因此linux內核提供一個函數接口skb_reserve()來完成這個操作,每當協議棧中的上一層在往下一層傳遞數據之前,都會調用該函數來添加首部。

如果是下層向上層傳遞skb,那麼下層的首部相關的信息對於上層來說就沒有用了,此時,linux內核並沒有將下層的數據刪除,而是將指針指向上層的頭部,這種方式極大的提高了處理數據的能力。

2.2 套接口緩存skb

skb主要有兩部分組成,一部分是skb描述符(即skb結構體本身),另一部分是數據緩存區,這部分是現申請的,這樣的設計保證了skb可以處理可變長的數據報文,如下圖所示,當然skb不止一個data成員指向數據緩存區,還有其他的成員,當然後續會講到。

linux 內核網絡系統的源碼剖析第一節

linux 套接口結構示意圖

skb的成員變量的介紹:

struct sk_buff*next;

struct sk_buff*prev;

這兩個成員使得skb結構構成了雙向鏈表,頭結點是skb_buff_head,這個就比較簡單了,雙向鏈表構成如下圖:

linux 內核網絡系統的源碼剖析第一節

linux 套接口鏈表連接方式

下一篇,接著介紹linux內核網絡子系統的相關知識,謝謝。


分享到:


相關文章: