zoukankan      html  css  js  c++  java
  • pskb_copy skb_clone skb_copy

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

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

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

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

    /**
     *    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:拷贝skb描述符+ 线性数据缓冲区, 线性缓冲区外---非线性区(frags/frag_list)数据共享

     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

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

    上述 使用中都遇到了:

    skb_orphan_frags以及__alloc_skb

     __alloc_skb:

    算了 下次再看吧;

    http代理服务器(3-4-7层代理)-网络事件库公共组件、内核kernel驱动 摄像头驱动 tcpip网络协议栈、netfilter、bridge 好像看过!!!! 但行好事 莫问前程 --身高体重180的胖子
  • 相关阅读:
    Linux 多线程编程 实例 1
    面试题-链表反转c实现
    information_schema.TABLES
    mongodb遇到的错误
    MySQL优化的奇技淫巧之STRAIGHT_JOIN
    mongodb安装
    XtraBackup安装
    提高mysql千万级大数据SQL查询优化30条经验(Mysql索引优化注意)
    我用 TypeScript 语言的七个月
    Grunt之添加文件监视:Grunt-watch (已备份)
  • 原文地址:https://www.cnblogs.com/codestack/p/14284277.html
Copyright © 2011-2022 走看看