全部博文(403)
分类: C/C++
2007-03-30 14:27:32
该结构维护一个收到的或者要发送的网络包。但其本身并不包含存放网络包的数据的存储区。存储区是另外单独分配的内存空间,但该结构说明了如何访问存储区空间,如何维护多个存储区空间以及存储网络包解析的成果。
所有的sk_buff是通过一个双向链表进行维护的。需要说明的是该双向链表中的一个元素是struct sk_buff_head类型。它相当于该双向链表的表头,其中有锁,链表元素个数等维护链表的相关信息。链表中其它的元素都是sk_buff类型。
链表结构图如下:
而对于每个sk_buff而言,如前所述,其本身并不维护网络包的存储区。该结构跟存储区的关系如下图所示:
图的左边表示sk_buff结构,右侧表示网络包的存储区。可以看到,sk_buff中有四个指针指向存储区。其中head一定指向存储区的开头,end一定指向存储区的结尾。data指向实际内容的开头,tail指向实际内容的结尾。这样做有两个原因,一是在分配空间的时候我们尚不知道具体需要多大的空间,只能按照最大可能空间来分配;二是为了满足字节对齐的需要。
图中Data部分的内容包括网络包的所有内容。对于输入包而言,其就是从当前层向上的所有层的头和最后的负载,每解析掉一层的头,该协议的协议头对应的数据就不再继续处理,所以data指针在每层会逐渐增大。对于输出包而言,其每向下传输一层,都会添加一层的头,所以sk_buff的data指针也会不断减小。
对于输入包而言,存储区的内容是不变的。但我们在分析包时,在每层都会剥除该层的头。为了保留我们的剥除结果,结构中会有三个指针分别指向以太,网络和传输三层的协议头。这三个指针依次分别是union {…} mac,union {…} nh和union{…} h。三个成员都是联合,其中的内容是该层可能的协议类型的指针。
还有一组成员表示存储区中数据的长度。len表示存储区的数据长度和分片长度之和。data_len表示分片长度。mac_len表示mac头的长度。truesize表示存储区总长度(即end-head)和sk_buff本身长度之和。
下面的内容是关于如何维护存储区。
alloc_skb和dev_alloc_skb用来分配sk_buff和存储区,kfree_skb和dev_kfree_skb则释放sk_buff和其对应的存储区。刚初始化完的存储区,head,data,tail都指向存储区的开头,end指向结尾。下面这些函数是修改data和tail指针的指向。
skb_reserve是在存储区的开头保留一段空间。其有两个作用,对于接收到的报文而言,可以保持字节对齐;对于发送的报文而言,可以保留空间用于存放各层的协议头。毕竟我们在高层协议就会分配该存储区,所以需要预留下层的协议头的空间。该函数的作用会导致data和tail两个指针都下移,在head和它们之间留出空间。
skb_put则是将tail下移,即增加了真正空间的长度。
skb_push是将data上移,也增加了真正空间的长度。
skb_pull将data下移,减少了真正空间的长度。
下面是sk_buff的其它成员:
struct sock *sk:表示该网络包所属的socket。对于该主机发送的和接收的网络包,自然对应着一个socket套接字。对于转发的网络包,则该成员为NULL。
atomic_t users:表示该sk_buff结构实例被引用的计数。这个是结构本身的引用计数,而不是其对应的存储区的引用计数。
void (*destructor)():析构函数。
struct timeval stamp:对于接受包,表示该包接收到的时间。
struct net_device *dev:接收或者发送包的网卡接口。
struct net_device *input_dev:接收到包的网卡接口。
struct net_device *real_dev:在某些机器中,多个物理网卡接口可以被看作一个虚拟设备。这中情况下real_dev表示物理结构。
char cb[40]:一个用于对该网络包进行处理的通用缓冲区。可以存放一些在不同层之间传输的数据。
unsigned int csum,ipsum:校验和。
unsigned char cloned:
unsigned char pkt_type:包类型,可以是单发给该主机的包,广播包,多播包,转发包等。
unsigned short protocol:表示以太层的上层协议,可以是IP,IPv6和ARP。
下面是关于skb_shared_info结构的。当我们使用alloc_skb分配空间时,会在存储区的后面紧接着一个该结构的实例。如下图所示:
其中存储了关于网络块的附加信息。不知为何不也放在sk_buff中。其中维护了存储块的引用计数,IP分片数据的信息。
对于sk_buff和存储块,有时是需要拷贝的。分为三种情况,一是只拷贝sk_buff,存储块复用,此时使用skb_clone函数;二是拷贝sk_buff和存储块的主体,但存储块后的skb_shared_info中frags数组指向的分片数据不拷贝,这使用pskb_copy函数;三是上述的全都拷贝,使用skb_copy函数。在不同情况下不同使用。
最后是一些维护sk_buff链表的函数。
leigaiting2011-03-03 10:06:42
本站网友 时间:2011-02-22 12:26:45 IP地址:192.100.130.★ skb_put则是将tail下移,即增加了真正空间的长度。 skb_push是将data上移,也增加了真正空间的长度。 这两句中,有一句肯定不对. 额。。将尾巴拉长 或者 将头拉长 不都是增加了长度吗?怎么就不对了?
chinaunix网友2011-02-22 12:26:45
skb_put则是将tail下移,即增加了真正空间的长度。 skb_push是将data上移,也增加了真正空间的长度。 这两句中,有一句肯定不对.