套接字缓存之skb_clone、pskb_copy、skb_copy
skb_clone–只复制skb描述符本身,如果只修改skb描述符则使用该函数克隆;
pskb_copy–复制skb描述符+线性数据区域(包括skb_shared_info),如果需要修改描述符以及数据则使用该函数复制;
skb_copy–复制所有数据,包括skb描述符+线性数据区域+非线性数据区,如果需要修改描述符和全部数据则使用该函数复制;
以下为三个函数的分析;
1 /** 2 * skb_clone - duplicate an sk_buff 3 * @skb: buffer to clone 4 * @gfp_mask: allocation priority 5 * 6 * Duplicate an &sk_buff. The new one is not owned by a socket. Both 7 * copies share the same packet data but not structure. The new 8 * buffer has a reference count of 1. If the allocation fails the 9 * function returns %NULL otherwise the new buffer is returned. 10 * 11 * If this function is called from an interrupt gfp_mask() must be 12 * %GFP_ATOMIC. 13 */ 14 /* 15 用于修改skb描述符中的某些字段 16 克隆skb,该函数只克隆sk_buff部分 17 数据区域公用(需要递增引用计数) 18 */ 19 struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) 20 { 21 /* 获取到支持克隆的skb */ 22 struct sk_buff_fclones *fclones = container_of(skb, 23 struct sk_buff_fclones, 24 skb1); 25 struct sk_buff *n; 26 27 /* 28 若发送标记有零拷贝,则拷贝用户空间的 29 片段缓存到内核空间 30 */ 31 if (skb_orphan_frags(skb, gfp_mask)) 32 return NULL; 33 34 /* 如果skb可以被克隆,并且克隆引用为1 */ 35 if (skb->fclone == SKB_FCLONE_ORIG && 36 atomic_read(&fclones->fclone_ref) == 1) { 37 /* 待克隆n指向skb2 */ 38 n = &fclones->skb2; 39 /* 增加引用计数 */ 40 atomic_set(&fclones->fclone_ref, 2); 41 } 42 /* 否则,为新克隆的skb分配内存 */ 43 else { 44 if (skb_pfmemalloc(skb)) 45 gfp_mask |= __GFP_MEMALLOC; 46 47 n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); 48 if (!n) 49 return NULL; 50 51 kmemcheck_annotate_bitfield(n, flags1); 52 /* 初始化克隆状态 */ 53 n->fclone = SKB_FCLONE_UNAVAILABLE; 54 } 55 56 /* 调用克隆 */ 57 return __skb_clone(n, skb); 58 }
1 /* 2 用于修改skb描述符和数据缓冲区内容时拷贝 3 skb拷贝,拷贝skb描述符+ 线性数据缓冲区, 4 线性缓冲区以外数据共享 5 */ 6 static inline struct sk_buff *pskb_copy(struct sk_buff *skb, 7 gfp_t gfp_mask) 8 { 9 return __pskb_copy(skb, skb_headroom(skb), gfp_mask); 10 }
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 拷贝skb描述符+ 线性数据缓冲区, 19 线性缓冲区外部数据共享 20 */ 21 struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom, 22 gfp_t gfp_mask, bool fclone) 23 { 24 unsigned int size = skb_headlen(skb) + headroom; 25 int flags = skb_alloc_rx_flag(skb) | (fclone ? SKB_ALLOC_FCLONE : 0); 26 struct sk_buff *n = __alloc_skb(size, gfp_mask, flags, NUMA_NO_NODE); 27 28 if (!n) 29 goto out; 30 31 /* Set the data pointer */ 32 /* 保留头部空间 */ 33 skb_reserve(n, headroom); 34 /* Set the tail pointer and length */ 35 /* 增加尾指针和数据长度 */ 36 skb_put(n, skb_headlen(skb)); 37 /* Copy the bytes */ 38 /* 拷贝线性缓冲区 */ 39 skb_copy_from_linear_data(skb, n->data, n->len); 40 41 /* 设置长度值 */ 42 n->truesize += skb->data_len; 43 n->data_len = skb->data_len; 44 n->len = skb->len; 45 46 /* 若有片段 */ 47 if (skb_shinfo(skb)->nr_frags) { 48 int i; 49 50 /* 片段数据拷贝到内核 */ 51 if (skb_orphan_frags(skb, gfp_mask)) { 52 kfree_skb(n); 53 n = NULL; 54 goto out; 55 } 56 57 /* 复制判断内容 */ 58 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 59 skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; 60 skb_frag_ref(skb, i); 61 } 62 63 /* 片段数 */ 64 skb_shinfo(n)->nr_frags = i; 65 } 66 67 /* 如果有片段链表 */ 68 if (skb_has_frag_list(skb)) { 69 /* 引用片段链表 */ 70 skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; 71 skb_clone_fraglist(n); 72 } 73 74 /* 拷贝头部信息 */ 75 copy_skb_header(n, skb); 76 out: 77 return n; 78 }
1 /** 2 * skb_copy - create private copy of an sk_buff 3 * @skb: buffer to copy 4 * @gfp_mask: allocation priority 5 * 6 * Make a copy of both an &sk_buff and its data. This is used when the 7 * caller wishes to modify the data and needs a private copy of the 8 * data to alter. Returns %NULL on failure or the pointer to the buffer 9 * on success. The returned buffer has a reference count of 1. 10 * 11 * As by-product this function converts non-linear &sk_buff to linear 12 * one, so that &sk_buff becomes completely private and caller is allowed 13 * to modify all the data of returned buffer. This means that this 14 * function is not recommended for use in circumstances when only 15 * header is going to be modified. Use pskb_copy() instead. 16 */ 17 /* 拷贝skb描述符+线性缓冲区+非线性缓冲区 */ 18 struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask) 19 { 20 /* 头部空间长度 */ 21 int headerlen = skb_headroom(skb); 22 23 /* 分配空间= skb空间+ skb以外的数据空间 */ 24 unsigned int size = skb_end_offset(skb) + skb->data_len; 25 struct sk_buff *n = __alloc_skb(size, gfp_mask, 26 skb_alloc_rx_flag(skb), NUMA_NO_NODE); 27 28 if (!n) 29 return NULL; 30 31 /* Set the data pointer */ 32 //保留头部空间 33 skb_reserve(n, headerlen); 34 /* Set the tail pointer and length */ 35 /* 偏移尾部指针修改总长度 */ 36 skb_put(n, skb->len); 37 38 /* 拷贝数据 */ 39 if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len)) 40 BUG(); 41 42 /* 拷贝skb头 */ 43 copy_skb_header(n, skb); 44 return n; 45 }