0
点赞
收藏
分享

微信扫一扫

pskb_copy skb_clone skb_copy

  刚离开时,总想着四海为家,仗剑行走天涯!一副数风流人物还看今朝!
  惊涛拍浪时,偶而有个电话,却又烦唠叨而言它!殊不知以后也没多少时间听父母叨叨了!!!

不哆嗦了!!今天查bug 又涉及到了skb_clone 以及skb_copy ;那就来看看吧!顺便做做笔记,免得总是忘了,好记性不如乱博客

对skb拷贝无非就是 skb的描述符填充字段;线性数据区 linear  非线性区frags  以及frags_list

 

 skb_copy:拷贝skb描述符+线性缓冲区+非线性缓冲区 

pskb_copy skb_clone skb_copy_数据区pskb_copy skb_clone skb_copy_数据区_02

/**
* 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); /* 头部空间长度 head---->data之间长度*/
// skb空间+ skb以外的数据空间
unsigned int size = skb_end_offset(skb) + skb->data_len; // head----end + frag/frag_list的数据长度
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);
/* 拷贝数据 从skb的data 偏移 -headerlen 开始 copy 长度为 headerlen+skb->len */
if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len))
BUG();
//copy header
copy_skb_header(n, skb);
return n;
}

View Code

pskb_copy skb_clone skb_copy_数据_03

 pskb_copy skb_clone skb_copy_数据区_04

 

 

 

pskb:拷贝skb描述符+ 线性数据缓冲区, 线性缓冲区外---非线性区(frags/frag_list)数据共享

pskb_copy skb_clone skb_copy_数据区pskb_copy skb_clone skb_copy_数据区_02

1 /**
2 * __pskb_copy_fclone - create copy of an sk_buff with private head.
3 * @skb: buffer to copy
4 * @headroom: headroom of new skb
5 * @gfp_mask: allocation priority
6 * @fclone: if true allocate the copy of the skb from the fclone
7 * cache instead of the head cache; it is recommended to set this
8 * to true for the cases where the copy will likely be cloned
9 *
10 * Make a copy of both an &sk_buff and part of its data, located
11 * in header. Fragmented data remain shared. This is used when
12 * the caller wishes to modify only header of &sk_buff and needs
13 * private copy of the header to alter. Returns %NULL on failure
14 * or the pointer to the buffer on success.
15 * The returned buffer has a reference count of 1.
16 */
17
18 struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
19 gfp_t gfp_mask, bool fclone)
20 {
21 unsigned int size = skb_headlen(skb) + headroom;
22 int flags = skb_alloc_rx_flag(skb) | (fclone ? SKB_ALLOC_FCLONE : 0);
23 struct sk_buff *n = __alloc_skb(size, gfp_mask, flags, NUMA_NO_NODE);
24
25 if (!n)
26 goto out;
27
28 /* Set the data pointer 保留头部空间 */
29 skb_reserve(n, headroom);
30 /* Set the tail pointer and length 修正尾指针和数据长度*/
31 skb_put(n, skb_headlen(skb));
32 /* Copy the bytes 拷贝线性缓冲区 从 skb->data 开始 长度为n->len 拷贝到 n->data*/
33 skb_copy_from_linear_data(skb, n->data, n->len);
34 //SKB_TRUESIZE//truesize 大小为: 线性区数据+非线性区数据+sizeof(sk_buff) + sizeof(skb_shared_info)
35 n->truesize += skb->data_len;
36 n->data_len = skb->data_len;
37 n->len = skb->len;
38
39 if (skb_shinfo(skb)->nr_frags) {/* 若有片段 */
40 int i;
41
42 if (skb_orphan_frags(skb, gfp_mask)) {
43 kfree_skb(n);
44 n = NULL;
45 goto out;
46 }
47 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
48 skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];//n->frags 执行skb的frags --- 共享 数据
49 skb_frag_ref(skb, i);//对page增加引用计数
50 }
51 skb_shinfo(n)->nr_frags = i;
52 }
53
54 if (skb_has_frag_list(skb)) {
55 skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
56 skb_clone_fraglist(n);// 增加每个skb的users计数
57 }
58 //COPY HEAD FILED字段
59 copy_skb_header(n, skb);
60 out:
61 return n;
62 }

View Code

pskb_copy skb_clone skb_copy_描述符_07

 pskb_copy skb_clone skb_copy_数据区_08

 

 

 

skb_clone:由skb_clone()函数克隆一个skb,然后共享其他数据。虽然可以提高效率,但是存在一个很大的缺陷,就是当有克隆skb指向共享数据区是,那么共享数据区的数据就不能被修改了。所以说如果只是让多个skb查看共享数据区内容,则可以用skb_clone()函数来克隆这几个skb出来,提高效率。但如果涉及到某个skb要修改sk_buff结构的数据区,则必须要用pskb_copy  skb_copy这几个函数来克隆拷贝出skb

pskb_copy skb_clone skb_copy_数据_09

 

 

pskb_copy skb_clone skb_copy_数据区pskb_copy skb_clone skb_copy_数据区_02

/**
* 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可以被克隆,fclone---SKB_FCLONE_ORIG标志在allock_skb时 设置 通过 flag 是否 允许 SKB_ALLOC_FCLONE 来实现;
并且克隆引用为1 */
if (skb->fclone == SKB_FCLONE_ORIG &&
atomic_read(&fclones->fclone_ref) == 1) {
n = &fclones->skb2;
atomic_set(&fclones->fclone_ref, 2);
} else {
if (skb_pfmemalloc(skb))
gfp_mask |= __GFP_MEMALLOC;

n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
if (!n)//为新克隆的skb分配内存
return NULL;

kmemcheck_annotate_bitfield(n, flags1);
n->fclone = SKB_FCLONE_UNAVAILABLE;
}

return __skb_clone(n, skb);
}
/*
* You should not add any new code to this function. Add it to
* __copy_skb_header above instead.
*/
static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
{
#define C(x) n->x = skb->x

n->next = n->prev = NULL;
n->sk = NULL;
__copy_skb_header(n, skb);

C(len);
C(data_len);
C(mac_len);
n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
n->cloned = 1;
n->nohdr = 0;
n->destructor = NULL;
C(tail);
C(end);
C(head);
C(head_frag);
C(data);
C(truesize);
atomic_set(&n->users, 1);

atomic_inc(&(skb_shinfo(skb)->dataref));
skb->cloned = 1;

return n;
#undef C
}
/*
atomic_inc(&(skb_shinfo(skb)->dataref));这个简单的说就是,因为sk_buff的数据区和分片结构是一体的,连内存申请和释放都是一起的。而dataref是分片结构skb_shared_info中的一个 表示sk_buff的数据区和分片结构被多少skb共享的 成员字段。这里调用atomic_inc()函数让该引用计数器自增,表明克隆skb对sk_buff数据区和分片结构的共享引用。*/
skb->cloned = 1;表明这是个克隆的skb结构体

View Code

 pskb_copy skb_clone skb_copy_数据区_12

 

 

上述 使用中都遇到了:

skb_orphan_frags以及__alloc_skb

 __alloc_skb:

算了 下次再看吧;

http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子

举报

相关推荐

0 条评论