skb的分配以及释放
alloc_skb:分配一個數據長度為size的network buffer {skb+data_buffer}
1 /**
2 * __alloc_skb - allocate a network buffer
3 * @size: size to allocate
4 * @gfp_mask: allocation mask
5 * @flags: If SKB_ALLOC_FCLONE is set, allocate from fclone cache
6 * instead of head cache and allocate a cloned (child) skb.
7 * If SKB_ALLOC_RX is set, __GFP_MEMALLOC will be used for
8 * allocations in case the data is required for writeback
9 * @node: numa node to allocate memory on
10 *
11 * Allocate a new &sk_buff. The returned buffer has no headroom and a
12 * tail room of at least size bytes. The object has a reference count
13 * of one. The return is the buffer. On a failure the return is %NULL.
14 *
15 * Buffers may only be allocated from interrupts using a @gfp_mask of
16 * %GFP_ATOMIC.
17 */
18 /*1.SKB 的分配時機主要有兩種,最常見的一種是在網卡的中斷中,有數據包到達的時,系統分配 SKB 包進行包處理;
19 第二種情況是主動分配 SKB 包用于各種調試或者其他處理環境.
20
21 2.SKB 的 reserve 操作:SKB 在分配的過程中使用了一個小技巧 :
22 即在數據區中預留了 128 個字節大小的空間作為協議頭使用,
23 通過移動 SKB 的 data 與 tail 指針的位置來實現這個功能.
24 3.當數據到達網卡后,會觸發網卡的中斷,從而進入 ISR 中,系統會在 ISR 中計算出此次接收到的數據的字節數 : pkt_len,
25 然后調用 SKB 分配函數來分配 SKB :
26 skb = dev_alloc_skb(pkt_len+);
27 實際上傳入的數據區的長度還要比實際接收到的字節數多,這實際上是一種保護機制.
28 實際上,在 dev_alloc_skb 函數調用 __dev_alloc_skb 函數,而 __dev_alloc_skb 函數又調用 alloc_skb 函數 時,
29 其數據區的大小又增加了 128 字節, 這 128 字節就事前面我們所說的 reserve 機制預留的 header 空間
30 */
31 struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
32 int flags, int node)
33 {
34 struct kmem_cache *cache;
35 struct skb_shared_info *shinfo;
36 struct sk_buff *skb;
37 u8 *data;
38 bool pfmemalloc;
39 //獲取指定的高速緩存 fclone_skb or skb
40 cache = (flags & SKB_ALLOC_FCLONE)
41 ? skbuff_fclone_cache : skbuff_head_cache;
42
43 if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX))
44 gfp_mask |= __GFP_MEMALLOC;
45
46 /* Get the HEAD 從cache上分配, 如果cache上無法分配,則從內存中申請 */
47 skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
48 if (!skb)
49 goto out;
50 prefetchw(skb); //用于寫預取 手工執行預抓取 ----提升性能
51
52 /* We do our best to align skb_shared_info on a separate cache
53 * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
54 * aligned memory blocks, unless SLUB/SLAB debug is enabled.
55 * Both skb->head and skb_shared_info are cache line aligned.
56 */
57 size = SKB_DATA_ALIGN(size);/* 數據對齊 */
58 /* 對齊后的數據加上skb_shared_info對齊后的大小 */
59 size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
60 //分配數據區 使用kmalloc ??????
61 data = kmalloc_reserve(size, gfp_mask, node, &pfmemalloc);---
62 if (!data)
63 goto nodata;
64 /* kmalloc(size) might give us more room than requested.
65 * Put skb_shared_info exactly at the end of allocated zone,
66 * to allow max possible filling before reallocation.
67 */
68 /* 除了skb_shared_info以外的數據大小 */
69 size = SKB_WITH_OVERHEAD(ksize(data));
70 prefetchw(data + size);// 手工執行預抓取
71
72 /*
73 * Only clear those fields we need to clear, not those that we will
74 * actually initialise below. Hence, don't put any more fields after
75 * the tail pointer in struct sk_buff!
76 */
77 memset(skb, 0, offsetof(struct sk_buff, tail));
78 /* Account for allocated memory : skb + skb->head */
79 /* 總長度= skb大小+ 數據大小+ skb_shared_info大小 */
80 skb->truesize = SKB_TRUESIZE(size);
81 skb->pfmemalloc = pfmemalloc;
82 atomic_set(&skb->users, 1);/* 設置引用計數為1 */
83 skb->head = data;/*head data tail均指向數據區頭部*/
84 skb->data = data;
85 skb_reset_tail_pointer(skb);
86 //end tail+size 指向尾部
87 skb->end = skb->tail + size;
88 // l2 l3 l4 head 初始化 為啥不是0
89 skb->mac_header = (typeof(skb->mac_header))~0U;
90 skb->transport_header = (typeof(skb->transport_header))~0U;
91
92 /* make sure we initialize shinfo sequentially */
93 //之前 手工執行預抓取 現在使用 -------從end開始的區域為skb_shared_info
94 shinfo = skb_shinfo(skb);// skb->end 也就是 linear data的end ----> 數據的開始
95 memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
96 atomic_set(&shinfo->dataref, 1);
97 kmemcheck_annotate_variable(shinfo->destructor_arg);
98
99 /*skbuff_fclone_cache和skbuff_head_cache。它們兩個的區別是前者是每兩個skb為一組。
100 當從skbuff_fclone_cache分配skb時,會兩個連續的skb一起分配,但是釋放的時候可以分別釋放。
101 也就是說當調用者知道需要兩個skb時,如后面的操作很可能使用skb_clone時,
102 那么從skbuff_fclone_cache上分配skb會更高效一些。*/
103
104 if (flags & SKB_ALLOC_FCLONE) {//如果有克隆標記
105 struct sk_buff_fclones *fclones;/* 如果是fclone cache的話,那么skb的下一個buf,也被分配le
106 之前使用的是flcone_cache 分配*/
107
108 fclones = container_of(skb, struct sk_buff_fclones, skb1);
109
110 kmemcheck_annotate_bitfield(&fclones->skb2, flags1);
111 skb->fclone = SKB_FCLONE_ORIG; //orig
112 atomic_set(&fclones->fclone_ref, 1);//
113
114 fclones->skb2.fclone = SKB_FCLONE_CLONE;
115 fclones->skb2.pfmemalloc = pfmemalloc;
116 }
117 out:
118 return skb;
119 nodata:
120 kmem_cache_free(cache, skb);
121 skb = NULL;
122 goto out;
123 }
dev_alloc_skb:分配skb,通常被設備驅動用在中斷上下文中,它是alloc_skb的封裝函數,因為在中斷處理函數中被調用,因此要求原子操作(GFP_ATOMIC)----不允許休眠;
GFP_ATOMIC:防止allocmemory時出現休眠導致在中斷里面出現調度
static inline struct sk_buff *dev_alloc_skb(unsigned int length)
{
return netdev_alloc_skb(NULL, length);
}
1 /**
2 * __netdev_alloc_skb - allocate an skbuff for rx on a specific device
3 * @dev: network device to receive on
4 * @len: length to allocate
5 * @gfp_mask: get_free_pages mask, passed to alloc_skb
6 *
7 * Allocate a new &sk_buff and assign it a usage count of one. The
8 * buffer has NET_SKB_PAD headroom built in. Users should allocate
9 * the headroom they think they need without accounting for the
10 * built in space. The built in space is used for optimisations.
11 *
12 * %NULL is returned if there is no free memory.
13 */
14 struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
15 gfp_t gfp_mask)
16 {
17 struct page_frag_cache *nc;
18 unsigned long flags;
19 struct sk_buff *skb;
20 bool pfmemalloc;
21 void *data;
22
23 /* 分配長度+ skb_shared_info長度 然后對整個長度進行對齊*/
24 len += NET_SKB_PAD;
25 len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
26 len = SKB_DATA_ALIGN(len);
27
28 if (sk_memalloc_socks())
29 gfp_mask |= __GFP_MEMALLOC;
30
31 local_irq_save(flags);//為啥要 關閉中斷??
32
33 nc = this_cpu_ptr(&netdev_alloc_cache);
34 data = __alloc_page_frag(nc, len, gfp_mask); /* 分配空間 */
35 pfmemalloc = nc->pfmemalloc;
36
37 local_irq_restore(flags);/* 開啟中斷 并restore flag*/
38
39 if (unlikely(!data))
40 return NULL;
41
42 skb = __build_skb(data, len);/* 構建skb */
43 if (unlikely(!skb)) {
44 skb_free_frag(data);
45 return NULL;
46 }
47
48 /* use OR instead of assignment to avoid clearing of bits in mask */
49 if (pfmemalloc)
50 skb->pfmemalloc = 1;
51 skb->head_frag = 1;
52
53 skb_success:
54 skb_reserve(skb, NET_SKB_PAD); /* 保留空間 */
55 skb->dev = dev;/* 設置輸入設備 */
56
57 skb_fail:
58 return skb;
59 }
View Code
1 /**
2 * __build_skb - build a network buffer
3 * @data: data buffer provided by caller
4 * @frag_size: size of data, or 0 if head was kmalloced
5 *
6 * Allocate a new &sk_buff. Caller provides space holding head and
7 * skb_shared_info. @data must have been allocated by kmalloc() only if
8 * @frag_size is 0, otherwise data should come from the page allocator
9 * or vmalloc()
10 * The return is the new skb buffer.
11 * On a failure the return is %NULL, and @data is not freed.
12 * Notes :
13 * Before IO, driver allocates only data buffer where NIC put incoming frame
14 * Driver should add room at head (NET_SKB_PAD) and
15 * MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info))
16 * After IO, driver calls build_skb(), to allocate sk_buff and populate it
17 * before giving packet to stack.
18 * RX rings only contains data buffers, not full skbs.
19 */
20 struct sk_buff *__build_skb(void *data, unsigned int frag_size)
21 {
22 struct skb_shared_info *shinfo;
23 struct sk_buff *skb;
24 unsigned int size = frag_size ? : ksize(data);
25
26 skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC);
27 if (!skb)
28 return NULL;
29
30 size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
31
32 memset(skb, 0, offsetof(struct sk_buff, tail));
33 skb->truesize = SKB_TRUESIZE(size);
34 atomic_set(&skb->users, 1);
35 skb->head = data;
36 skb->data = data;
37 skb_reset_tail_pointer(skb);skb->tail = skb->data;
38 skb->end = skb->tail + size;
39 skb->mac_header = (typeof(skb->mac_header))~0U;
40 skb->transport_header = (typeof(skb->transport_header))~0U;
41
42 /* make sure we initialize shinfo sequentially */
43 shinfo = skb_shinfo(skb);
44 memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
45 atomic_set(&shinfo->dataref, 1);
46 kmemcheck_annotate_variable(shinfo->destructor_arg);
47
48 return skb;
49 }
View Code
napi_alloc_skb:分配skb,和dev_allock_skb差不多:
__napi_alloc_skb - allocate skbuff for rx in a specific NAPI instance
__netdev_alloc_skb - allocate an skbuff for rx on a specific device
和__netdev_alloc_skb 相比;__napi_alloc_skb 實現差不多就多了一部分代碼:
分配長度+ skb_shared_info長度> 一頁 且有__GFP_DIRECT_RECLAIM | GFP_DMA 標記------>則調用alloc_skb分配
struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len,
gfp_t gfp_mask)
{
struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache);
struct sk_buff *skb;
void *data;
len += NET_SKB_PAD + NET_IP_ALIGN;
if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) ||
(gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
if (!skb)
goto skb_fail;
goto skb_success;
}
-------------------
}
當然分配內存最后的底層實現就不看了:有機會再看吧;應該是kmalloc kmem_cache slab get_page order_page啥的吧
kfree_skb:減少skb引用,為0則釋放;Drop a reference to the buffer and free it if the usage count hashit zero.
/**
* kfree_skb - free an sk_buff
* @skb: buffer to free
*
* Drop a reference to the buffer and free it if the usage count has
* hit zero.
*/
void kfree_skb(struct sk_buff *skb)
{
if (unlikely(!skb))
return;
/* 引用為1,可直接釋放 */
if (likely(atomic_read(&skb->users) == 1))
smp_rmb();
// 對引用減1,并且判斷,如果結果不為0 說明還有對象持有 返回
else if (likely(!atomic_dec_and_test(&skb->users)))
return;
trace_kfree_skb(skb, __builtin_return_address(0));
__kfree_skb(skb); //真正的skb釋放
}
/**
* __kfree_skb - private function
* @skb: buffer
*
* Free an sk_buff. Release anything attached to the buffer.
* Clean the state. This is an internal helper function. Users should
* always call kfree_skb
*/
void __kfree_skb(struct sk_buff *skb)
{
skb_release_all(skb);/* 釋放skb附帶的所有數據 */
kfree_skbmem(skb);/* 釋放skb */
}
consume_skb:釋放skb,與kfree_skb區別是,kfree_skb用于失敗時丟包釋放;
也就是:consume_skb表示skb是正常釋放。kfree_skb表示因為某種錯誤報文被丟棄
#define dev_kfree_skb(a) consume_skb(a)
1 /**
2 * consume_skb - free an skbuff
3 * @skb: buffer to free
4 *
5 * Drop a ref to the buffer and free it if the usage count has hit zero
6 * Functions identically to kfree_skb, but kfree_skb assumes that the frame
7 * is being dropped after a failure and notes that
8 */
9 void consume_skb(struct sk_buff *skb)
10 {
11 if (unlikely(!skb))
12 return;
13 if (likely(atomic_read(&skb->users) == 1))
14 smp_rmb();
15 else if (likely(!atomic_dec_and_test(&skb->users)))
16 return;
17 trace_consume_skb(skb);
18 __kfree_skb(skb);
19 }
View Code
所以consume_skb和kfree_skb基本相同;除了統計分析的函數不一樣
http代理服務器(3-4-7層代理)-網絡事件庫公共組件、內核kernel驅動 攝像頭驅動 tcpip網絡協議棧、netfilter、bridge 好像看過!!!!
但行好事 莫問前程
--身高體重180的胖子
總結
以上是生活随笔為你收集整理的skb的分配以及释放的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java exception 二次抛出_
- 下一篇: java listen_Java进阶-I