1. 程式人生 > >網路協議棧深入分析(二)--sk_buff的操作函式

網路協議棧深入分析(二)--sk_buff的操作函式

1、alloc_skb()函式

該函式的作用是在上層協議要傳送資料包的時候或網路裝置準備接收資料包的時候會呼叫alloc_skb()函式分配sk_buff結構體,需要釋放時呼叫kfree_skb()函式。

  1. staticinlinestruct sk_buff *alloc_skb(unsigned int size,  
  2.                     gfp_t priority)  
  3. {  
  4.     return __alloc_skb(size, priority, 0, NUMA_NO_NODE);  
  5. }  

這裡使用行內函數,非行內函數呼叫會進堆疊的切換,造成額外的開銷,而行內函數可以解決這一點,可以提高執行效率,只是增加了程式的空間開銷。

        函式呼叫需要時間和空間開銷,呼叫函式實際上將程式執行流程轉移到被調函式中,被調函式的程式碼執行完後,再返回到呼叫的地方。這種呼叫操作要求呼叫前保護好現場並記憶執行的地址,返回後恢復現場,並按原來儲存的地址繼續執行。對於較長的函式這種開銷可以忽略不計,但對於一些函式體程式碼很短,又被頻繁呼叫的函式,就不能忽視這種開銷。引入行內函數正是為了解決這個問題,提高程式的執行效率。

  1. /*  Allocate a new skbuff. We do this ourselves so we can fill in a few 
  2.  *  'private' fields and also do memory statistics to find all the
     
  3.  *  [BEEP] leaks. 
  4.  * 
  5.  */
  6. /** 
  7.  *  __alloc_skb -   allocate a network buffer 
  8.  *  @size: size to allocate 
  9.  *  @gfp_mask: allocation mask 
  10.  *  @fclone: allocate from fclone cache instead of head cache 
  11.  *      and allocate a cloned (child) skb 
  12.  *  @node: numa node to allocate memory on 
  13.  *
     
  14.  *  Allocate a new &sk_buff. The returned buffer has no headroom and a 
  15.  *  tail room of size bytes. The object has a reference count of one. 
  16.  *  The return is the buffer. On a failure the return is %NULL. 
  17.  * 
  18.  *  Buffers may only be allocated from interrupts using a @gfp_mask of 
  19.  *  %GFP_ATOMIC. 
  20.  */
  21. struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,  
  22.                 int fclone, int node)  
  23. {  
  24.     struct kmem_cache *cache;  
  25.     struct skb_shared_info *shinfo;  
  26.     struct sk_buff *skb;  
  27.     u8 *data;  
  28.     cache = fclone ? skbuff_fclone_cache : skbuff_head_cache;  
  29.     /* Get the HEAD */
  30.     skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);//分配儲存空間
  31.     if (!skb)  
  32.         goto out;//分配失敗,返回NULL
  33.     prefetchw(skb);  
  34.     /* We do our best to align skb_shared_info on a separate cache 
  35.      * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives 
  36.      * aligned memory blocks, unless SLUB/SLAB debug is enabled. 
  37.      * Both skb->head and skb_shared_info are cache line aligned. 
  38.      */
  39.     size = SKB_DATA_ALIGN(size);//調整skb大小
  40.     size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));  
  41.     data = kmalloc_node_track_caller(size, gfp_mask, node);//分配資料區
  42.     if (!data)  
  43.         goto nodata;  
  44.     /* kmalloc(size) might give us more room than requested. 
  45.      * Put skb_shared_info exactly at the end of allocated zone, 
  46.      * to allow max possible filling before reallocation. 
  47.      */
  48.     size = SKB_WITH_OVERHEAD(ksize(data));  
  49.     prefetchw(data + size);  
  50.     /* 
  51.      * Only clear those fields we need to clear, not those that we will 
  52.      * actually initialise below. Hence, don't put any more fields after 
  53.      * the tail pointer in struct sk_buff! 
  54.      */
  55.      //sk_buff結構體中最後6個屬性不能改變位置,只能在最後
  56.     memset(skb, 0, offsetof(struct sk_buff, tail));//將sk_buff結構體中tail屬性之前的屬性清零
  57.     /* Account for allocated memory : skb + skb->head */
  58.     skb->truesize = SKB_TRUESIZE(size);//計算緩衝區的尺寸
  59.     atomic_set(&skb->users, 1);  
  60.     //初始化資料區的指標
  61.     skb->head = data;  
  62.     skb->data = data;  
  63.     skb_reset_tail_pointer(skb);  
  64.     skb->end = skb->tail + size;  
  65. #ifdef NET_SKBUFF_DATA_USES_OFFSET
  66.     skb->mac_header = ~0U;  
  67. #endif
  68.     /* make sure we initialize shinfo sequentially */
  69.     //初始化skb_shared_info
  70.     shinfo = skb_shinfo(skb);  
  71.     memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));  
  72.     atomic_set(&shinfo->dataref, 1);  
  73.     kmemcheck_annotate_variable(shinfo->destructor_arg);  
  74.     if (fclone) {  
  75.         struct sk_buff *child = skb + 1;  
  76.         atomic_t *fclone_ref = (atomic_t *) (child + 1);  
  77.         kmemcheck_annotate_bitfield(child, flags1);  
  78.         kmemcheck_annotate_bitfield(child, flags2);  
  79.         skb->fclone = SKB_FCLONE_ORIG;  
  80.         atomic_set(fclone_ref, 1);  
  81.         child->fclone = SKB_FCLONE_UNAVAILABLE;  
  82.     }  
  83. out:  
  84.     return skb;  
  85. nodata:  
  86.     kmem_cache_free(cache, skb);  
  87.     skb = NULL;  
  88.     goto out;  
  89. }  
函式執行完成後,sk_buff的資料指標的形式如下:



2、kfree_skb()函式

該函式就是釋放不被使用的sk_buff結構

  1. /** 
  2.  *  kfree_skb - free an sk_buff 
  3.  *  @skb: buffer to free 
  4.  * 
  5.  *  Drop a reference to the buffer and free it if the usage count has 
  6.  *  hit zero. 
  7.  */
  8. void kfree_skb(struct sk_buff *skb)  
  9. {  
  10.     if (unlikely(!skb))  
  11.         return;  
  12.     if (likely(atomic_read(&skb->users) == 1))  
  13.         smp_rmb();  
  14.     elseif (likely(!atomic_dec_and_test(&skb->users)))  
  15.         return;  
  16.     trace_kfree_skb(skb, __builtin_return_address(0));  
  17.     __kfree_skb(skb);  
  18. }  
再呼叫__kfree_skb函式
  1. void __kfree_skb(struct sk_buff *skb)  
  2. {  
  3.     skb_release_all(skb);//釋放除了skb本身佔用的記憶體
  4.     kfree_skbmem(skb);  
  5. 相關推薦

    no