• skb 添加删除尾部数据


    skb_add_data

      skb_add_data()将指定用户空间的数据添加到SKB的数据缓存区的尾部,操作过程如图3-22所示。如果成功则返回0,否则返回相应的错误码。参数skb为待添加数据的SKB;from为待添加的数据源,指向在用户空间的存储缓存区;copy为待添加数据的长度。

      

    skb_trim

      skb_trim()根据指定长度删除SKB的数据缓存区尾部的数据,如果新长度大于当前长度,则不作处理,操作过程如图3-23所示。调用该函数的前提条件是,待操作的SKB的数据必须是线性存储的。参数skb为待操作的SKB;len为删除尾部数据后剩余的长度。

    pskb_strim

      pskb_trim()与skb_trim()功能类似,也是根据指定长度删除SKB尾部的数据。不同的是,pskb_trim()是skb_trim()的功能超集,不仅可以处理线性数据的SKB,还可以处理非线性的SKB。线性数据的处理过程与skb_trim()相同,非线性数据操作过程如图3-24 和图3-25所示。

    skb_split

      拆分数据函数是把数据区数据拆分成两个存放到另外一个 skb 中,其实拆分数据函数并不复杂,只是一些指针的赋值,和控制。下面看函数实现:

    // skb为原来的skb结构体(将要被拆分的),skb1为拆分后得到的子skb,len为拆分后的skb的新长度
    void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
    {
        int pos = skb_headlen(skb);// pos = skb->len - skb->data_len,pos是skb结构中数据区的有效数据长度
     
        if (len < pos)    // 如果拆分长度小于skb数据区中的有效长度,则调用下面函数
            skb_split_inside_header(skb, skb1, len, pos);// 该函数只拆分skb数据区中的数据
        else  // 反之,如果拆分长度不小于skb数据区中的有效长度,则调用下面函数
            skb_split_no_header(skb, skb1, len, pos);// 拆分skb结构中的分片结构中数据区数据
    }
     
    // 这是只拆分sk_buff结构数据区的数据,其他参数不变,参数:pos则是sk_buff结构数据区中有效数据长度
    static inline void skb_split_inside_header(struct sk_buff *skb,
                           struct sk_buff* skb1,
                           const u32 len, const int pos)
    {
        int i;
        // 这是个把sk_buff结构中有效数据拷贝到新的skb1中,pos为有效数据长度,len为剩下数据长度,得:pos-len为要拷贝的数据长度
            // skb_put(skb1,pos-len)是移动tail指针让skb1结构数据区空出空间来存放将要拷贝的数据,该函数返回tail指针
        skb_copy_from_linear_data_offset(skb, len, skb_put(skb1, pos - len),
                         pos - len);
                // 为了方便理解,把该函数实现代码注释进来
                // skb为要被拆分的sk_buff结构,offset为剩下新的skb数据长度,to为skb1结构中tail指针,len为要拷贝的数据长度
                // static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb,
            //                    const int offset, void *to,
            //                    const unsigned int len)
            // {
            // 从skb要剩下的数据位置开始(即是skb->data+offset,skb->data和skb->data+offset之间的数据是要保留的)
                // to则是tail指针移动前返回的一个位置指针(详细请看skb_put()函数实现),拷贝len长度内容
            //    <span style="white-space:pre">    </span>memcpy(to, skb->data + offset, len);
            //<span style="white-space:pre">    </span>}
            // 如果对sk_buff结构及相关结构体中成员变量了解,则这些代码就非常好理解了。
            // nr_frags为多少个分片数据区,循环把所有分片数据拷贝到skb1中
        for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
            skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i];
        
        //下面做的都是些成员字段拷贝赋值操作,并且设置skb的字段
        skb_shinfo(skb1)->nr_frags = skb_shinfo(skb)->nr_frags;
        skb_shinfo(skb)->nr_frags  = 0;
        skb1->data_len           = skb->data_len;
        skb1->len           += skb1->data_len;
        skb->data_len           = 0;
        skb->len           = len;
        skb_set_tail_pointer(skb, len);// 下面把实现函数代码注释进来,方便理解    
             //    static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
            //    {
            //        // 这是把tail指针移到数据区的最后面
            //        skb->tail = skb->data + offset;    
            //    }
    }
     
     
    // 这是拆分分片结构数据区数据,同理,其他参数不变,参数:pos则是sk_buff结构数据区中有效数据长度
    static inline void skb_split_no_header(struct sk_buff *skb,
                           struct sk_buff* skb1,
                           const u32 len, int pos)
    {
        int i, k = 0;
        // 开始设置sk_buff结构数据区内容
        const int nfrags = skb_shinfo(skb)->nr_frags;
        skb_shinfo(skb)->nr_frags = 0;
        skb1->len          = skb1->data_len = skb->len - len;
        skb->len          = len;
        skb->data_len          = len - pos;
        
        // 这是循环拆分分片结构数据区数据
        for (i = 0; i < nfrags; i++) {
            int size = skb_shinfo(skb)->frags[i].size;
        // 其实拆分,数据区存储不会动,动的只是指向这些数据存储的位置指针
           //  下面都是把skb的一些指向分片结构数据区的指针赋值给skb1中的数据区相关变量
            if (pos + size > len) {
                skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i];
                if (pos < len) {
                    get_page(skb_shinfo(skb)->frags[i].page);
                    skb_shinfo(skb1)->frags[0].page_offset += len - pos;
                    skb_shinfo(skb1)->frags[0].size -= len - pos;
                    skb_shinfo(skb)->frags[i].size    = len - pos;
                    skb_shinfo(skb)->nr_frags++;
                }
                k++;
            } else
                skb_shinfo(skb)->nr_frags++;
            pos += size;
        }
        skb_shinfo(skb1)->nr_frags = k;
    }

    pskb_expand_head

     pskb_pull():

      对于带有frag page的分片skb来说,data指针往下移动,可能会导致线性区越界,因此需要判断是否线性区有足够的空间用来pull操作,如果空间不够,那么需要执行linearize,重构线性区,把一部分frags中的数据移动到线性区中来操作。

    pskb_may_pull():

    主要在使用skb_pull之前来检查线性区buffer有没有足够的数据用于 pull。

     

  • 相关阅读:
    SqlDataReader 和SqlDataAdapter 区别
    【面筋烧烤手册】20210301
    【CSS】组件中怎么对css进行处理的
    【CSS】实现五点布局
    【面筋烧烤手册】20200228
    【JavaScript】Class类
    【面筋烧烤手册】CSS
    【面筋烧烤手册】函数柯里化延伸的知识点
    【PlantAPP】TS在RN的具体应用
    【面筋烧烤手册】网络安全
  • 原文地址:https://www.cnblogs.com/codestack/p/16183078.html
Copyright © 2020-2023  润新知