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. 封装一个jquery库

    现在Javascript库海量,流行的也多,比如jQuery,YUI等,虽然功能强大,但也是不万能的,功能不可能涉及方方面面,自己写一个的JS库是对这些的补充,很多也比较实用,把应用到项目中中去也比较 ...

  2. hdu 1392 Surround the Trees (凸包)

    Surround the Trees Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  3. [CTSC2014]企鹅QQ hash

    ~~~题面~~~ 题解: 通过观察可以发现,其实题目就是要求长度相等的字符串中有且只有1位字符不同的 ”字符串对“ 有多少. 因为数据范围不大, 所以考虑一种暴力至极的方法. 我们枚举是哪一位不同,然 ...

  4. POJ1269:Intersecting Lines——题解

    http://poj.org/problem?id=1269 题目大意:给四个点,求前两个点所构成的直线和后两个点所构成的直线的位置关系(平行,重合,相交),如果是相交,输出交点坐标. ——————— ...

  5. POJ3648:Wedding——题解(配2-SAT简易讲解)

    http://poj.org/problem?id=3648 (在家,而且因为2-SAT写的不明不白的,所以这篇详细写) 题目大意: 有一对新人结婚,邀请了n-1 对夫妇去参加婚礼.婚礼上所有人要坐在 ...

  6. BZOJ1591 & 洛谷2924:[USACO2008 DEC]Largest Fence 最大的围栏——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=1591 https://www.luogu.org/problemnew/show/P2924#sub ...

  7. BZOJ2588:Count on a tree——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你 ...

  8. 51NOD 1038:X^A Mod P——题解

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1038 X^A mod P = B,其中P为质数.给出P和A B,求< ...

  9. ucenter搭建

    使用xftp传到虚拟机.解压[root@ygy130 ~]# unzip -o -d ./Ucenter_1.6 UCenter_1.6.0_SC_UTF8.zip [root@ygy130 ~]# ...

  10. 负载均衡配置(基于Nginx)

    以下是基于nginx进行负载均衡配置的流程: 服务器配置如下: 1.  安装nginx的服务器:192.168.1.1 2.  nginx配置负载均衡位置及端口:192.168.1.1 80端口 3. ...