日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

skb的分配以及释放

發(fā)布時(shí)間:2023/12/13 综合教程 39 生活家
生活随笔 收集整理的這篇文章主要介紹了 skb的分配以及释放 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
alloc_skb:分配一個(gè)數(shù)據(jù)長(zhǎng)度為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 的分配時(shí)機(jī)主要有兩種,最常見的一種是在網(wǎng)卡的中斷中,有數(shù)據(jù)包到達(dá)的時(shí),系統(tǒng)分配 SKB 包進(jìn)行包處理; 
 19  第二種情況是主動(dòng)分配 SKB 包用于各種調(diào)試或者其他處理環(huán)境.
 20  
 21  2.SKB 的 reserve 操作:SKB 在分配的過(guò)程中使用了一個(gè)小技巧 : 
 22  即在數(shù)據(jù)區(qū)中預(yù)留了 128 個(gè)字節(jié)大小的空間作為協(xié)議頭使用, 
 23  通過(guò)移動(dòng) SKB 的 data 與 tail 指針的位置來(lái)實(shí)現(xiàn)這個(gè)功能.
 24  3.當(dāng)數(shù)據(jù)到達(dá)網(wǎng)卡后,會(huì)觸發(fā)網(wǎng)卡的中斷,從而進(jìn)入 ISR 中,系統(tǒng)會(huì)在 ISR 中計(jì)算出此次接收到的數(shù)據(jù)的字節(jié)數(shù) : pkt_len, 
 25  然后調(diào)用 SKB 分配函數(shù)來(lái)分配 SKB :
 26  skb = dev_alloc_skb(pkt_len+);
 27 實(shí)際上傳入的數(shù)據(jù)區(qū)的長(zhǎng)度還要比實(shí)際接收到的字節(jié)數(shù)多,這實(shí)際上是一種保護(hù)機(jī)制.
 28 實(shí)際上,在 dev_alloc_skb 函數(shù)調(diào)用 __dev_alloc_skb 函數(shù),而 __dev_alloc_skb 函數(shù)又調(diào)用 alloc_skb 函數(shù) 時(shí),
 29 其數(shù)據(jù)區(qū)的大小又增加了 128 字節(jié), 這 128 字節(jié)就事前面我們所說(shuō)的 reserve 機(jī)制預(yù)留的 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上無(wú)法分配,則從內(nèi)存中申請(qǐng) */
 47     skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
 48     if (!skb)
 49         goto out; 
 50     prefetchw(skb); //用于寫預(yù)取 手工執(zhí)行預(yù)抓取 ----提升性能
 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);/* 數(shù)據(jù)對(duì)齊 */
 58      /* 對(duì)齊后的數(shù)據(jù)加上skb_shared_info對(duì)齊后的大小 */
 59     size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
 60      //分配數(shù)據(jù)區(qū)  使用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以外的數(shù)據(jù)大小 */
 69     size = SKB_WITH_OVERHEAD(ksize(data));
 70     prefetchw(data + size);// 手工執(zhí)行預(yù)抓取
 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      /* 總長(zhǎng)度= skb大小+  數(shù)據(jù)大小+  skb_shared_info大小 */
 80     skb->truesize = SKB_TRUESIZE(size);
 81     skb->pfmemalloc = pfmemalloc;
 82     atomic_set(&skb->users, 1);/* 設(shè)置引用計(jì)數(shù)為1   */
 83     skb->head = data;/*head data tail均指向數(shù)據(jù)區(qū)頭部*/
 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     //之前 手工執(zhí)行預(yù)抓取 現(xiàn)在使用        -------從end開始的區(qū)域?yàn)閟kb_shared_info 
 94     shinfo = skb_shinfo(skb);// skb->end 也就是 linear data的end ----> 數(shù)據(jù)的開始
 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。它們兩個(gè)的區(qū)別是前者是每?jī)蓚€(gè)skb為一組。
100 當(dāng)從skbuff_fclone_cache分配skb時(shí),會(huì)兩個(gè)連續(xù)的skb一起分配,但是釋放的時(shí)候可以分別釋放。
101 也就是說(shuō)當(dāng)調(diào)用者知道需要兩個(gè)skb時(shí),如后面的操作很可能使用skb_clone時(shí),
102 那么從skbuff_fclone_cache上分配skb會(huì)更高效一些。*/
103 
104     if (flags & SKB_ALLOC_FCLONE) {//如果有克隆標(biāo)記 
105         struct sk_buff_fclones *fclones;/* 如果是fclone cache的話,那么skb的下一個(gè)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,通常被設(shè)備驅(qū)動(dòng)用在中斷上下文中,它是alloc_skb的封裝函數(shù),因?yàn)樵谥袛嗵幚砗瘮?shù)中被調(diào)用,因此要求原子操作(GFP_ATOMIC)----不允許休眠;

GFP_ATOMIC:防止allocmemory時(shí)出現(xiàn)休眠導(dǎo)致在中斷里面出現(xiàn)調(diào)度

 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     /* 分配長(zhǎng)度+ skb_shared_info長(zhǎng)度 然后對(duì)整個(gè)長(zhǎng)度進(jìn)行對(duì)齊*/
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);//為啥要 關(guān)閉中斷??
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);/* 構(gòu)建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;/* 設(shè)置輸入設(shè)備 */
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 實(shí)現(xiàn)差不多就多了一部分代碼:

分配長(zhǎng)度+ skb_shared_info長(zhǎng)度> 一頁(yè) 且有__GFP_DIRECT_RECLAIM | GFP_DMA 標(biāo)記------>則調(diào)用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;
    }
-------------------
}

當(dāng)然分配內(nèi)存最后的底層實(shí)現(xiàn)就不看了:有機(jī)會(huì)再看吧;應(yīng)該是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();
    // 對(duì)引用減1,并且判斷,如果結(jié)果不為0 說(shuō)明還有對(duì)象持有 返回
    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附帶的所有數(shù)據(jù) */
    kfree_skbmem(skb);/* 釋放skb */
}

consume_skb:釋放skb,與kfree_skb區(qū)別是,kfree_skb用于失敗時(shí)丟包釋放;

也就是:consume_skb表示skb是正常釋放。kfree_skb表示因?yàn)槟撤N錯(cuò)誤報(bào)文被丟棄

#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基本相同;除了統(tǒng)計(jì)分析的函數(shù)不一樣

http代理服務(wù)器(3-4-7層代理)-網(wǎng)絡(luò)事件庫(kù)公共組件、內(nèi)核kernel驅(qū)動(dòng) 攝像頭驅(qū)動(dòng) tcpip網(wǎng)絡(luò)協(xié)議棧、netfilter、bridge 好像看過(guò)!!!!
但行好事 莫問(wèn)前程
--身高體重180的胖子

總結(jié)

以上是生活随笔為你收集整理的skb的分配以及释放的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。