/*allocate a network buffer, and init the skb->data and skb->tail to skb->head*/
struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
{
struct sk_buff *skb;
u8 *data;
if (in_interrupt() && (gfp_mask & __GFP_WAIT)) {
static int count = 0;
if (++count < 5) {
printk(KERN_ERR "alloc_skb called nonatomically "
"from interrupt %p/n", NET_CALLER(size));
BUG();
}
gfp_mask &= ~__GFP_WAIT;
}
/* Get the HEAD */
skb = skb_head_from_pool();
if (skb == NULL) {
skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask & ~__GFP_DMA);
if (skb == NULL)
goto nohead;
}
/* Get the DATA. Size must match skb_add_mtu(). */
size = SKB_DATA_ALIGN(size); //32字節對齊
data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
if (data == NULL)
goto nodata;
/* XXX: does not include slab overhead */
skb->truesize = size + sizeof(struct sk_buff);
這是緩衝區的總長度,包括sk_buff結構和數據部分。如果申請一個len字節的緩衝區,
alloc_skb函數會把它初始化成len+sizeof(sk_buff)。
/* Load the data pointers. */
skb->head = data;
skb->data = data;
skb->tail = data;
skb->end = data + size;
/* Set up other state */
skb->len = 0;
skb->cloned = 0;
skb->data_len = 0;
atomic_set(&skb->users, 1);
atomic_set(&(skb_shinfo(skb)->dataref), 1);
skb_shinfo(skb)->nr_frags = 0;
skb_shinfo(skb)->frag_list = NULL;
return skb;
nodata:
skb_head_to_pool(skb);
nohead:
return NULL;
}
skb_head_pool[NR_CPUS]就是skb head的池子,每個cpu一個struct skb_buff_head list.
當一個skb不在需要的時候,不使用kmem_cache_free釋放,而是skb_head_to_poo加到當前
cpu的skb_head_pool的list上,這樣下次分配skb的時候,就可以skb_head_from_pool從skb_head_pool
中取,而不用kmem_cache_alloc重新分配.int sysctl_hot_list_len=128是list的長度上限。
alloc_skb的時候先從skb_head_pool裏skb_head_from_pool去sk_buff,如果沒取到它返回的就是NULL,
就kmem_cache_alloc從skbuff_head_cache裏分配.
skb_head_from_pool就是從skb_head_pool的list取sk_buff
skb_head_to_pool把不用的sk_buff加到skb_head_pool的list上,如果list滿了就kmem_cache_free(skbuff_head_cache,skb)
在alloc_skb裏面
data=kmalloc(size+sizeof(struct skb_shared_info),gfp_mask);
if(data==NULL) /*數據空間分配沒有成功,上面成功分配了sk_buff*/
goto nodata;
......
nodata:
skb_head_to_pool(skb); /*skb_head_pool的list沒滿就加到list上,以後alloc_skb時用*/
void kfree_skbmem(struct sk_buff *skb)
{
skb_release_data(skb); /*釋放數據空間*/
skb_head_to_pool(skb); /*處理sk_buff,跟上面一樣*/
}
http://vger.kernel.org/~davem/ skb參考資料