• 套接字缓存之skb_clone、pskb_copy、skb_copy


    skb_clone–只复制skb描述符本身,如果只修改skb描述符则使用该函数克隆;

    pskb_copy–复制skb描述符+线性数据区域(包括skb_shared_info),如果需要修改描述符以及数据则使用该函数复制;

    skb_copy–复制所有数据,包括skb描述符+线性数据区域+非线性数据区,如果需要修改描述符和全部数据则使用该函数复制;

    以下为三个函数的分析;

     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 /*
    15 用于修改skb描述符中的某些字段
    16     克隆skb,该函数只克隆sk_buff部分
    17     数据区域公用(需要递增引用计数)
    18 */
    19 struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
    20 {
    21     /* 获取到支持克隆的skb */
    22     struct sk_buff_fclones *fclones = container_of(skb,
    23                                struct sk_buff_fclones,
    24                                skb1);
    25     struct sk_buff *n;
    26 
    27     /* 
    28         若发送标记有零拷贝,则拷贝用户空间的
    29         片段缓存到内核空间
    30     */
    31     if (skb_orphan_frags(skb, gfp_mask))
    32         return NULL;
    33 
    34     /* 如果skb可以被克隆,并且克隆引用为1 */
    35     if (skb->fclone == SKB_FCLONE_ORIG &&
    36         atomic_read(&fclones->fclone_ref) == 1) {
    37         /* 待克隆n指向skb2 */
    38         n = &fclones->skb2;
    39         /* 增加引用计数 */
    40         atomic_set(&fclones->fclone_ref, 2);
    41     } 
    42     /* 否则,为新克隆的skb分配内存 */
    43     else {
    44         if (skb_pfmemalloc(skb))
    45             gfp_mask |= __GFP_MEMALLOC;
    46 
    47         n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
    48         if (!n)
    49             return NULL;
    50 
    51         kmemcheck_annotate_bitfield(n, flags1);
    52         /* 初始化克隆状态 */
    53         n->fclone = SKB_FCLONE_UNAVAILABLE;
    54     }
    55 
    56     /* 调用克隆 */
    57     return __skb_clone(n, skb);
    58 }
     1 /*
     2     用于修改skb描述符和数据缓冲区内容时拷贝
     3     skb拷贝,拷贝skb描述符+ 线性数据缓冲区,
     4     线性缓冲区以外数据共享 
     5 */
     6 static inline struct sk_buff *pskb_copy(struct sk_buff *skb,
     7                     gfp_t gfp_mask)
     8 {
     9     return __pskb_copy(skb, skb_headroom(skb), gfp_mask);
    10 }
     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     拷贝skb描述符+ 线性数据缓冲区,
    19     线性缓冲区外部数据共享
    20 */
    21 struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom,
    22                    gfp_t gfp_mask, bool fclone)
    23 {
    24     unsigned int size = skb_headlen(skb) + headroom;
    25     int flags = skb_alloc_rx_flag(skb) | (fclone ? SKB_ALLOC_FCLONE : 0);
    26     struct sk_buff *n = __alloc_skb(size, gfp_mask, flags, NUMA_NO_NODE);
    27 
    28     if (!n)
    29         goto out;
    30 
    31     /* Set the data pointer */
    32     /* 保留头部空间 */
    33     skb_reserve(n, headroom);
    34     /* Set the tail pointer and length */
    35     /* 增加尾指针和数据长度 */
    36     skb_put(n, skb_headlen(skb));
    37     /* Copy the bytes */
    38     /* 拷贝线性缓冲区 */
    39     skb_copy_from_linear_data(skb, n->data, n->len);
    40 
    41     /* 设置长度值 */
    42     n->truesize += skb->data_len;
    43     n->data_len  = skb->data_len;
    44     n->len         = skb->len;
    45 
    46     /* 若有片段 */
    47     if (skb_shinfo(skb)->nr_frags) {
    48         int i;
    49 
    50         /* 片段数据拷贝到内核 */
    51         if (skb_orphan_frags(skb, gfp_mask)) {
    52             kfree_skb(n);
    53             n = NULL;
    54             goto out;
    55         }
    56 
    57         /* 复制判断内容 */
    58         for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
    59             skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i];
    60             skb_frag_ref(skb, i);
    61         }
    62 
    63         /* 片段数 */
    64         skb_shinfo(n)->nr_frags = i;
    65     }
    66 
    67     /* 如果有片段链表 */
    68     if (skb_has_frag_list(skb)) {
    69         /* 引用片段链表 */
    70         skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;
    71         skb_clone_fraglist(n);
    72     }
    73 
    74     /* 拷贝头部信息 */
    75     copy_skb_header(n, skb);
    76 out:
    77     return n;
    78 }
     1 /**
     2  *    skb_copy    -    create private copy of an sk_buff
     3  *    @skb: buffer to copy
     4  *    @gfp_mask: allocation priority
     5  *
     6  *    Make a copy of both an &sk_buff and its data. This is used when the
     7  *    caller wishes to modify the data and needs a private copy of the
     8  *    data to alter. Returns %NULL on failure or the pointer to the buffer
     9  *    on success. The returned buffer has a reference count of 1.
    10  *
    11  *    As by-product this function converts non-linear &sk_buff to linear
    12  *    one, so that &sk_buff becomes completely private and caller is allowed
    13  *    to modify all the data of returned buffer. This means that this
    14  *    function is not recommended for use in circumstances when only
    15  *    header is going to be modified. Use pskb_copy() instead.
    16  */
    17 /* 拷贝skb描述符+线性缓冲区+非线性缓冲区 */
    18 struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
    19 {
    20     /* 头部空间长度 */
    21     int headerlen = skb_headroom(skb);
    22 
    23     /* 分配空间= skb空间+ skb以外的数据空间 */
    24     unsigned int size = skb_end_offset(skb) + skb->data_len;
    25     struct sk_buff *n = __alloc_skb(size, gfp_mask,
    26                     skb_alloc_rx_flag(skb), NUMA_NO_NODE);
    27 
    28     if (!n)
    29         return NULL;
    30 
    31     /* Set the data pointer */
    32     //保留头部空间
    33     skb_reserve(n, headerlen);
    34     /* Set the tail pointer and length */
    35     /* 偏移尾部指针修改总长度 */
    36     skb_put(n, skb->len);
    37 
    38     /* 拷贝数据 */
    39     if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len))
    40         BUG();
    41 
    42     /* 拷贝skb头 */
    43     copy_skb_header(n, skb);
    44     return n;
    45 }
  • 相关阅读:
    java语法基础
    HashMap中的put()和get()的实现原理
    理解:o(1), o(n), o(logn), o(nlogn) 时间复杂度
    mongodb去重分页查询支持排序
    elk日志分析系统搭建(window )亲自搭建
    IDEA更改主题插件——Material Theme UI
    css实现图片的瀑布流且右上角有计数
    C# string "yyMMdd" 转DataTime
    Vue.js系列(一):Vue项目创建详解
    VS2017常用快捷键
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/7529605.html
Copyright © 2020-2023  润新知