skb管理函数之alloc_skb、dev_alloc_skb、kfree_skb、dev_kfree_skb、consume_skb

alloc_skb--分配skb

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

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

dev_kfree_skb==consume_skb--减少skb引用,为0则释放,成功状态下释放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 }
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 }

---free系列---

 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 }
1 #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 /* 释放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 }
时间: 2024-10-27 18:03:27

skb管理函数之alloc_skb、dev_alloc_skb、kfree_skb、dev_kfree_skb、consume_skb的相关文章

skb管理函数之skb_clone、pskb_copy、skb_copy

skb_clone--只复制skb描述符本身,如果只修改skb描述符则使用该函数克隆: pskb_copy--复制skb描述符+线性数据区域(包括skb_shared_info),如果需要修改描述符以及数据则使用该函数复制: skb_copy--复制所有数据,包括skb描述符+线性数据区域+非线性数据区,如果需要修改描述符和全部数据则使用该函数复制: 1 /** 2 * skb_clone - duplicate an sk_buff 3 * @skb: buffer to clone 4 *

skb管理函数之skb_put、skb_push、skb_pull、skb_reserve

四个操作函数直接的区别,如下图: 1 /** 2 * skb_put - add data to a buffer 3 * @skb: buffer to use 4 * @len: amount of data to add 5 * 6 * This function extends the used data area of the buffer. If this would 7 * exceed the total buffer size the kernel will panic. A

使用内存管理函数实现动态数组

C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间释放,为有效地使用内存资源提供了手段. 动态数组,指的就是利用内存的申请和释放函数,在程序的运行过程中,根据实际需要指定数组的大小.其本质就是一个指向数组的指针变量. 主要用到的内存管理函数是:malloc和free. 1.分配内存函数malloc: 调用形式:(类型说明符*)malloc(size): 功     能:在内存的动态存储区中分配一块长度为size字节的连续区域. 返     回:该区域

lwip-内存管理函数说明

1.mem_init()   : 内存堆初始化函数,主要设置内存堆的起始地址,以及初始化空闲列表,lwip初始化时调用,内部接口. 2.void *mem_malloc(mem_size_t size)  : 申请分配内存,size为需要申请的内存字节数,返回值为最新分配的内存块的数据地址,注意 不是内存块的地址.如果为分配好内存,返回NULL.申请的内存堆是全局变量. 3.*mem_calloc(mem_size_t count, mem_size_t size) : 是对mem_malloc

functools:管理函数工具(部分)

# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #functools:管理函数工具 #作用:处理其他函数的函数 #版本:2.5及之后 #用于调整或者扩展函数和其他可回调对象,不用重写 #修饰符:主要工具是partial在,用于包装,一个有默认参数可回调对象.得到对象本身是可回调的,可以看作就像是原来的函数,它与原函数完全相同,调用时也可以提供额外的位置或者命名参数,可以使用partial而不是lambda提供的默

μC/OS-Ⅲ系统的时间管理函数和定时器

一.时间管理函数 μC/OS-Ⅲ系统提供一些列时间管理服务函数: 1.OSTimeDly():任务延时n个时钟节拍. 2.OSTimeDlyHMSM():任务延时指定的时间,采用“时:分:秒:毫秒”方式指定. 3.OSTimeDlyResume():恢复被延时的任务.注意,一个任务利用这个函数恢复其他函数时,被恢复任务不知道自己是被其他任务恢复,会任务是延时结束而得到恢复.所以此函数要谨慎使用. 4.OSTimeGet():获取当前时钟节拍计数器的值. 5.OSTimeSet():设置时钟节拍计

ucosiii几个常用的时间管理函数

昨天我们说了系统节拍,经过一步步的分析,了解了任务运行的基础,是怎么来的.今天就继续谈谈"时间管理"这个话题,系统节拍驱动任务的运行,时间管理就是对任务的运行时间进行管理的一种内核机制.那么下面就简单介绍几个常用的时间管理函数. 1.OSTimeDly函数,它位于os_time.c文件中,这个文件还有其他很多的时间管理函数,以下的函数都位于这个文件. 看了上面的参数是不是还是毫无感觉,那我们看看源码,注明:注释不是自己写的,是秉火团队写的.我们需要做的不光是学会使用这些别人提供的好内容

STM32中断管理函数

CM3 内核支持256 个中断,其中包含了16 个内核中断和240 个外部中断,并且具有256 级的可编程中断设置.但STM32 并没有使用CM3 内核的全部东西,而是只用了它的一部分. STM32 有76 个中断,包括16 个内核中断和60 个可屏蔽中断,具有16 级可编程的中断优先级. 而我们常用的就是这60 个可屏蔽中断,所以我们就只针对这60 个可屏蔽中断进行介绍. 在 MDK 内,与NVIC 相关的寄存器,MDK 为其定义了如下的结构体: typedef struct { vu32 I

Linux C 堆内存管理函数malloc(),calloc(),realloc(),free()详解

C 编程中,经常需要操作的内存可分为下面几个类别: 堆栈区(stack):由编译器自动分配与释放,存放函数的参数值,局部变量,临时变量等等,它们获取的方式都是由编译器自动执行的 堆区(heap):一般由程序员分配与释放,基程序员不释放,程序结束时可能由操作系统回收(C/C++没有此等回收机制,Java/C#有),注意它与数据结构中的堆是两回事,分配方式倒是类似于链表. 全局区(静态区)(static):全局变量和静态变量的存储是放在一块儿的,初始化的全局变量和静态变量在一块区域,未初始化的全局变