默默的一块石头
分类: LINUX
2020-07-18 15:40:13
https://blog.csdn.net/farmwang/article/details/54233975
skbuffs是那些linux内核处理网络分组的缓存。网卡收到分组后,将它们放进skbuff,然后再传送给网络堆栈。网络堆栈一直
要用到skbuff。
1. 一个完整的skb buff组成(1) struct sk_buff--用于维护socket buffer状态和描述信息(3) struct skb_shared_info --作为header data的补充,用于存储ip分片,其中sk_buff *frag_list是一系列子skbuff链表,而frag[]是由一组单独的page组成的数据缓冲区
这两个函数的定义位于net/core/skbuff.c文件内。通过这alloc_skb()申请的内存空间有两个,一个是存放实际报文数据的内存空间,通过kmalloc()函数申请;一个是sk_buff数据结构的内存空间,通过 kmem_cache_alloc()函数申请
len和data_len!
之前说过len代表的是整个数据的长度,data_len代表的是非线性数据长度。
现在从分配内存开始解释这个图的由来:
我们使用skb_alloc给skb分配空间,那么刚刚分配结束返回时候,是什么样的情况呢?看下图(图二):
刚刚开始初始化的时候,预分配一个一块线性数据区域,这个区域一般放入的是各个协议层次的不同的头,还有一些实际数据,下面的非线性区域是为了弥补当数据真的很多的时候,作为数据区域的扩展!关于skb_shared_info具体意思下面会继续说!注意在初始化的时候,head,data和tail都指向内存的开始位置,head在这个位置始终不变,它表示的是分配的内存的开始位置。end的位置也是不变的,表示的是分配的内存的结束位置。data和tail会随着数据的加入和减少变化,总之表示的是放入数据的内存区域(由图一)可知。
现在需要解释一下skb_shared_info这个结构体,这个结构体真的是很很有特色!主要是其中的两个字段frags和frag_list,下面继续解释:
-
struct skb_shared_info {
-
atomic_t dataref; // 对象被引用次数
-
unsigned short nr_frags; // 分页段数目,即frags数组元素个数
-
unsigned short tso_size;
-
unsigned short tso_segs;
-
unsigned short ufo_size;
-
unsigned int ip6_frag_id;
-
struct sk_buff *frag_list; // 一般用于分段(还没有非常清楚的理解)
-
skb_frag_t frags[MAX_SKB_FRAGS]; // 保存分页数据(skb->data_len=所有的数组数据长度之和)
-
};
> : 对于frags[]一般用在,当数据真的很多,而且在线性数据区域装不下的时候,需要使用这个,skb_frag_t中是一页一页的数据,先看看结构体:
-
struct skb_frag_struct {
-
struct page *page; // 代表一页数据
-
__u16 page_offset; // 代表相对开始位置的页偏移量
-
__u16 size; // page中数据长度
-
};
需要注意的是:只有在DMA支持物理分散页的Scatter/Gather(SG,分散/聚集)操作时候才可以使用frags[]来保存剩下的数据,否则,只能扩展线性数据区域进行保存!!!
这些页其实是其实就是虚拟页映射到物理页的结构,看下图(图三):