有關SKB連結串列管理和資料操作的幾個函式
核心中,SKB是以雙向迴圈連結串列的形式儲存的,並且,為了使特定的skb被快速找到,在連結串列的頭部增加了一個新的資料結構sk_buff_head,該結構只是一個輔助節點,不含有資料。
在對SKB連結串列進行操作的時候,首先必須取得sk_buff_head結構中的自旋鎖,這樣才能安全的操作SKB連結串列。
下面以linux-2.6.20核心為例,對有關操作進行說明,以下涉及到的函式定義均在skbuff.c檔案中。
對連結串列的操作主要有以下幾個方面:
1.連結串列初始化,skb_queue_head_init()
2.新增skb到連結串列頭部,skb_queue_head()
3.新增skb
4.從連結串列頭部取下一個skb,skb_dequeue()
5.從連結串列尾部取下一個skb,skb_dequeue_tail()
6.清空連結串列,skb_queue_purge()
7.遍歷skb連結串列,skb_queue_walk(這是一個巨集)
(從這幾個名字中看出,核心程式碼也不過如此嘛,起碼函式名字起的不是很好,含義模糊,哈哈)
對資料的操作主要有以下幾個方面:
新增資料
將使用者空間資料新增到skb尾部,skb_add_data()
刪除資料
刪除線性資料區的資料, skb_trim()
刪除非線性資料區的資料,pskb_trim()
拆分資料
skb_spilt()函式是拆分資料的函式,該函式中有一個引數len,len表示拆分後原來skb中剩餘的資料的長度,因此就有兩種情況:
假設原來的skb中線性資料區的長度為n.因此len和n之間的大小就存在三種關係,大於,小於,等於,相等的情況暫且放入到小於的情形中,一起考慮。因此剩餘兩種情況:
即len<=n和len > n;
如果len<=n,比較容易,因為此時舊的skb中剩餘的資料區比原來的資料區要小(最大相等),也就是說僅僅是對線性資料區進行了拆分。
如果len > n,則表明舊的skb中剩餘的資料大於了原來的線性資料的長度,即把非線性資料區進行了拆分。
重新分配skb的線性資料區。
一個skb一旦分配完成,即呼叫skb_alloc()函式之後,該skb的大小就固定了,即指標head和end之間的長度就是固定的了。有時候需要增加線性資料區的長度,該怎麼辦?答案:重新分配skb。
核心中負責重新分配skb線性區的函式為pskb_expand_head().當然該函式不是隨便分配一個skb,而是在原來skb的基礎上,對headroom 空間和 tailroom 空間進行了擴充套件。分配完新的skb之後,原來的skb被釋放。
檢測SKB佇列是否為空 : skb_queue_empty()