sk_buff结构

文章出处:http://book.51cto.com/art/200912/168620.htm

                    http://www.newsmth.net/pc/pccon.php?id=1363&nid=296040&pid=0&tag=0&tid=7570

    内核层和用户层在网络方面的差别很大,在内核的网络层中sk_buff结构占有重要的地位,几乎所有的处理均与此结构有关系。网络协议栈是一个层次架构的软件结构,层与层之间通过预定的接口传递报文。网络报文中包含了在协议各层使用到的各种信息。由于网络报文之间的大小不是固定的,因此采用合适的数据结构来存储这些网络报文就显得非常重要。

1. 结构sk_buff的原型

    在linux的2.6版本的内核中,采用结构sk_buff来存储这些数据。在这个结构中,既有指向网络报文的指针,同时也有描述网络报文的变量。sk_buff数据结构的代码如下所示。

struct sk_buff   
{  
struct sk_buff         *next;  
struct sk_buff         *prev;  
struct sock           *sk;  
ktime_t                 tstamp;  
struct net_device       *dev;  
union   
{  
struct  dst_entry    *dst;  
struct  rtable       *rtable;  
};  
struct  sec_path      *sp;  
char                 cb[48];  
unsigned int          len,  
data_len;  
__u16               mac_len,  
hdr_len;  
union   
{  
__wsum           csum;  
struct  
{  
__u16            csum_start;  
__u16            csum_offset;  
};  
};  
__u32                   priority;  
__u8                     local_df:1,  
                 cloned:1,  
ip_summed:2,  
nohdr:1,  
nfctinfo:3;  
__u8                    pkt_type:3,  
fclone:2,  
ipvs_property:1,  
peeked:1,  
nf_trace:1;  
__be16                  protocol;  
void                    (*destructor)(struct sk_buff *skb);  
struct nf_conntrack     *nfct;  
struct sk_buff          *nfct_reasm;  
struct nf_bridge_info   *nf_bridge;  
int                     iif;  
__u16                   queue_mapping;  
__u16                   tc_index;  
__u16                   tc_verd;  
__u8                    ndisc_nodetype:2;  
dma_cookie_t            dma_cookie;  
__u32                   secmark;  
__u32                   mark;  
sk_buff_data_t          transport_header;  
sk_buff_data_t          network_header;  
sk_buff_data_t          mac_header;  
sk_buff_data_t          tail;  
sk_buff_data_t          end;  
unsigned char           *head,  
                        *data;  
unsigned int            truesize;  
atomic_t                users;  
}; 



    sk_buff主要成员的含义如下:

    next: sk_buff链表中的下一个缓冲区。

    prev: sk_buff链表中的前一个缓冲区。以上两个变量将sk_buff链接到一个双向链表中。

    sk: 本网络报文所属的sock结构,此值仅在本机发出的报文中有效,从网络收到的报文此值为空。

    tstamp: 报文收到的时间戳。

    dev: 收到此报文的网络设备。

    transport_header: 传输层头部。

    network_header: 网络层头部。

    mac_header: 链路层头部。

    cb: 用于控制缓冲区。每个层都可以使用此指针,将私有的数据放置于此。

    len: 有效数据长度。

    data_len: 数据长度。

    mac_len: 链路层头部长度,对于以太网,指mac地址所用的长度,为6.

    hdr_len: skb的可写头部长度。

    csum: 校验和(包含开始和偏移)。

    csum_start: 当开始计算校验和时从skb->head的偏移。

    csum_offset: 从csum_start开始的偏移。

    local_df: 允许本地分片。

    pkt_type: 包的类别。

    priority: 包队列的优先级。

    truesize: 报文缓冲区的大小。

    head: 报文缓冲区的头。

    data: 数据的头指针。

    tail: 数据的尾指针。

    end: 报文缓冲区的尾部。

    2. sk_buff的含义

下图是sk_buff的框图,其中tail、end、head和data是对网络报文部分的描述。

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

图中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_kree_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结构_第1张图片

    网络报文存储空间实在应用层发送网络数据,或者网络设备收到网络数据时动态分配的,分配成功之后,将接收或者发送的网络数据填充到这个存储空间中去。将网络数据填充到存储空间时,在存储空间的头部预留了一定数量的空隙,然后从此偏移量开始将网络报文复制到存储空间中

    结构sk_buff以sk_buff_head构成一个环状的链,如下图所示,next变量指向下一个sk_buff结构,prev变量指向前一个sk_buff结构,内核程序通过访问其中的各个单元来遍历整个协议栈中的网络数据。

sk_buff结构_第2张图片




   

你可能感兴趣的:(数据结构,struct,网络,header,存储,destructor)