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. springBoot按条件装配:Condition

    编码格式转换器接口 package com.boot.condition.bootconditionconfig.converter; /** * 编码格式转换器接口 */ public interf ...

  2. 2.StringBuffer:线程安全的可变字符串序列

    一.String.StringBuffer和StringBuilder的区别 1.String是内容不可变的,而StringBuffer和StringBuilder都是内容可变的. 2.StringB ...

  3. BZOJ 2306 幸福路径(DP)

    题解来源:http://www.cnblogs.com/jianglangcaijin/p/3799494.html 最后必然是走了一条链,或者是一个环(一直绕),或者是一条链加一个环.设f[i][j ...

  4. 【bzoj4922】[Lydsy六月月赛]Karp-de-Chant Number 贪心+背包dp

    题目描述 给出 $n$ 个括号序列,从中选出任意个并将它们按照任意顺序连接起来,求以这种方式得到匹配括号序列的最大长度. 输入 第一行包含一个正整数n(1<=n<=300),表示括号序列的 ...

  5. POJ3261:Milk Patterns——题解

    http://poj.org/problem?id=3261 给一个序列,求至少出现 k 次的最长重复子串,这 k 个子串可以重叠. 论文题+傻逼题. 上一道题(POJ1743)会做即可. 还是二分长 ...

  6. 洛谷 P1640 [SCOI2010]连续攻击游戏 解题报告

    P1640 [SCOI2010]连续攻击游戏 题目描述 lxhgww最近迷上了一款游戏,在游戏里,他拥有很多的装备,每种装备都有2个属性,这些属性的值用[1,10000]之间的数表示.当他使用某种装备 ...

  7. HDU.2640 Queuing (矩阵快速幂)

    HDU.2640 Queuing (矩阵快速幂) 题意分析 不妨令f为1,m为0,那么题目的意思为,求长度为n的01序列,求其中不含111或者101这样串的个数对M取模的值. 用F(n)表示串长为n的 ...

  8. React注释

    React中注释有以下三种 var content = ( <Nav> {/* 一般注释, 用 {} 包围 */} <Person /* 多 行 注释 */ name={window ...

  9. POSIX.2 正则表达式

    By francis_hao    Oct 1,2017   这里的正则表达式主要是指扩展正则,也就是egrep(grep -e)用到的正则表达式. 字符 含义 类别说明 | 分割分支,正则表达式会去 ...

  10. Redrain 通用菜单控件使用方法和说明(附源码和demo)

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42889709 大概半年前我写过博客说明怎么改造duilib的原代Menu ...