SKB几个复制函数的区别

2023-11-03 20:18
文章标签 函数 几个 区别 复制 skb

本文主要是介绍SKB几个复制函数的区别,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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.  */
  1. struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
  2. {
  3.     struct sk_buff *n;

  4.     /* n指向被clone的skb */
  5.     n = skb + 1;
  6.     /* 判断原始skb是否是从skbuff_fclone_cache 缓冲区中分配的,从skbuff_fclone_cache 分配将预先为clone的skb分配好内存,同时判定该预先分配的clone skb是否被使用 */
  7.     if (skb->fclone == SKB_FCLONE_ORIG &&
  8.      n->fclone == SKB_FCLONE_UNAVAILABLE) {
  9.         /* 预先从skbuff_fclone_cache 中分配的skb结构,且未使用,则增加dataref计数*/
  10.         atomic_t *fclone_ref = (atomic_t *) (n + 1);
  11.         n->fclone = SKB_FCLONE_CLONE; /* 置clone的skb中fclone值为SKB_FCLONE_CLONE ,标明其数据区指向原始skb同一数据区 */
  12.         atomic_inc(fclone_ref);
  13.     } else {
  14.         /* 主skb并未同时分配clone skb的情况,将重新独立分配skb结构作为clone的skb */
  15.         n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
  16.         if (!n)
  17.             return NULL;

  18.         kmemcheck_annotate_bitfield(n, flags1);
  19.         kmemcheck_annotate_bitfield(n, flags2);
  20.         /* 指明该clone的skb并未分配独立的数据缓冲区 */
  21.         n->fclone = SKB_FCLONE_UNAVAILABLE;
  22.     }
  23.     /* 完成后续的skb结构体的复制工作 */
  24.     return __skb_clone(n, skb);
  25. }


  26. /*
  27.  * You should not add any new code to this function. Add it to
  28.  * __copy_skb_header above instead.
  29.  */
  30. static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb)
  31. {
  32. #define C(x) n->x = skb->x

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

  37.     C(len);
  38.     C(data_len);
  39.     C(mac_len);
  40.     n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len;
  41.     n->cloned = 1;
  42.     n->nohdr = 0;
  43.     n->destructor = NULL;
  44.     C(tail);
  45.     C(end);
  46.     C(head);
  47.     C(data);
  48.     C(truesize);
  49.     /* 设置skb描述符的users为1 */
  50.     atomic_set(&n->users, 1);

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

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

    2、pskb_copy()

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

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

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

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

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

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

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

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

    8.  */

    9. struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
    10. {

    11.        struct sk_buff *n;
    12. /* 先申请skb描述符字段的内存空间,在这种情况下,skb描述符是不能继用预先分配的skb描述符的 */
    13. #ifdef NET_SKBUFF_DATA_USES_OFFSET
    14.        n = alloc_skb(skb->end, gfp_mask);
    15. #else
    16.        n = alloc_skb(skb->end - skb->head, gfp_mask);
    17. #endif
             if (!n)
                    goto out;
    18.        /* Set the data pointer */
          /* 设置数据指针 */
             skb_reserve(n, skb->data - skb->head);
             /* Set the tail pointer and length */
          /* 设置skb->tail指针和skb->len 长度 */
    19.        skb_put(n, skb_headlen(skb));
             /* Copy the bytes */
          /* 拷贝线性空间的数据 */
             skb_copy_from_linear_data(skb, n->data, n->len);
    20.     /* 对share info结构进行拷贝,并设置相关字段的值 */
    21.        n->truesize += skb->data_len;

    22.        n->data_len = skb->data_len;
    23.        n->len = skb->len;
    24.        if (skb_shinfo(skb)->nr_frags) {
                    int i;
    25.         /*在share info中有数据的情况下,拷贝share字段,特别注意:这里并没有拷贝share info中的数据 */
    26.               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
    27.                      skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
    28.                      get_page(skb_shinfo(n)->frags[i].page);

    29.               }
    30.               skb_shinfo(n)->nr_frags = i;

    31.        }

    32.        if (skb_has_frags(skb)) {
                    skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
    33.               skb_clone_fraglist(n);
    34.        }
    35.     /* 拷贝skb头部的相关字段 */

    36.        copy_skb_header(n, skb);

    37. out:
    38.        return n;

    39. }

    40. static inline void skb_reserve(struct sk_buff *skb, int len
    41. {
    42.        skb->data += len;
    43.        skb->tail += len;
    44. }

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

这篇关于SKB几个复制函数的区别的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/340620

相关文章

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

kotlin中const 和val的区别及使用场景分析

《kotlin中const和val的区别及使用场景分析》在Kotlin中,const和val都是用来声明常量的,但它们的使用场景和功能有所不同,下面给大家介绍kotlin中const和val的区别,... 目录kotlin中const 和val的区别1. val:2. const:二 代码示例1 Java

CSS Padding 和 Margin 区别全解析

《CSSPadding和Margin区别全解析》CSS中的padding和margin是两个非常基础且重要的属性,它们用于控制元素周围的空白区域,本文将详细介绍padding和... 目录css Padding 和 Margin 全解析1. Padding: 内边距2. Margin: 外边距3. Padd

Springboot @Autowired和@Resource的区别解析

《Springboot@Autowired和@Resource的区别解析》@Resource是JDK提供的注解,只是Spring在实现上提供了这个注解的功能支持,本文给大家介绍Springboot@... 目录【一】定义【1】@Autowired【2】@Resource【二】区别【1】包含的属性不同【2】@

Kotlin 作用域函数apply、let、run、with、also使用指南

《Kotlin作用域函数apply、let、run、with、also使用指南》在Kotlin开发中,作用域函数(ScopeFunctions)是一组能让代码更简洁、更函数式的高阶函数,本文将... 目录一、引言:为什么需要作用域函数?二、作用域函China编程数详解1. apply:对象配置的 “流式构建器”最

Java中的String.valueOf()和toString()方法区别小结

《Java中的String.valueOf()和toString()方法区别小结》字符串操作是开发者日常编程任务中不可或缺的一部分,转换为字符串是一种常见需求,其中最常见的就是String.value... 目录String.valueOf()方法方法定义方法实现使用示例使用场景toString()方法方法

分辨率三兄弟LPI、DPI 和 PPI有什么区别? 搞清分辨率的那些事儿

《分辨率三兄弟LPI、DPI和PPI有什么区别?搞清分辨率的那些事儿》分辨率这个东西,真的是让人又爱又恨,为了搞清楚它,我可是翻阅了不少资料,最后发现“小7的背包”的解释最让我茅塞顿开,于是,我... 在谈到分辨率时,我们经常会遇到三个相似的缩写:PPI、DPI 和 LPI。虽然它们看起来差不多,但实际应用

GORM中Model和Table的区别及使用

《GORM中Model和Table的区别及使用》Model和Table是两种与数据库表交互的核心方法,但它们的用途和行为存在著差异,本文主要介绍了GORM中Model和Table的区别及使用,具有一... 目录1. Model 的作用与特点1.1 核心用途1.2 行为特点1.3 示例China编程代码2. Tab

Android Kotlin 高阶函数详解及其在协程中的应用小结

《AndroidKotlin高阶函数详解及其在协程中的应用小结》高阶函数是Kotlin中的一个重要特性,它能够将函数作为一等公民(First-ClassCitizen),使得代码更加简洁、灵活和可... 目录1. 引言2. 什么是高阶函数?3. 高阶函数的基础用法3.1 传递函数作为参数3.2 Lambda

Nginx指令add_header和proxy_set_header的区别及说明

《Nginx指令add_header和proxy_set_header的区别及说明》:本文主要介绍Nginx指令add_header和proxy_set_header的区别及说明,具有很好的参考价... 目录Nginx指令add_header和proxy_set_header区别如何理解反向代理?proxy