skb_clone–只复制skb描述符本身,如果只修改skb描述符则使用该函数克隆;

pskb_copy–复制skb描述符+线性数据区域(包括skb_shared_info),如果需要修改描述符以及数据则使用该函数复制;

skb_copy–复制所有数据,包括skb描述符+线性数据区域+非线性数据区,如果需要修改描述符和全部数据则使用该函数复制;

以下为三个函数的分析;

 /**
* skb_clone - duplicate an sk_buff
* @skb: buffer to clone
* @gfp_mask: allocation priority
*
* Duplicate an &sk_buff. The new one is not owned by a socket. Both
* copies share the same packet data but not structure. The new
* buffer has a reference count of 1. If the allocation fails the
* function returns %NULL otherwise the new buffer is returned.
*
* If this function is called from an interrupt gfp_mask() must be
* %GFP_ATOMIC.
*/
/*
用于修改skb描述符中的某些字段
克隆skb,该函数只克隆sk_buff部分
数据区域公用(需要递增引用计数)
*/
struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
{
/* 获取到支持克隆的skb */
struct sk_buff_fclones *fclones = container_of(skb,
struct sk_buff_fclones,
skb1);
struct sk_buff *n; /*
若发送标记有零拷贝,则拷贝用户空间的
片段缓存到内核空间
*/
if (skb_orphan_frags(skb, gfp_mask))
return NULL; /* 如果skb可以被克隆,并且克隆引用为1 */
if (skb->fclone == SKB_FCLONE_ORIG &&
atomic_read(&fclones->fclone_ref) == ) {
/* 待克隆n指向skb2 */
n = &fclones->skb2;
/* 增加引用计数 */
atomic_set(&fclones->fclone_ref, );
}
/* 否则,为新克隆的skb分配内存 */
else {
if (skb_pfmemalloc(skb))
gfp_mask |= __GFP_MEMALLOC; n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
if (!n)
return NULL; kmemcheck_annotate_bitfield(n, flags1);
/* 初始化克隆状态 */
n->fclone = SKB_FCLONE_UNAVAILABLE;
} /* 调用克隆 */
return __skb_clone(n, skb);
}
 /*
用于修改skb描述符和数据缓冲区内容时拷贝
skb拷贝,拷贝skb描述符+ 线性数据缓冲区,
线性缓冲区以外数据共享
*/
static inline struct sk_buff *pskb_copy(struct sk_buff *skb,
gfp_t gfp_mask)
{
return __pskb_copy(skb, skb_headroom(skb), gfp_mask);
}
 /**
* __pskb_copy_fclone - create copy of an sk_buff with private head.
* @skb: buffer to copy
* @headroom: headroom of new skb
* @gfp_mask: allocation priority
* @fclone: if true allocate the copy of the skb from the fclone
* cache instead of the head cache; it is recommended to set this
* to true for the cases where the copy will likely be cloned
*
* Make a copy of both an &sk_buff and part of its data, located
* in header. Fragmented data remain shared. This is used when
* the caller wishes to modify only header of &sk_buff and needs
* private copy of the header to alter. Returns %NULL on failure
* or the pointer to the buffer on success.
* The returned buffer has a reference count of 1.
*/
/*
拷贝skb描述符+ 线性数据缓冲区,
线性缓冲区外部数据共享
*/
struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
gfp_t gfp_mask, bool fclone)
{
unsigned int size = skb_headlen(skb) + headroom;
int flags = skb_alloc_rx_flag(skb) | (fclone ? SKB_ALLOC_FCLONE : );
struct sk_buff *n = __alloc_skb(size, gfp_mask, flags, NUMA_NO_NODE); if (!n)
goto out; /* Set the data pointer */
/* 保留头部空间 */
skb_reserve(n, headroom);
/* Set the tail pointer and length */
/* 增加尾指针和数据长度 */
skb_put(n, skb_headlen(skb));
/* Copy the bytes */
/* 拷贝线性缓冲区 */
skb_copy_from_linear_data(skb, n->data, n->len); /* 设置长度值 */
n->truesize += skb->data_len;
n->data_len = skb->data_len;
n->len = skb->len; /* 若有片段 */
if (skb_shinfo(skb)->nr_frags) {
int i; /* 片段数据拷贝到内核 */
if (skb_orphan_frags(skb, gfp_mask)) {
kfree_skb(n);
n = NULL;
goto out;
} /* 复制判断内容 */
for (i = ; i < skb_shinfo(skb)->nr_frags; i++) {
skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
skb_frag_ref(skb, i);
} /* 片段数 */
skb_shinfo(n)->nr_frags = i;
} /* 如果有片段链表 */
if (skb_has_frag_list(skb)) {
/* 引用片段链表 */
skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
skb_clone_fraglist(n);
} /* 拷贝头部信息 */
copy_skb_header(n, skb);
out:
return n;
}
 /**
* skb_copy - create private copy of an sk_buff
* @skb: buffer to copy
* @gfp_mask: allocation priority
*
* Make a copy of both an &sk_buff and its data. This is used when the
* caller wishes to modify the data and needs a private copy of the
* data to alter. Returns %NULL on failure or the pointer to the buffer
* on success. The returned buffer has a reference count of 1.
*
* As by-product this function converts non-linear &sk_buff to linear
* one, so that &sk_buff becomes completely private and caller is allowed
* to modify all the data of returned buffer. This means that this
* function is not recommended for use in circumstances when only
* header is going to be modified. Use pskb_copy() instead.
*/
/* 拷贝skb描述符+线性缓冲区+非线性缓冲区 */
struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
{
/* 头部空间长度 */
int headerlen = skb_headroom(skb); /* 分配空间= skb空间+ skb以外的数据空间 */
unsigned int size = skb_end_offset(skb) + skb->data_len;
struct sk_buff *n = __alloc_skb(size, gfp_mask,
skb_alloc_rx_flag(skb), NUMA_NO_NODE); if (!n)
return NULL; /* Set the data pointer */
//保留头部空间
skb_reserve(n, headerlen);
/* Set the tail pointer and length */
/* 偏移尾部指针修改总长度 */
skb_put(n, skb->len); /* 拷贝数据 */
if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len))
BUG(); /* 拷贝skb头 */
copy_skb_header(n, skb);
return n;
}

skb管理函数之skb_clone、pskb_copy、skb_copy的更多相关文章

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

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

  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. 【SQLAlchemy】SQLAlchemy技术文档(中文版)(上)

    1.版本检查 import sqlalchemy sqlalchemy.__version__ 2.连接 from sqlalchemy import create_engine engine = c ...

  2. 【hdu3555】Bomb 数位dp

    题目描述 求 1~N 内包含数位串 “49” 的数的个数. 输入 The first line of input consists of an integer T (1 <= T <= 1 ...

  3. hdu 2722 Here We Go(relians) Again (最短路径)

    Here We Go(relians) Again Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Jav ...

  4. 转:Scipy入门

    Scipy入门 转:http://notes.yeshiwei.com/scipy/getting_started.html 本章节主要内容来自 Getting Started .翻译的其中一部分,并 ...

  5. [LOJ2540] [PKUWC2018] 随机算法

    题目链接 LOJ:https://loj.ac/problem/2540 Solution 写的时候脑子不太清醒码了好长然后时间\(LOJ\)垫底... 反正随便状压\(dp\)一下就好了,设\(f[ ...

  6. 你可能使用了Spring最不推荐的注解方式

    前言 使用Spring框架最核心的两个功能就是IOC和AOP.IOC也就是控制反转,我们将类的实例化.依赖关系等都交由Spring来处理,以达到解耦合.利用复用.利于测试.设计出更优良程序的目的.而对 ...

  7. 洛谷 P2860 [USACO06JAN]冗余路径Redundant Paths 解题报告

    P2860 [USACO06JAN]冗余路径Redundant Paths 题目描述 为了从F(1≤F≤5000)个草场中的一个走到另一个,贝茜和她的同伴们有时不得不路过一些她们讨厌的可怕的树.奶牛们 ...

  8. 洛谷 P2323 [HNOI2006]公路修建问题 解题报告

    P2323 [HNOI2006]公路修建问题 题目描述 输入输出格式 输入格式: 在实际评测时,将只会有m-1行公路 输出格式: 思路: 二分答案 然后把每条能加的大边都加上,然后加小边 但在洛谷的题 ...

  9. 背景建模技术(二):BgsLibrary的框架、背景建模的37种算法性能分析、背景建模技术的挑战

    背景建模技术(二):BgsLibrary的框架.背景建模的37种算法性能分析.背景建模技术的挑战 1.基于MFC的BgsLibrary软件下载 下载地址:http://download.csdn.ne ...

  10. VC使用sqlite

    SQLite可以到官方站点(http://www.sqlite.org/download.html)下载:Linux,Mac OS X, Windows下的已编译文件以及源代码.帮助文档. SQLit ...