免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 16489 | 回复: 18

【班门弄斧一下】skb_clone分析 [复制链接]

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2011-03-01 21:58 |显示全部楼层
1、skb_clone()
Skb_clone()函数只是复制sk_buff结构,并不复制skb的数据缓冲区。Clone后的sk_buff结构与原始的sk_buff指向同一数据缓冲区。原始的和clone后的skb描述符的cloned值都会被置1,clone的skb描述符的users值置1,同时数据缓冲区的引用计数dataref增加1。
  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. struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
  15. {
  16.     struct sk_buff *n;

  17.     /* n指向被clone的skb */
  18.     n = skb + 1;
  19.     /* 判断原始skb是否是从skbuff_fclone_cache 缓冲区中分配的,从skbuff_fclone_cache 分配将预先为clone的skb分配好内存,同时判定该预先分配的clone skb是否被使用 */
  20.     if (skb->fclone == SKB_FCLONE_ORIG &&
  21.      n->fclone == SKB_FCLONE_UNAVAILABLE) {
  22.         /* 预先从skbuff_fclone_cache 中分配的skb结构,且未使用,则增加dataref计数*/
  23.         atomic_t *fclone_ref = (atomic_t *) (n + 1);
  24.         n->fclone = SKB_FCLONE_CLONE; /* 置clone的skb中fclone值为SKB_FCLONE_CLONE ,标明其数据区指向原始skb同一数据区 */
  25.         atomic_inc(fclone_ref);
  26.     } else {
  27.         /* 主skb并未同时分配clone skb的情况,将重新独立分配skb结构作为clone的skb */
  28.         n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
  29.         if (!n)
  30.             return NULL;

  31.         kmemcheck_annotate_bitfield(n, flags1);
  32.         kmemcheck_annotate_bitfield(n, flags2);
  33.         /* 指明该clone的skb并未分配独立的数据缓冲区 */
  34.         n->fclone = SKB_FCLONE_UNAVAILABLE;
  35.     }
  36.     /* 完成后续的skb结构体的复制工作 */
  37.     return __skb_clone(n, skb);
  38. }


  39. /*
  40. * You should not add any new code to this function. Add it to
  41. * __copy_skb_header above instead.
  42. */
  43. static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
  44. {
  45. #define C(x) n->x = skb->x

  46.     n->next = n->prev = NULL;
  47.     n->sk = NULL;
  48.     /* copy 头部字段,详细请参考源代码,很简单 */
  49.     __copy_skb_header(n, skb);

  50.     C(len);
  51.     C(data_len);
  52.     C(mac_len);
  53.     n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
  54.     n->cloned = 1;
  55.     n->nohdr = 0;
  56.     n->destructor = NULL;
  57.     C(tail);
  58.     C(end);
  59.     C(head);
  60.     C(data);
  61.     C(truesize);
  62.     /* 设置skb描述符的users为1 */
  63.     atomic_set(&n->users, 1);

  64.     /* 增加shinfo中dataref的引用计数,因为clone的skb与原始skb指向同一数据缓冲区*/
  65.     atomic_inc(&(skb_shinfo(skb)->dataref));
  66.     skb->cloned = 1; /* 指明原始skb是被clone过的 */

  67.     return n;
  68. #undef C
  69. }
复制代码
特别说明,skb_clone()函数复制的只是skb描述符,而复制后的skb与原始skb指向的是同一数据缓冲区,由于数据缓冲区并未加什么同步锁机制,因此skb_clone()操作的skb结构的数据缓冲区是不能被修改的。

评分

参与人数 1可用积分 +30 收起 理由
Godbach + 30 感谢分享

查看全部评分

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
发表于 2011-03-01 22:28 |显示全部楼层
dreamice 兄的好文。
等了半天没敢回复,怕是后面还有呢。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2011-03-01 23:34 |显示全部楼层
dreamice 兄的好文。
等了半天没敢回复,怕是后面还有呢。
Godbach 发表于 2011-03-01 22:28



    一天写点呢,呵呵

论坛徽章:
0
发表于 2011-03-02 00:29 |显示全部楼层
支持下 :)

论坛徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16赛季CBA联赛之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金鸡报晓
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年纪念徽章
日期:2016-11-09 13:19:1015-16赛季CBA联赛之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序设计版块每日发帖之星
日期:2015-12-03 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-09 06:20:002015亚冠之吉达阿赫利
日期:2015-07-03 08:39:42
发表于 2011-03-02 14:13 |显示全部楼层
学习

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2011-03-02 16:23 |显示全部楼层
晚上继续,不过楼层已经被占了

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
发表于 2011-03-02 16:34 |显示全部楼层
晚上继续,不过楼层已经被占了
dreamice 发表于 2011-03-02 16:23

你当时应该预留几个嘛

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2011-03-02 21:03 |显示全部楼层
本帖最后由 dreamice 于 2011-03-02 21:04 编辑

2、pskb_copy()
与skb_copy()不同,当一个函数不仅需要修改skb描述符,而且需要修改其缓冲区中的数据时,就需要复制缓冲区的数据。如果需要修改的数据在skb->head到skb->end之间,即数据是一个线性空间的数据时,便可调用pskb_copy()函数来完成此操作。

  1. /**

  2. * pskb_copy - create copy of an sk_buff with private head.

  3. * @skb: buffer to copy

  4. * @gfp_mask: allocation priority

  5. *

  6. * Make a copy of both an &sk_buff and part of its data, located

  7. * in header. Fragmented data remain shared. This is used when

  8. * the caller wishes to modify only header of &sk_buff and needs

  9. * private copy of the header to alter. Returns %NULL on failure

  10. * or the pointer to the buffer on success.

  11. * The returned buffer has a reference count of 1.

  12. */



  13. struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)

  14. {

  15.        /*

  16.         * Allocate the copy buffer

  17.         */

  18.        struct sk_buff *n;

  19. /* 先申请skb描述符字段的内存空间,在这种情况下,skb描述符是不能继用预先分配的skb描述符的 */

  20. #ifdef NET_SKBUFF_DATA_USES_OFFSET

  21.        n = alloc_skb(skb->end, gfp_mask);

  22. #else

  23.        n = alloc_skb(skb->end - skb->head, gfp_mask);

  24. #endif

  25.        if (!n)

  26.               goto out;



  27.        /* Set the data pointer */

  28.     /* 设置数据指针 */

  29.        skb_reserve(n, skb->data - skb->head);

  30.        /* Set the tail pointer and length */

  31.     /* 设置skb->tail指针和skb->len 长度 */

  32.        skb_put(n, skb_headlen(skb));

  33.        /* Copy the bytes */

  34.     /* 拷贝线性空间的数据 */

  35.        skb_copy_from_linear_data(skb, n->data, n->len);

  36.    

  37.     /* 对share info结构进行拷贝,并设置相关字段的值 */

  38.        n->truesize += skb->data_len;

  39.        n->data_len = skb->data_len;

  40.        n->len = skb->len;



  41.        if (skb_shinfo(skb)->nr_frags) {

  42.               int i;



  43.         /*在share info中有数据的情况下,拷贝share字段,特别注意:这里并没有拷贝share info中的数据 */

  44.               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {

  45.                      skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];

  46.                      get_page(skb_shinfo(n)->frags[i].page);

  47.               }

  48.               skb_shinfo(n)->nr_frags = i;

  49.        }



  50.        if (skb_has_frags(skb)) {

  51.               skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;

  52.               skb_clone_fraglist(n);

  53.        }



  54.     /* 拷贝skb头部的相关字段 */

  55.        copy_skb_header(n, skb);

  56. out:

  57.        return n;

  58. }



  59. /**

  60. * skb_reserve - adjust headroom

  61. * @skb: buffer to alter

  62. * @len: bytes to move

  63. *

  64. * Increase the headroom of an empty &sk_buff by reducing the tail

  65. * room. This is only allowed for an empty buffer.

  66. */

  67. static inline void skb_reserve(struct sk_buff *skb, int len)

  68. {

  69.        skb->data += len;

  70.        skb->tail += len;

  71. }
复制代码
特别说明:pskb_copy()与skb_copy()更重量级一些,他不仅仅拷贝skb描述符,还需要拷贝skb->data指向的数据,但他并不拷贝share info指向的非线性数据,新skb的share info指向与原始skb的share info相同的数据。

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
发表于 2011-03-02 21:05 |显示全部楼层
你当时应该预留几个嘛
Godbach 发表于 2011-03-02 16:34



    你能提升楼层不?不行等我写完了合并到第一楼去,呵呵

论坛徽章:
36
IT运维版块每日发帖之星
日期:2016-04-10 06:20:00IT运维版块每日发帖之星
日期:2016-04-16 06:20:0015-16赛季CBA联赛之广东
日期:2016-04-16 19:59:32IT运维版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-19 06:20:00每日论坛发贴之星
日期:2016-04-19 06:20:00IT运维版块每日发帖之星
日期:2016-04-25 06:20:00IT运维版块每日发帖之星
日期:2016-05-06 06:20:00IT运维版块每日发帖之星
日期:2016-05-08 06:20:00IT运维版块每日发帖之星
日期:2016-05-13 06:20:00IT运维版块每日发帖之星
日期:2016-05-28 06:20:00每日论坛发贴之星
日期:2016-05-28 06:20:00
发表于 2011-03-03 10:46 |显示全部楼层
这个估计得问一下管理员了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP