生活随笔
收集整理的這篇文章主要介紹了
Linux内核--网络协议栈深入分析(二)--sk_buff的操作函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
本文分析基于Linux Kernel 3.2.1
原創作品,轉載請標明http://blog.csdn.net/yming0221/article/details/7972647
更多請查看網絡棧分析專欄http://blog.csdn.net/column/details/linux-kernel-net.html
作者:閆明
1、alloc_skb()函數
該函數的作用是在上層協議要發送數據包的時候或網絡設備準備接收數據包的時候會調用alloc_skb()函數分配sk_buff結構體,需要釋放時調用kfree_skb()函數。
[cpp]?view plaincopy
static?inline?struct?sk_buff?*alloc_skb(unsigned?int?size,?? ????????????????????gfp_t?priority)?? {?? ????return?__alloc_skb(size,?priority,?0,?NUMA_NO_NODE);?? }?? 這里使用內聯函數,非內聯函數調用會進堆棧的切換,造成額外的開銷,而內聯函數可以解決這一點,可以提高執行效率,只是增加了程序的空間開銷。
? ? ? ? 函數調用需要時間和空間開銷,調用函數實際上將程序執行流程轉移到被調函數中,被調函數的代碼執行完后,再返回到調用的地方。這種調用操作要求調用前保護好現場并記憶執行的地址,返回后恢復現場,并按原來保存的地址繼續執行。對于較長的函數這種開銷可以忽略不計,但對于一些函數體代碼很短,又被頻繁調用的函數,就不能忽視這種開銷。引入內聯函數正是為了解決這個問題,提高程序的運行效率。
[cpp]?view plaincopy
? ? ? ? ?? ?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? struct?sk_buff?*__alloc_skb(unsigned?int?size,?gfp_t?gfp_mask,?? ????????????????int?fclone,?int?node)?? {?? ????struct?kmem_cache?*cache;?? ????struct?skb_shared_info?*shinfo;?? ????struct?sk_buff?*skb;?? ????u8?*data;?? ?? ????cache?=?fclone???skbuff_fclone_cache?:?skbuff_head_cache;?? ?? ?????? ????skb?=?kmem_cache_alloc_node(cache,?gfp_mask?&?~__GFP_DMA,?node);?? ????if?(!skb)?? ????????goto?out;?? ????prefetchw(skb);?? ?? ????? ? ? ? ?? ????size?=?SKB_DATA_ALIGN(size);?? ????size?+=?SKB_DATA_ALIGN(sizeof(struct?skb_shared_info));?? ????data?=?kmalloc_node_track_caller(size,?gfp_mask,?node);?? ????if?(!data)?? ????????goto?nodata;?? ????? ? ? ?? ????size?=?SKB_WITH_OVERHEAD(ksize(data));?? ????prefetchw(data?+?size);?? ?? ????? ? ? ? ?? ??????? ????memset(skb,?0,?offsetof(struct?sk_buff,?tail));?? ?????? ????skb->truesize?=?SKB_TRUESIZE(size);?? ????atomic_set(&skb->users,?1);?? ?????? ????skb->head?=?data;?? ????skb->data?=?data;?? ????skb_reset_tail_pointer(skb);?? ????skb->end?=?skb->tail?+?size;?? #ifdef?NET_SKBUFF_DATA_USES_OFFSET?? ????skb->mac_header?=?~0U;?? #endif?? ?? ?????? ?????? ????shinfo?=?skb_shinfo(skb);?? ????memset(shinfo,?0,?offsetof(struct?skb_shared_info,?dataref));?? ????atomic_set(&shinfo->dataref,?1);?? ????kmemcheck_annotate_variable(shinfo->destructor_arg);?? ?? ????if?(fclone)?{?? ????????struct?sk_buff?*child?=?skb?+?1;?? ????????atomic_t?*fclone_ref?=?(atomic_t?*)?(child?+?1);?? ?? ????????kmemcheck_annotate_bitfield(child,?flags1);?? ????????kmemcheck_annotate_bitfield(child,?flags2);?? ????????skb->fclone?=?SKB_FCLONE_ORIG;?? ????????atomic_set(fclone_ref,?1);?? ?? ????????child->fclone?=?SKB_FCLONE_UNAVAILABLE;?? ????}?? out:?? ????return?skb;?? nodata:?? ????kmem_cache_free(cache,?skb);?? ????skb?=?NULL;?? ????goto?out;?? }?? 函數執行完成后,sk_buff的數據指針的形式如下:
2、kfree_skb()函數
該函數就是釋放不被使用的sk_buff結構
[cpp]?view plaincopy
? ? ? ? ? ? ?? void?kfree_skb(struct?sk_buff?*skb)?? {?? ????if?(unlikely(!skb))?? ????????return;?? ????if?(likely(atomic_read(&skb->users)?==?1))?? ????????smp_rmb();?? ????else?if?(likely(!atomic_dec_and_test(&skb->users)))?? ????????return;?? ????trace_kfree_skb(skb,?__builtin_return_address(0));?? ????__kfree_skb(skb);?? }?? 再調用__kfree_skb函數 [cpp]?view plaincopy
void?__kfree_skb(struct?sk_buff?*skb)?? {?? ????skb_release_all(skb);?? ????kfree_skbmem(skb);?? }?? 這里不再向深層函數探究,以后再說。
3、skb_put()函數
該函數是在數據區的末端添加某協議的尾部
[cpp]?view plaincopy
? ? ? ? ? ? ? ? ?? unsigned?char?*skb_put(struct?sk_buff?*skb,?unsigned?int?len)?? {?? ????unsigned?char?*tmp?=?skb_tail_pointer(skb);?? ????SKB_LINEAR_ASSERT(skb);?? ????skb->tail?+=?len;?? ????skb->len??+=?len;?? ????if?(unlikely(skb->tail?>?skb->end))?? ????????skb_over_panic(skb,?len,?__builtin_return_address(0));?? ????return?tmp;?? }?? 執行前后的示意圖如下:
4、skb_push()函數
該函數的作用是在數據區的前端添加某協議的頭部,和skb_put類似。
只不過這里移動的數據指針的是data前移len個單位。
[cpp]?view plaincopy
unsigned?char?*skb_push(struct?sk_buff?*skb,?unsigned?int?len)?? {?? ????skb->data?-=?len;?? ????skb->len??+=?len;?? ????if?(unlikely(skb->data<skb->head))?? ????????skb_under_panic(skb,?len,?__builtin_return_address(0));?? ????return?skb->data;?? }??
5、skb_pull和skb_trim函數正好和上面兩個函數的功能相反,是去掉相應的部分,不再贅述。
6、skb_reverse()函數
該函數的作用是在數據區創建存儲協議頭部的空間,函數實現很簡單。
[cpp]?view plaincopy
static?inline?void?skb_reserve(struct?sk_buff?*skb,?int?len)?? {?? ????skb->data?+=?len;?? ????skb->tail?+=?len;?? }?? 7、sk_buff緩沖區鏈表的操作函數
skb_orphan()函數是將一個緩沖結構體變成孤立的skb
[cpp]?view plaincopy
static?inline?void?skb_orphan(struct?sk_buff?*skb)?? {?? ????if?(skb->destructor)?? ????????skb->destructor(skb);?? ????skb->destructor?=?NULL;?? ????skb->sk??????=?NULL;?? }?? skb_queue_head_init()函數將初始化sk_buff_head結構體
[cpp]?view plaincopy
static?inline?void?skb_queue_head_init(struct?sk_buff_head?*list)?? {?? ????spin_lock_init(&list->lock);?? ????__skb_queue_head_init(list);?? }?? skb_queue_head()在鏈表頭添加一個sk_buff結構
[cpp]?view plaincopy
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);?? }?? 調用__skb_queue_head()函數實現功能
[cpp]?view plaincopy
static?inline?void?__skb_queue_head(struct?sk_buff_head?*list,?? ????????????????????struct?sk_buff?*newsk)?? {?? ????__skb_queue_after(list,?(struct?sk_buff?*)list,?newsk);?? }?? static?inline?void?__skb_queue_after(struct?sk_buff_head?*list,?? ?????????????????????struct?sk_buff?*prev,?? ?????????????????????struct?sk_buff?*newsk)?? {?? ????__skb_insert(newsk,?prev,?prev->next,?list);?? }?? 最后用函數__skb_insert操作雙鏈表
[cpp]?view plaincopy
static?inline?void?__skb_insert(struct?sk_buff?*newsk,?? ????????????????struct?sk_buff?*prev,?struct?sk_buff?*next,?? ????????????????struct?sk_buff_head?*list)?? {?? ????newsk->next?=?next;?? ????newsk->prev?=?prev;?? ????next->prev??=?prev->next?=?newsk;?? ????list->qlen++;?? }?? 函數skb_queue_tail() ?在緩沖區鏈表尾部添加新的skb
函數skb_dequeue() ? 在鏈表頭部移走一個skb
函數skb_dequeue_tail() ?在鏈表尾部移走一個skb
函數skb_queue_purge() ?清空一個由sk_buff_head管理的緩沖區鏈表,具體操作如下:
[cpp]?view plaincopy
void?skb_queue_purge(struct?sk_buff_head?*list)?? {?? ????struct?sk_buff?*skb;?? ????while?((skb?=?skb_dequeue(list))?!=?NULL)?? ????????kfree_skb(skb);?? }?? 函數skb_append() ?在指定的skb后附加一個緩沖區,最終還是調用__skb_insert()函數完成的鏈表操作
轉載于:https://www.cnblogs.com/wangfengju/archive/2013/04/13/6173193.html
總結
以上是生活随笔為你收集整理的Linux内核--网络协议栈深入分析(二)--sk_buff的操作函数的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。