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的更多相关文章

  1. skb管理函数之skb_clone、pskb_copy、skb_copy

    skb_clone--只复制skb描述符本身,如果只修改skb描述符则使用该函数克隆: pskb_copy--复制skb描述符+线性数据区域(包括skb_shared_info),如果需要修改描述符以 ...

  2. 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 ...

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

    一.时间管理函数 μC/OS-Ⅲ系统提供一些列时间管理服务函数: 1.OSTimeDly():任务延时n个时钟节拍. 2.OSTimeDlyHMSM():任务延时指定的时间,采用“时:分:秒:毫秒”方 ...

  4. 内存管理运算符new delete与内存管理函数malloc free的区别——已经他们对对象创建的过程。

    (1)内存管理函数与内存管理运算符的区别 内存管理函数有内存分配函数,malloc calloc realloc 以及内存释放函数free. 内存管理运算符有new 和delete. 两种内存管理方式 ...

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

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #functools:管理函数工具 #作用:处理其他函数的函数 #版 ...

  6. POSIX多线程——基本线程管理函数介绍

    POSIX基本的几个线程管理函数见下表: ------------------------------------------------------------------------------- ...

  7. [图形学] Chp9 三维几何变换--栈处理函数与矩阵管理函数的区别

    矩阵管理函数:glLoadIdentity()是把当前活动矩阵设置为单位矩阵. 栈处理函数:glPushMatrix()是将当前活动的变换矩阵复制一份,压入栈顶:glPopMatrix()是破坏当前活 ...

  8. C++内存管理-重载内存管理函数

    记录学习的点点滴滴,参考侯捷<<C++内存管理>> 我们先重载一下C++的几个内存管理函数 operator new, operator new[], operator del ...

  9. 【教训】null == '',改造ThinkSNS 系统里面的一个缓存管理函数S()后,留下一个大bug

    本来想简化 ThinkSNS 系统里面的一个缓存管理函数: <?php /** * 用来对应用缓存信息的读.写.删除 * $expire = null/0 表示永久缓存,否则为缓存有效期 */ ...

随机推荐

  1. 【Python】python之set

    阅读目录 一.set集合介绍 二.集合的方法 1.s.add()添加元素 3.s.copy()浅拷贝 4.s.difference(b) 5.s.difference_update(b) 6.s.di ...

  2. 【以前的空间】link cut tree

    这篇文章讲的很好很详细,但是写了几天后发现似乎是挺残的版本. 2049: [Sdoi2008]Cave 洞穴勘测 3282: Tree 2002: [Hnoi2010]Bounce 弹飞绵羊 1036 ...

  3. MHA选择主库源码解析

    知数堂第5期MySQL实战班学员,第10期MySQL优化班学员,现任职助教. MHA在选择新的主库之前,会先把活着的slave分为几个数组,分别为latest(最靠前的slave数组),pref(优先 ...

  4. 项目管理---git----快速使用git笔记(一)------git的简单介绍

    最近svn代码管理服务器崩溃了,切换到git来运作. 经过几天的使用,感觉很不错. 尤其是代码合并到正式版本之前 可以对代码进行 code review. 这样能很好的保证团队的代码质量和一些重复代码 ...

  5. java oracle clob string 大字符串存储【转】

    单位用到了oracle存储string类型到数据库里的clob,上网查看资料找到解决方案.如下: public class ClobTest { static String url = "j ...

  6. ACE线程管理机制-线程的创建与管理

    转载于:http://www.cnblogs.com/TianFang/archive/2006/12/04/581369.html 有过在不同的操作系统下用c++进行过多线程编程的朋友对那些线程处理 ...

  7. im-switch -s ibus错误:Error: no configuration file "ibus" exists.

    在虚拟机上安装Ubuntu14.04 后安装ibus输入法,万万没想到在切换输入法的时候居然出错了! 无语了,再网上查了一下,这个错误出现的还是比较少的. 先说Ubuntu输入法(ibus)安装的一般 ...

  8. CCPC-Winter Camp div2 day1

    A:机器人 传送门:https://www.zhixincode.com/contest/1/problem/A 题意:地图是由A.B两根线组成的,机器人一开始是在A线上的S点,他初始时可以选择任意方 ...

  9. 【题解】互不侵犯 SCOI 2005 BZOJ 1087 插头dp

    以前没学插头dp的时候觉得这题贼难,根本不会做,学了才发现原来是一裸题. 用二进制表示以前的格子的状态,0表示没放国王,1表示放了国王. 假设当前位置为(x,y),需要记录的是(x-1,y-1)至(x ...

  10. 求前n项正整数的倒数和

    求前n项正整数的倒数和 前n项正整数的和是一个发散的序列,学过高等数学的这个都知道.所以它没有一个精确的公式,但是近似的公式是有的: 1 + 1/2 + 1/3 + …… + 1/n ≍ ln n + ...