Chinaunix首页 | 论坛 | 博客
  • 博客访问: 444654
  • 博文数量: 403
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: -70
  • 用 户 组: 普通用户
  • 注册时间: 2016-09-05 12:45
文章分类

全部博文(403)

文章存档

2014年(3)

2013年(1)

2012年(3)

2011年(21)

2010年(13)

2009年(64)

2008年(9)

2007年(36)

2006年(253)

分类: C/C++

2007-03-30 14:27:32

struct sk_buff {
    struct sk_buff    * next;                
         struct sk_buff    * prev;            
    struct sk_buff_head * list;        
    struct sock    *sk;            
    struct timeval    stamp;            
    struct net_device    *dev;        
    struct net_device    *real_dev;    

    union
    {
        struct tcphdr    *th;
        struct udphdr    *uh;
        struct icmphdr    *icmph;
        struct igmphdr    *igmph;
        struct iphdr    *ipiph;
        struct spxhdr    *spxh;
        unsigned char    *raw;
    } h;

    
    union
    {
        struct iphdr    *iph;
        struct ipv6hdr    *ipv6h;
        struct arphdr    *arph;
        struct ipxhdr    *ipxh;
        unsigned char    *raw;
    } nh;
union
    {    
          struct ethhdr    *ethernet;
          unsigned char     *raw;
    } mac;

    struct  dst_entry *dst;

     
    char        cb[48];     

    unsigned int     len;        

    unsigned int     data_len;
    unsigned int    csum;                
         unsigned char     __unused,            
        
            cloned,                       pkt_type,        
              ip_summed;            __u32        priority;            atomic_t    users;            
    unsigned short    protocol;        

    unsigned short    security;        
    unsigned int    truesize;                            

    unsigned char    *head;                            
    unsigned char    *data;                            
    unsigned char    *tail;            
    unsigned char     *end;            
    void         (*destructor)(struct sk_buff *);    
#ifdef CONFIG_NETFILTER
    
        unsigned long    nfmark;
    
    __u32        nfcache;
    
    struct nf_ct_info *nfct;
#ifdef CONFIG_NETFILTER_DEBUG
        unsigned int nf_debug;
#endif
#endif

#if defined(CONFIG_HIPPI)
    union{
        __u32    ifield;
    } private;
#endif

#ifdef CONFIG_NET_SCHED
       __u32           tc_index;               
#endif
};
 

该结构维护一个收到的或者要发送的网络包。但其本身并不包含存放网络包的数据的存储区。存储区是另外单独分配的内存空间,但该结构说明了如何访问存储区空间,如何维护多个存储区空间以及存储网络包解析的成果。

所有的sk_buff是通过一个双向链表进行维护的。需要说明的是该双向链表中的一个元素是struct sk_buff_head类型。它相当于该双向链表的表头,其中有锁,链表元素个数等维护链表的相关信息。链表中其它的元素都是sk_buff类型。

链表结构图如下:

而对于每个sk_buff而言,如前所述,其本身并不维护网络包的存储区。该结构跟存储区的关系如下图所示:

图的左边表示sk_buff结构,右侧表示网络包的存储区。可以看到,sk_buff中有四个指针指向存储区。其中head一定指向存储区的开头,end一定指向存储区的结尾。data指向实际内容的开头,tail指向实际内容的结尾。这样做有两个原因,一是在分配空间的时候我们尚不知道具体需要多大的空间,只能按照最大可能空间来分配;二是为了满足字节对齐的需要。

图中Data部分的内容包括网络包的所有内容。对于输入包而言,其就是从当前层向上的所有层的头和最后的负载,每解析掉一层的头,该协议的协议头对应的数据就不再继续处理,所以data指针在每层会逐渐增大。对于输出包而言,其每向下传输一层,都会添加一层的头,所以sk_buffdata指针也会不断减小。

对于输入包而言,存储区的内容是不变的。但我们在分析包时,在每层都会剥除该层的头。为了保留我们的剥除结果,结构中会有三个指针分别指向以太,网络和传输三层的协议头。这三个指针依次分别是union {…} macunion {…} nhunion{…} h。三个成员都是联合,其中的内容是该层可能的协议类型的指针。

还有一组成员表示存储区中数据的长度。len表示存储区的数据长度和分片长度之和。data_len表示分片长度。mac_len表示mac头的长度。truesize表示存储区总长度(即end-head)和sk_buff本身长度之和。

 

下面的内容是关于如何维护存储区。

alloc_skbdev_alloc_skb用来分配sk_buff和存储区,kfree_skbdev_kfree_skb则释放sk_buff和其对应的存储区。刚初始化完的存储区,headdatatail都指向存储区的开头,end指向结尾。下面这些函数是修改datatail指针的指向。

skb_reserve是在存储区的开头保留一段空间。其有两个作用,对于接收到的报文而言,可以保持字节对齐;对于发送的报文而言,可以保留空间用于存放各层的协议头。毕竟我们在高层协议就会分配该存储区,所以需要预留下层的协议头的空间。该函数的作用会导致datatail两个指针都下移,在head和它们之间留出空间。

skb_put则是将tail下移,即增加了真正空间的长度。

skb_push是将data上移,也增加了真正空间的长度。

skb_pulldata下移,减少了真正空间的长度。

 

下面是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 csumipsum:校验和。

unsigned char cloned

unsigned char pkt_type:包类型,可以是单发给该主机的包,广播包,多播包,转发包等。

unsigned short protocol:表示以太层的上层协议,可以是IPIPv6ARP

 

下面是关于skb_shared_info结构的。当我们使用alloc_skb分配空间时,会在存储区的后面紧接着一个该结构的实例。如下图所示:

其中存储了关于网络块的附加信息。不知为何不也放在sk_buff中。其中维护了存储块的引用计数,IP分片数据的信息。

 

对于sk_buff和存储块,有时是需要拷贝的。分为三种情况,一是只拷贝sk_buff,存储块复用,此时使用skb_clone函数;二是拷贝sk_buff和存储块的主体,但存储块后的skb_shared_infofrags数组指向的分片数据不拷贝,这使用pskb_copy函数;三是上述的全都拷贝,使用skb_copy函数。在不同情况下不同使用。

 

    最后是一些维护sk_buff链表的函数。

阅读(7249) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~

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上移,也增加了真正空间的长度。 这两句中,有一句肯定不对.