緩衝區的複製和拷貝
當一個緩衝區需要被特別處理時,可能需要修改sk_buff描述符的內容,但核心不需要完全拷貝sk_buff結構和相關聯的資料緩衝區。為了提高效率,核心可以只複製原始值,也就是拷貝sk_buff結構,然後增加資料緩衝區的引用計數,防止被釋放。 當一個資料包需要被傳輸給多個接受者,如協議處理常式或多個網路分流器時,就需要使用資料包複製技術。 sk_buff的複製沒有連結到任何錶,而且也沒有引用通訊端的擁有者。skb->cloned欄位在複製的和原來的結構豬都設定為1.複製的skb->users設定為1,但對資料緩衝區的引用計數會遞增,因為又有一個sk_buff結構指向這個資料區。skb_clone函數可用於檢查一個skb緩衝區的複製狀態。skb_share_check函數檢查skb->users引用計數是否為1,當不為1時,則說明這個skb是共用的,複製一個新的skb返回,同時將原來的skb引用計數減一。否則直接返回原來的skb。
當一個緩衝區被複製是,資料區塊的內容不能修改,因此訪問該資料的代碼不需要上鎖機制。當若函數不僅需要修改sk_buff結構體的欄位,還需要修改資料時,就必須連資料緩衝區一起複製。這種情況有兩種選擇:若只需要修改skb->head和skb->end地區的資料內容,則可以使用pskb_copy只複製這個地區。若需要修改分區資料區塊中的內容,則需要使用skb_copy將分區地區的資料一起複製。在skb_shared_info結構中也可以包含一個sk_buff結構列表frag_list。以下分別為pskb_copy和skb_copy函數的操作結果:常見sk_buff元素隊列的管理函數skb_queue_head_init:對skb_buff_head隊列頭指標進行初始化skb_queue_head、skb_queue_tail:把一個sk_buff添加到隊列頭或尾skb_dequeue、skb_dequeue_tail:將一個sk_buff從隊列頭或尾移除skb_queue_purge:把隊列變為空白隊列skb_queue_walk:遍曆隊列中的每個元素
這類函數必須以原子方式執行,所以會擷取sk_buff_head隊列頭結構的自旋鎖
- void skb_queue_head(struct sk_buff_head *list, struct
sk_buff *newsk)
- {
- unsigned long flags;
- spin_lock_irqsave(&list->lock, flags);
- __skb_queue_head(list, newsk);
- spin_unlock_irqrestore(&list->lock, flags);
- }