skb管理函数之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 }
时间: 2024-08-02 11:21:07

skb管理函数之skb_clone、pskb_copy、skb_copy的相关文章

skb_clone/pskb_copy/skb_copy

在Linux对网络数据包的处理过程中,会用到对skb的拷贝,skb的拷贝分成了几种拷贝,之所以分成几种拷贝,在于不同情况下,可能需要修改的skb范围不同,核心思想在于尽可能小的重新开辟内存,尽可能的共享内存,共享数据区. 对一个正常的skb来讲,一般要包括sk_buff以及数据区两部分.而数据区又分成普通数据区和skb_shared_info. skb_clone: 只拷贝sk_buff, 换而言之,整个数据区从策略上讲,是没有计划修改的. pskb_copy: 拷贝sk_buff以及普通数据区

skb管理函数之skb_put、skb_push、skb_pull、skb_reserve

四个操作函数直接的区别,如下图: 1 /** 2 * skb_put - add data to a buffer 3 * @skb: buffer to use 4 * @len: amount of data to add 5 * 6 * This function extends the used data area of the buffer. If this would 7 * exceed the total buffer size the kernel will panic. A

skb管理函数之alloc_skb、dev_alloc_skb、kfree_skb、dev_kfree_skb、consume_skb

alloc_skb--分配skb dev_alloc_skb--分配skb,通常被设备驱动用在中断上下文中,它是alloc_skb的封装函数,因为在中断处理函数中被调用,因此要求原子操作(GFP_ATOMIC) kfree_skb--减少skb引用,为0则释放,用于出错丢包时释放skb使用: dev_kfree_skb==consume_skb--减少skb引用,为0则释放,成功状态下释放skb使用: 1 static inline struct sk_buff *alloc_skb(unsig

使用内存管理函数实现动态数组

C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态地分配内存空间,也可把不再使用的空间释放,为有效地使用内存资源提供了手段. 动态数组,指的就是利用内存的申请和释放函数,在程序的运行过程中,根据实际需要指定数组的大小.其本质就是一个指向数组的指针变量. 主要用到的内存管理函数是:malloc和free. 1.分配内存函数malloc: 调用形式:(类型说明符*)malloc(size): 功     能:在内存的动态存储区中分配一块长度为size字节的连续区域. 返     回:该区域

lwip-内存管理函数说明

1.mem_init()   : 内存堆初始化函数,主要设置内存堆的起始地址,以及初始化空闲列表,lwip初始化时调用,内部接口. 2.void *mem_malloc(mem_size_t size)  : 申请分配内存,size为需要申请的内存字节数,返回值为最新分配的内存块的数据地址,注意 不是内存块的地址.如果为分配好内存,返回NULL.申请的内存堆是全局变量. 3.*mem_calloc(mem_size_t count, mem_size_t size) : 是对mem_malloc

functools:管理函数工具(部分)

# -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #functools:管理函数工具 #作用:处理其他函数的函数 #版本:2.5及之后 #用于调整或者扩展函数和其他可回调对象,不用重写 #修饰符:主要工具是partial在,用于包装,一个有默认参数可回调对象.得到对象本身是可回调的,可以看作就像是原来的函数,它与原函数完全相同,调用时也可以提供额外的位置或者命名参数,可以使用partial而不是lambda提供的默

μC/OS-Ⅲ系统的时间管理函数和定时器

一.时间管理函数 μC/OS-Ⅲ系统提供一些列时间管理服务函数: 1.OSTimeDly():任务延时n个时钟节拍. 2.OSTimeDlyHMSM():任务延时指定的时间,采用“时:分:秒:毫秒”方式指定. 3.OSTimeDlyResume():恢复被延时的任务.注意,一个任务利用这个函数恢复其他函数时,被恢复任务不知道自己是被其他任务恢复,会任务是延时结束而得到恢复.所以此函数要谨慎使用. 4.OSTimeGet():获取当前时钟节拍计数器的值. 5.OSTimeSet():设置时钟节拍计

ucosiii几个常用的时间管理函数

昨天我们说了系统节拍,经过一步步的分析,了解了任务运行的基础,是怎么来的.今天就继续谈谈"时间管理"这个话题,系统节拍驱动任务的运行,时间管理就是对任务的运行时间进行管理的一种内核机制.那么下面就简单介绍几个常用的时间管理函数. 1.OSTimeDly函数,它位于os_time.c文件中,这个文件还有其他很多的时间管理函数,以下的函数都位于这个文件. 看了上面的参数是不是还是毫无感觉,那我们看看源码,注明:注释不是自己写的,是秉火团队写的.我们需要做的不光是学会使用这些别人提供的好内容

STM32中断管理函数

CM3 内核支持256 个中断,其中包含了16 个内核中断和240 个外部中断,并且具有256 级的可编程中断设置.但STM32 并没有使用CM3 内核的全部东西,而是只用了它的一部分. STM32 有76 个中断,包括16 个内核中断和60 个可屏蔽中断,具有16 级可编程的中断优先级. 而我们常用的就是这60 个可屏蔽中断,所以我们就只针对这60 个可屏蔽中断进行介绍. 在 MDK 内,与NVIC 相关的寄存器,MDK 为其定义了如下的结构体: typedef struct { vu32 I