各种形形色色的讲SKB的文章已经有很多了,我这里就不说大而全的东西,想了解全部建议还是看《深入Linux网络内幕》里关于skb的介绍。
本文重点强调介绍两个方面:
一,skb所占用的内存分布
二,skb的报文头存放地方限制
一:skb占用的内存分布
一个skb包含三个部分:
skb结构体本身,内含大量的指针指向各种关联数据
skb->data指向的线性数据区,其实内存应该从skb->head开始算到skb->end为止,skb->data和skb->tail是用来指向当前处理所指向的数据的。比如内存从0x00ff1000(head)开始,到0x00ff2000(end)结束,那么在IP层数据处理时data可能指向0x00ff1200,IP报头从这开始,但0xff1186里一般还会有mac头的存在。
shared_info里存放的非线性数据区,包含两部分:一部分是放在frags里,以page为单位保持,一部分放在frag_list里,以skb为链表串起来。
我们来看一下skb的申请函数:
alloc_skb(header_len, gfp_mask)
这里申请的内存全放在以skb->head开头的一块内存里(此时skb->data=skb->head)
sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
unsigned long data_len, int noblock,
int *errcode)
这里header_len大小的连续内存的指针还是放在skb->head里,但data_len就由多个page组成了,然后page指针统一放在frags里。
有人说了:frag_list呢?据我的工作经验来看,frag_list在申请skb时是不会有的,首先:人为的可以串起来,其次:kernel在两个地方会做这个事:一个是在收包的GRO处理时,会把多个skb串成一个skb,第一个做头,其余的全部放在frag_list里。 二是在网卡驱动里,有些网卡开启LRO后会把skb以frag_list的形式串起来。在发包时,更多的数据一般还是在frags里以page形式保存。
二,skb的报文头存放地方限制
之所以引出这个话题,是因为我在做虚拟网卡前后端驱动时,有过这样的疑惑,比如说:guest里发出来的报文,在host里要创建新的skb对其进行管理,前端发生的报文一般是以页为单位来存放的,如果后端也可以以一页一页数据直接对照,无论是copy还是置换抑或是直接使用,都要方便很多。
但是host里对skb可能会有很多操作,比如pskb_expand_head,比如将skb->network_header等指向之后进行操作,这些操作如果不发生在本机管理的内存上的话,无论如何也是很不方便的。
最重要的一点,对skb->head里的数据进行操作,都是基于一个默认前提:这块内存是连续的,而frags里的page很显然是不保证这一点的。
因此:skb的报头(二层,三层,四层)一定是在skb->head指向的一块连续(线性)内存区。
阅读(5191) | 评论(0) | 转发(0) |