skb管理函数之alloc_skb、dev_alloc_skb、kfree_skb、dev_kfree_skb、consume_skb
alloc_skb
–分配skb,进行基本的初始化;
static inline struct sk_buff *alloc_skb(unsigned int size,
gfp_t priority)
{
return __alloc_skb(size, priority, , NUMA_NO_NODE);
}
/**
* __alloc_skb - allocate a network buffer
* @size: size to allocate
* @gfp_mask: allocation mask
* @flags: If SKB_ALLOC_FCLONE is set, allocate from fclone cache
* instead of head cache and allocate a cloned (child) skb.
* If SKB_ALLOC_RX is set, __GFP_MEMALLOC will be used for
* allocations in case the data is required for writeback
* @node: numa node to allocate memory on
*
* Allocate a new &sk_buff. The returned buffer has no headroom and a
* tail room of at least size bytes. The object has a reference count
* of one. The return is the buffer. On a failure the return is %NULL.
*
* Buffers may only be allocated from interrupts using a @gfp_mask of
* %GFP_ATOMIC.
*/
struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
int flags, int node)
{
struct kmem_cache *cache;
struct skb_shared_info *shinfo;
struct sk_buff *skb;
u8 *data;
bool pfmemalloc; /* 得到分配使用的高速缓存 */
cache = (flags & SKB_ALLOC_FCLONE)
? skbuff_fclone_cache : skbuff_head_cache; if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX))
gfp_mask |= __GFP_MEMALLOC; /* Get the HEAD */
/* 分配skb */
skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);
if (!skb)
goto out;
prefetchw(skb); /* We do our best to align skb_shared_info on a separate cache
* line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives
* aligned memory blocks, unless SLUB/SLAB debug is enabled.
* Both skb->head and skb_shared_info are cache line aligned.
*/
/* 数据对齐 */
size = SKB_DATA_ALIGN(size);
/* 对齐后的数据加上skb_shared_info对齐后的大小 */
size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); //分配数据区
data = kmalloc_reserve(size, gfp_mask, node, &pfmemalloc);
if (!data)
goto nodata;
/* kmalloc(size) might give us more room than requested.
* Put skb_shared_info exactly at the end of allocated zone,
* to allow max possible filling before reallocation.
*/
/* 除了skb_shared_info以外的数据大小 */
size = SKB_WITH_OVERHEAD(ksize(data));
prefetchw(data + size); /*
* Only clear those fields we need to clear, not those that we will
* actually initialise below. Hence, don't put any more fields after
* the tail pointer in struct sk_buff!
*/
memset(skb, , offsetof(struct sk_buff, tail));
/* Account for allocated memory : skb + skb->head */
/* 总长度= skb大小+ 数据大小+ skb_shared_info大小 */
skb->truesize = SKB_TRUESIZE(size);
/* PFMEMALLOC分配标记 */
skb->pfmemalloc = pfmemalloc;
/* 设置引用计数为1 */
atomic_set(&skb->users, );
/*head data tail均指向数据区头部*/
skb->head = data;
skb->data = data;
skb_reset_tail_pointer(skb); /* end指向数据区尾部 */
skb->end = skb->tail + size;
/* 初始化默认各层header偏移值 */
skb->mac_header = (typeof(skb->mac_header))~0U;
skb->transport_header = (typeof(skb->transport_header))~0U; /* make sure we initialize shinfo sequentially */
/* 从end开始的区域为skb_shared_info */
shinfo = skb_shinfo(skb);
memset(shinfo, , offsetof(struct skb_shared_info, dataref));
/* 设置引用计数为1 */
atomic_set(&shinfo->dataref, );
kmemcheck_annotate_variable(shinfo->destructor_arg); /* 如果有克隆标记 */
if (flags & SKB_ALLOC_FCLONE) {
struct sk_buff_fclones *fclones; /* 得到clone结构 */
fclones = container_of(skb, struct sk_buff_fclones, skb1); kmemcheck_annotate_bitfield(&fclones->skb2, flags1); /* 设置克隆标记 */
skb->fclone = SKB_FCLONE_ORIG; /* 设置引用为1 */
atomic_set(&fclones->fclone_ref, ); /* 设置skb2的克隆标记 */
fclones->skb2.fclone = SKB_FCLONE_CLONE;
}
out:
return skb;
nodata:
kmem_cache_free(cache, skb);
skb = NULL;
goto out;
}
dev_alloc_skb
–分配skb,通常被设备驱动用在中断上下文中,它是alloc_skb的封装函数,因为在中断处理函数中被调用,因此要求原子操作(GFP_ATOMIC);
/* legacy helper around netdev_alloc_skb() */
static inline struct sk_buff *dev_alloc_skb(unsigned int length)
{
return netdev_alloc_skb(NULL, length);
}
/**
* netdev_alloc_skb - allocate an skbuff for rx on a specific device
* @dev: network device to receive on
* @length: length to allocate
*
* Allocate a new &sk_buff and assign it a usage count of one. The
* buffer has unspecified headroom built in. Users should allocate
* the headroom they think they need without accounting for the
* built in space. The built in space is used for optimisations.
*
* %NULL is returned if there is no free memory. Although this function
* allocates memory it can be called from an interrupt.
*/
static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev,
unsigned int length)
{
return __netdev_alloc_skb(dev, length, GFP_ATOMIC);
}
/**
* __netdev_alloc_skb - allocate an skbuff for rx on a specific device
* @dev: network device to receive on
* @len: length to allocate
* @gfp_mask: get_free_pages mask, passed to alloc_skb
*
* Allocate a new &sk_buff and assign it a usage count of one. The
* buffer has NET_SKB_PAD headroom built in. Users should allocate
* the headroom they think they need without accounting for the
* built in space. The built in space is used for optimisations.
*
* %NULL is returned if there is no free memory.
*/
struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len,
gfp_t gfp_mask)
{
struct page_frag_cache *nc;
unsigned long flags;
struct sk_buff *skb;
bool pfmemalloc;
void *data; len += NET_SKB_PAD; /*
分配长度+ skb_shared_info长度> 一页
有__GFP_DIRECT_RECLAIM | GFP_DMA 标记
*/
if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) ||
(gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) {
/* 通过__alloc_skb分配内存*/
skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE);
if (!skb)
goto skb_fail; /* 分配成功 */
goto skb_success;
} /* 分配长度+ skb_shared_info长度*/
len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
/* 对整个长度进行对齐 */
len = SKB_DATA_ALIGN(len); if (sk_memalloc_socks())
gfp_mask |= __GFP_MEMALLOC; /* 保存中断 */
local_irq_save(flags); nc = this_cpu_ptr(&netdev_alloc_cache);
/* 分配空间 */
data = page_frag_alloc(nc, len, gfp_mask);
pfmemalloc = nc->pfmemalloc; /* 恢复中断 */
local_irq_restore(flags); if (unlikely(!data))
return NULL; /* 构建skb */
skb = __build_skb(data, len);
if (unlikely(!skb)) {
skb_free_frag(data);
return NULL;
} /* use OR instead of assignment to avoid clearing of bits in mask */
/* 设置PFMEMALLOC标记 */
if (pfmemalloc)
skb->pfmemalloc = ; //打内存分配标记
skb->head_frag = ; skb_success:
/* 保留空间 */
skb_reserve(skb, NET_SKB_PAD);
/* 设置输入设备 */
skb->dev = dev; skb_fail:
return skb;
}
kfree_skb
–减少skb引用,为0则释放,用于出错丢包时释放skb使用;
/**
* 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.
*/
/*
释放skb
*/
void kfree_skb(struct sk_buff *skb)
{
if (unlikely(!skb))
return;
/* 引用为1,可直接释放 */
if (likely(atomic_read(&skb->users) == ))
smp_rmb();
/*
对引用减1,并且判断,如果结果不为0
说明还有引用,返回
*/
else if (likely(!atomic_dec_and_test(&skb->users)))
return;
trace_kfree_skb(skb, __builtin_return_address()); //真正的skb释放
__kfree_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
*/
/* 释放skb */
void __kfree_skb(struct sk_buff *skb)
{
/* 释放skb附带的所有数据 */
skb_release_all(skb);
/* 释放skb */
kfree_skbmem(skb);
}
dev_kfree_skb && consume_skb
–减少skb引用,为0则释放,成功状态下释放skb使用;
/**
* consume_skb - free an skbuff
* @skb: buffer to free
*
* Drop a ref to the buffer and free it if the usage count has hit zero
* Functions identically to kfree_skb, but kfree_skb assumes that the frame
* is being dropped after a failure and notes that
*/
/* 释放skb,与kfree_skb区别是,kfree_skb用于失败时丢包释放 */
void consume_skb(struct sk_buff *skb)
{
if (unlikely(!skb))
return;
if (likely(atomic_read(&skb->users) == ))
smp_rmb();
else if (likely(!atomic_dec_and_test(&skb->users)))
return;
trace_consume_skb(skb);
__kfree_skb(skb);
}
#define dev_kfree_skb(a) consume_skb(a)
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管理函数之skb_put、skb_push、skb_pull、skb_reserve
		
四个操作函数直接的区别,如下图: /** * skb_put - add data to a buffer * @skb: buffer to use * @len: amount of data t ...
 - μC/OS-Ⅲ系统的时间管理函数和定时器
		
一.时间管理函数 μC/OS-Ⅲ系统提供一些列时间管理服务函数: 1.OSTimeDly():任务延时n个时钟节拍. 2.OSTimeDlyHMSM():任务延时指定的时间,采用“时:分:秒:毫秒”方 ...
 - 内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。
		
(1)内存管理函数与内存管理运算符的区别 内存管理函数有内存分配函数,malloc calloc realloc 以及内存释放函数free. 内存管理运算符有new 和delete. 两种内存管理方式 ...
 - functools:管理函数工具(部分)
		
# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #functools:管理函数工具 #作用:处理其他函数的函数 #版 ...
 - POSIX多线程——基本线程管理函数介绍
		
POSIX基本的几个线程管理函数见下表: ------------------------------------------------------------------------------- ...
 - [图形学] Chp9 三维几何变换--栈处理函数与矩阵管理函数的区别
		
矩阵管理函数:glLoadIdentity()是把当前活动矩阵设置为单位矩阵. 栈处理函数:glPushMatrix()是将当前活动的变换矩阵复制一份,压入栈顶:glPopMatrix()是破坏当前活 ...
 - C++内存管理-重载内存管理函数
		
记录学习的点点滴滴,参考侯捷<<C++内存管理>> 我们先重载一下C++的几个内存管理函数 operator new, operator new[], operator del ...
 - 【教训】null == '',改造ThinkSNS 系统里面的一个缓存管理函数S()后,留下一个大bug
		
本来想简化 ThinkSNS 系统里面的一个缓存管理函数: <?php /** * 用来对应用缓存信息的读.写.删除 * $expire = null/0 表示永久缓存,否则为缓存有效期 */ ...
 
随机推荐
- 第45天:2017webstrom下载破解汉化
			
1.webstrom 11.0.3下载地址1:http://pan.baidu.com/s/1kVQjcwf 密码:uggr 下载地址2:http://pan.baidu.com/s/1kVQjcwf ...
 - 【Python】爬虫与反爬虫大战
			
爬虫与发爬虫的厮杀,一方为了拿到数据,一方为了防止爬虫拿到数据,谁是最后的赢家? 重新理解爬虫中的一些概念 爬虫:自动获取网站数据的程序反爬虫:使用技术手段防止爬虫程序爬取数据误伤:反爬虫技术将普通用 ...
 - RT-thread内核之空闲线程
			
空闲线程是系统线程中一个比较特殊的线程,它具有最低的优先级,当系统中无其他线程可运行时,调度器将调度到空闲线程.空闲线程通常是一个死循环,永远不被挂起.RT-Thread实时操作系统为空闲线程提供了钩 ...
 - javascript中var let const三种变量声明方式
			
javascript中var let const三种变量声明方式 1.var ①var表示声明了一个变量,并且可以同时初始化该变量. ②使用var语句声明的变量的作用域是当前执行位置的上下文:一个函 ...
 - BZOJ2178:圆的面积并——题解
			
https://www.lydsy.com/JudgeOnline/problem.php?id=2178 给出N个圆,求其面积并. simpson,将圆劈成两半,假设上面的叫上壳,下面的叫下壳,对这 ...
 - BZOJ4566:[HAOI2016]找相同字符——题解
			
https://www.lydsy.com/JudgeOnline/problem.php?id=4566 https://www.luogu.org/problemnew/show/P3181 给定 ...
 - bzoj1878: [SDOI2009]HH的项链(主席树/离线+BIT)
			
这题有离线和在线两种做法. 离线:将查询区间按左端点排序,预处理出所有数下一次的出现位置,一开始将所有第一次出现的数a[i]++,之后当扫到这个数的时候a[next[i]]++,相当于差分,给之后 ...
 - ContestHunter暑假欢乐赛 SRM 08
			
rating再次跳水www A题贴HR题解!HR智商流选手太强啦!CYC也好强%%%发现了len>10大概率是Y B题 dp+bit优化,据LLQ大爷说splay也可以优化,都好强啊.. C题跑 ...
 - bzoj 2434 [Noi2011]阿狸的打字机 AC自动机
			
[Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4001 Solved: 2198[Submit][Status][D ...
 - IBM AppScan 安全漏洞问题修复(.net)
			
按问题类型分类的问题 使用 SQL 注入的认证旁路2 已解密的登录请求3 登录错误消息凭证枚举1 会话标识未更新2 跨站点请求伪造1 Missing "Content-Security-Po ...