網路模組中,有兩個用來分配skb描述符的快取記憶體,在skb模組初始函式skb_init()中被建立:
void __init skb_init(voidskb_init()函式中建立了skbuff_head_cache 快取記憶體,一般情況下,skb都是從該快取記憶體中分配的。skbuff_fclone_cahe 快取記憶體的建立是為了方便skb的轉殖,如果乙個skb在分配的時候就知道可能被轉殖,那麼應該從這個快取記憶體中分配,因為這個快取記憶體中分配skb時,會同時分配乙個後備的skb,在轉殖的時候直接使用後備的skb即可,不用再次分配skb,很明顯這樣能提高效率。)
alloc_skb()用來分配 skb。資料快取區和 skb 描述符是兩個不同的實體,這就意味著,在
分配乙個 skb 時,需要分配兩塊記憶體,一塊是資料快取區,一塊是 skb 描述符。__alloc_skb()
調 用 kmem_cache_alloc_node() 從 高 速 緩 存 中 獲 取 一 個 sk_buff 結 構 的 空 間,然 後 調 用kmalloc_node_track_caller()分配資料快取區。引數說明如下:
size:待分配 skb 的線性儲存區的長度;
gfp_mask: 分配記憶體的方式
fclone:**是否會轉殖,用於確定從哪個快取記憶體中分配;
node: 當支援 numa(非均勻質儲存結構)時,用於確定何種區域中分配 skb。
struct sk_buff *__alloc_skb(unsigned int需 要 說 明 的 是 , __alloc_skb() 一 般 不 被 直 接 調 用 , 而 是 被 封 裝 函 數 調 用 , 如size, gfp_t gfp_mask,
int fclone, int
node)
out:
return
skb;
nodata:
kmem_cache_free(cache, skb);
skb =null;
goto
out;
}
__netdev_alloc_skb()、alloc_skb()、alloc_skb_fclone()等函式。
呼叫alloc_skb()之後的套介面快取結構:
}這裡__skb_clone就不介紹了,函式就是將要被clone的skb的域賦值給clone的skb。
下圖就是skb_clone之後的兩個skb的結構圖:
當乙個skb被clone之後,這個skb的資料區是不能被修改的,這就意為著,我們訪問資料不需要任何鎖。可是有時我們需要修改資料區,這個時候會有兩個選擇,乙個是我們只修改linear段,也就是head和end之間的段,一種是我們還要修改切片資料,也就是skb_shared_info.
這樣就有兩個函式供我們選擇,第乙個是pskb_copy,第二個是skb_copy.
我們先來看pskb_copy,函式先alloc乙個新的skb,然後呼叫skb_copy_from_linear_data來複製線性區的資料。
struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)然後是skb_copy,它是複製skb的所有資料段,包括切片資料:skb_shinfo(n)->nr_frags =i;
}... copy_skb_header(n, skb);
out:
return
n;}
struct sk_buff *skb_copy(const下面這張圖就表示了psb_copy和skb_copy呼叫後的記憶體模型,其中a是pskb_copy,b是skb_copy:struct sk_buff *skb, gfp_t gfp_mask)
接著來看skb的釋放:
這裡主要是判斷乙個引用標記位users,將它減一,如果大於0則直接返回,否則釋放skb。
void kfree_skb(struct sk_buff *skb)下面幾個函式是在網絡卡驅動裡面可能會用到的:
skb_reserve()
此函式在資料快取區頭部預留一定的空間,通常被用來在資料快取區中插入協議首部或者
在某個邊界上對齊。它並沒有把資料移出或移入資料快取區,而只是簡單地更新了資料快取區
的兩個指標——分別指向負載起始和結尾的data和tail指標。
請注意:skb_reserve()只能用於空的 skb,通常會在分配 skb 之後就呼叫該函式,此時 data
和 tail 指標還一同指向資料區的起始位置,如(a)所示。例如,某個乙太網裝置驅動的接收函
數,在分配 skb 之後,向資料快取區填充資料之前,會有這樣的一條語句 skb_reserve(skb, 2),
這是因為乙太網頭部為 14 位元組長,再加上 2 位元組就正好 16 位元組邊界對齊,所以大多數乙太網
裝置都會在資料報之前保留 2 個位元組。
當skb在協議棧中向下傳遞時,每一層協議都把skb->data指標向上移動,然後複製本層首
部,同時更新skb->len。
skb_push()
此函式在資料快取區的頭部加入一塊資料。修改指向資料區起始的指標data,使之往上移len
位元組,即使資料區向上擴大len位元組,並更新資料區長度len。呼叫skb_push()前後,skb結構變
化見下圖:
tcp層向鏈路層傳遞時的填充過程:
1) 當 tcp 傳送資料時,會根據一些條件,如 tcp 最大分段長度 mss、是否支援聚合分散 i/o
等,分配乙個 skb。
2) tcp 需在資料快取區的頭部預留足夠的空間,用來填充各層首部。max_tcp_header 是
各層首部長度的總和,它考慮了最壞的情況:由於 tcp 層不知道將要用哪個介面傳送包,
它為每一層預留了最大的首部長度,甚至還考慮了出現多個 ip 首部的可能性,因為在核心
編譯支援 ip over ip 的情況下,會遇到多個 ip 首部。
3) 把tcp負載複製到資料快取區。需要注意的是,圖 3-16 只是乙個例子,tcp負載可能會被
組織成其他形式,例如分片,在後續章節中將會看到乙個分片的資料快取區是什麼樣的。
4) tcp 層新增 tcp 首部。
5) skb 傳遞到 ip 層,ip 層為資料報新增 ip 首部。
6) skb 傳遞到鏈路層,鏈路層為資料報新增鏈路層首部。
skb_put()
此函式修改指向資料區末尾的指標tail,使之往下移len位元組,即使資料區向下擴大len位元組,
並更新資料區長度len。呼叫skb_put()前後,skb結構變化見下圖:
此函式通過將data指標往下移動來在資料區首部忽略len位元組長度的資料,通常用於接收到
的資料報後在各層間由下往上傳遞時,上層忽略下層的首部。呼叫skb_pull()前後,skb結構變
化見下圖:
其它還有很多操作sk_buff的函式這裡就不繼續列舉了。
linux 網絡卡驅動
如何安裝linux網絡卡驅動呢,看看下面的說明。適用機型 所有xseries 205 所有xseries 206 所有xseries 225 所有xseries 226 所有xseries 235 所有xseries 236 所有xseries 255 所有xseries 305 所有xseries...
linux網絡卡驅動安裝
有些主機板裝linux之後網絡卡沒驅動的。就要安裝驅動 方法如下 2.cd arl1e x.x.x.x src 3.make install 4.lib modules 2.6.18 238.5.1.el5 kernel drivers net atl1e atl1e.ko 5 insmod arl...
Linux安裝網絡卡驅動
device boot start end blocks id system dev sda1 1 1848 1997188 b w95 fat32 類似資訊,因為我的u盤是2g的盤所以就這個資訊 然後建立乙個目錄usb,如果存在了就算了,一般是這樣的 mkdir mnt usb 所謂的掛接u盤 m...