• 套接字缓存之alloc_skb、dev_alloc_skb、kfree_skb、dev_kfree_skb、consume_skb


    alloc_skb

    –分配skb,进行基本的初始化;

    1 static inline struct sk_buff *alloc_skb(unsigned int size,
    2                     gfp_t priority)
    3 {
    4     return __alloc_skb(size, priority, 0, NUMA_NO_NODE);
    5 }
      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 struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
     19                 int flags, int node)
     20 {
     21     struct kmem_cache *cache;
     22     struct skb_shared_info *shinfo;
     23     struct sk_buff *skb;
     24     u8 *data;
     25     bool pfmemalloc;
     26 
     27     /* 得到分配使用的高速缓存 */
     28     cache = (flags & SKB_ALLOC_FCLONE)
     29         ? skbuff_fclone_cache : skbuff_head_cache;
     30 
     31     if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX))
     32         gfp_mask |= __GFP_MEMALLOC;
     33 
     34     /* Get the HEAD */
     35     /* 分配skb */
     36     skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
     37     if (!skb)
     38         goto out;
     39     prefetchw(skb);
     40 
     41     /* We do our best to align skb_shared_info on a separate cache
     42      * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
     43      * aligned memory blocks, unless SLUB/SLAB debug is enabled.
     44      * Both skb->head and skb_shared_info are cache line aligned.
     45      */
     46     /* 数据对齐 */
     47     size = SKB_DATA_ALIGN(size);
     48     /* 对齐后的数据加上skb_shared_info对齐后的大小 */
     49     size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
     50 
     51     //分配数据区
     52     data = kmalloc_reserve(size, gfp_mask, node, &pfmemalloc);
     53     if (!data)
     54         goto nodata;
     55     /* kmalloc(size) might give us more room than requested.
     56      * Put skb_shared_info exactly at the end of allocated zone,
     57      * to allow max possible filling before reallocation.
     58      */
     59     /* 除了skb_shared_info以外的数据大小 */
     60     size = SKB_WITH_OVERHEAD(ksize(data));
     61     prefetchw(data + size);
     62 
     63     /*
     64      * Only clear those fields we need to clear, not those that we will
     65      * actually initialise below. Hence, don't put any more fields after
     66      * the tail pointer in struct sk_buff!
     67      */
     68     memset(skb, 0, offsetof(struct sk_buff, tail));
     69     /* Account for allocated memory : skb + skb->head */
     70     /* 总长度= skb大小+  数据大小+  skb_shared_info大小 */
     71     skb->truesize = SKB_TRUESIZE(size);
     72     /* PFMEMALLOC分配标记 */
     73     skb->pfmemalloc = pfmemalloc;
     74     /* 设置引用计数为1 */
     75     atomic_set(&skb->users, 1);
     76     /*head data tail均指向数据区头部*/
     77     skb->head = data;
     78     skb->data = data;
     79     skb_reset_tail_pointer(skb);
     80 
     81     /* end指向数据区尾部 */
     82     skb->end = skb->tail + size;
     83     /* 初始化默认各层header偏移值 */
     84     skb->mac_header = (typeof(skb->mac_header))~0U;
     85     skb->transport_header = (typeof(skb->transport_header))~0U;
     86 
     87     /* make sure we initialize shinfo sequentially */
     88     /* 从end开始的区域为skb_shared_info */
     89     shinfo = skb_shinfo(skb);
     90     memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));
     91     /* 设置引用计数为1 */
     92     atomic_set(&shinfo->dataref, 1);
     93     kmemcheck_annotate_variable(shinfo->destructor_arg);
     94 
     95     /* 如果有克隆标记 */
     96     if (flags & SKB_ALLOC_FCLONE) {
     97         struct sk_buff_fclones *fclones;
     98 
     99         /* 得到clone结构 */
    100         fclones = container_of(skb, struct sk_buff_fclones, skb1);
    101 
    102         kmemcheck_annotate_bitfield(&fclones->skb2, flags1);
    103 
    104         /* 设置克隆标记 */
    105         skb->fclone = SKB_FCLONE_ORIG;
    106 
    107         /* 设置引用为1 */
    108         atomic_set(&fclones->fclone_ref, 1);
    109 
    110         /* 设置skb2的克隆标记 */
    111         fclones->skb2.fclone = SKB_FCLONE_CLONE;
    112     }
    113 out:
    114     return skb;
    115 nodata:
    116     kmem_cache_free(cache, skb);
    117     skb = NULL;
    118     goto out;
    119 }
    dev_alloc_skb

    –分配skb,通常被设备驱动用在中断上下文中,它是alloc_skb的封装函数,因为在中断处理函数中被调用,因此要求原子操作(GFP_ATOMIC);

    1 /* legacy helper around netdev_alloc_skb() */
    2 static inline struct sk_buff *dev_alloc_skb(unsigned int length)
    3 {
    4     return netdev_alloc_skb(NULL, length);
    5 }
     1 /**
     2  *    netdev_alloc_skb - allocate an skbuff for rx on a specific device
     3  *    @dev: network device to receive on
     4  *    @length: length to allocate
     5  *
     6  *    Allocate a new &sk_buff and assign it a usage count of one. The
     7  *    buffer has unspecified headroom built in. Users should allocate
     8  *    the headroom they think they need without accounting for the
     9  *    built in space. The built in space is used for optimisations.
    10  *
    11  *    %NULL is returned if there is no free memory. Although this function
    12  *    allocates memory it can be called from an interrupt.
    13  */
    14 static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
    15                            unsigned int length)
    16 {
    17     return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
    18 }
     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     len += NET_SKB_PAD;
    24 
    25     /* 
    26         分配长度+ skb_shared_info长度> 一页
    27         有__GFP_DIRECT_RECLAIM | GFP_DMA 标记
    28     */
    29     if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) ||
    30         (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
    31         /* 通过__alloc_skb分配内存*/
    32         skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
    33         if (!skb)
    34             goto skb_fail;
    35 
    36         /* 分配成功 */
    37         goto skb_success;
    38     }
    39 
    40     /* 分配长度+ skb_shared_info长度*/
    41     len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
    42     /* 对整个长度进行对齐 */
    43     len = SKB_DATA_ALIGN(len);
    44 
    45     if (sk_memalloc_socks())
    46         gfp_mask |= __GFP_MEMALLOC;
    47 
    48     /* 保存中断 */
    49     local_irq_save(flags);
    50 
    51     nc = this_cpu_ptr(&netdev_alloc_cache);
    52     /* 分配空间 */
    53     data = page_frag_alloc(nc, len, gfp_mask);
    54     pfmemalloc = nc->pfmemalloc;
    55 
    56     /* 恢复中断 */
    57     local_irq_restore(flags);
    58 
    59     if (unlikely(!data))
    60         return NULL;
    61 
    62     /* 构建skb */
    63     skb = __build_skb(data, len);
    64     if (unlikely(!skb)) {
    65         skb_free_frag(data);
    66         return NULL;
    67     }
    68 
    69     /* use OR instead of assignment to avoid clearing of bits in mask */
    70     /* 设置PFMEMALLOC标记 */
    71     if (pfmemalloc)
    72         skb->pfmemalloc = 1;
    73 
    74     //打内存分配标记
    75     skb->head_frag = 1;
    76 
    77 skb_success:
    78     /* 保留空间 */
    79     skb_reserve(skb, NET_SKB_PAD);
    80     /* 设置输入设备 */
    81     skb->dev = dev;
    82 
    83 skb_fail:
    84     return skb;
    85 }
    kfree_skb

    –减少skb引用,为0则释放,用于出错丢包时释放skb使用;

     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 /*
     9     释放skb
    10 */
    11 void kfree_skb(struct sk_buff *skb)
    12 {
    13     if (unlikely(!skb))
    14         return;
    15     /* 引用为1,可直接释放 */
    16     if (likely(atomic_read(&skb->users) == 1))
    17         smp_rmb();
    18     /*
    19         对引用减1,并且判断,如果结果不为0
    20         说明还有引用,返回
    21     */
    22     else if (likely(!atomic_dec_and_test(&skb->users)))
    23         return;
    24     trace_kfree_skb(skb, __builtin_return_address(0));
    25 
    26     //真正的skb释放
    27     __kfree_skb(skb);
    28 }
     1 /**
     2  *    __kfree_skb - private function
     3  *    @skb: buffer
     4  *
     5  *    Free an sk_buff. Release anything attached to the buffer.
     6  *    Clean the state. This is an internal helper function. Users should
     7  *    always call kfree_skb
     8  */
     9 /* 释放skb */
    10 void __kfree_skb(struct sk_buff *skb)
    11 {
    12     /* 释放skb附带的所有数据 */
    13     skb_release_all(skb);
    14     /* 释放skb */
    15     kfree_skbmem(skb);
    16 }
    dev_kfree_skb && consume_skb

    –减少skb引用,为0则释放,成功状态下释放skb使用;

     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 /* 释放skb,与kfree_skb区别是,kfree_skb用于失败时丢包释放 */
    10 void consume_skb(struct sk_buff *skb)
    11 {
    12     if (unlikely(!skb))
    13         return;
    14     if (likely(atomic_read(&skb->users) == 1))
    15         smp_rmb();
    16     else if (likely(!atomic_dec_and_test(&skb->users)))
    17         return;
    18     trace_consume_skb(skb);
    19     __kfree_skb(skb);
    20 }
    1 #define dev_kfree_skb(a)    consume_skb(a)
  • 相关阅读:
    Oracle 按一行里某个字段里的值分割成多行进行展示
    Property or method "openPageOffice" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by
    SpringBoot 项目启动 Failed to convert value of type 'java.lang.String' to required type 'cn.com.goldenwater.dcproj.dao.TacPageOfficePblmListDao';
    Maven 设置阿里镜像
    JS 日期格式化,留作参考
    JS 过滤数组里对象的某个属性
    原生JS实现简单富文本编辑器2
    Chrome控制台使用详解
    android权限(permission)大全
    不借助第三方网站四步实现手机网站转安卓APP
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7529576.html
Copyright © 2020-2023  润新知