Chinaunix首页 | 论坛 | 博客

分类: LINUX

2014-04-01 23:32:55

/**
 *        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.
 */


struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
{
        struct sk_buff *n;


        n = skb + 1;
        /*
        来自:http://blog.csdn.net/echoisland/article/details/6981468
        为了使用套接字缓冲区,内核创建了两个后备高速缓存(looaside cache),它们分别是skbuff_head_cache和skbuff_fclone_cache,协议栈中所使用到的所有的sk_buff结构都是从这两个后备高速缓存中分配出来的。两者的区别在于skbuff_head_cache在创建时指定的单位内存区域的大小是sizeof(struct sk_buff) ,可以容纳任意数目的struct sk_buff,而skbuff_fclone_cache在创建时指定的单位内存区域大小是2*sizeof(struct sk_buff)+sizeof(atomic_t),它的最小区域单位是一对strcut sk_buff和一个引用计数,这一对sk_buff是克隆的,即它们指向同一个数据缓冲区,引用计数值是0,1或2,表示这一对中有几个sk_buff已被使用。如果是在skbuff_fclone_cache中创建,则创建一个struct sk_buff后,还要把紧邻它的一个struct sk_buff的fclone成员置标志SKB_FCLONE_UNAVAILABLE,表示该缓冲区还没有被创建出来,同时置自己的fclone为SKB_FCLONE_ORIG,表示自己可以被克隆。最后置引用计数为1*/
        if (skb->fclone == SKB_FCLONE_ORIG && n->fclone == SKB_FCLONE_UNAVAILABLE) {
                atomic_t *fclone_ref = (atomic_t *) (n + 1);
                n->fclone = SKB_FCLONE_CLONE;         //修改状态.
                atomic_inc(fclone_ref);
        } else {
                n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
                if (!n)
                        return NULL;
                kmemcheck_annotate_bitfield(n, flags1);
                kmemcheck_annotate_bitfield(n, flags2);
                n->fclone = SKB_FCLONE_UNAVAILABLE;                 /*在skbuff_head_cache下又有了不同的含义*/
        }

        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;         //并没有归并到sk_buff的双向链表中.
        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;        /*如果skb释放了head buffer,那么hdr_len被赋值为skb_headroom.既然skb都释放了head buffer,那么下面C(data)还有意义吗?*/
        n->cloned = 1;                         //new->cloned=1
        n->nohdr = 0;
        n->destructor = NULL;
        C(tail);
        C(end);
        C(head);
        C(data);
        C(truesize);
        atomic_set(&n->users, 1);


        atomic_inc(&(skb_shinfo(skb)->dataref));         /* 引用数据缓冲区+1 */
        skb->cloned = 1;                //old->cloned=1


        return n;
#undef C
}

阅读(1702) | 评论(0) | 转发(0) |
0

上一篇:sk_buffer 结构

下一篇:如何使用iptables(一)

给主人留下些什么吧!~~