加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

sk_buffer结构分析

(2010-07-21 14:49:39)
标签:

skb

linux

杂谈

分类: 系统结构
关于skb结构的文章有很多,这几天涉及到这方面的内容,就稍微总结了一下。其中主要是对share_info部分进行简单的总结,因为发现网上这部分内容还不是很清楚。
这是skb数据结构的定义,因为我是在Xen的场景下对该结构体进行研究,所以代码中可能有关于Xen的特殊定义,可以忽略掉。其中对于部分变量我进行了简单的解释说明。

skb结构:

struct sk_buff {
   
    struct sk_buff        *next;       //下一个skb地址
    struct sk_buff        *prev;       //前一个skb地址链表

    struct sock        *sk;            //此报文所属的sock结构,此值在本机发出的报文中有效,从网络设备收到的报文此值为空。
    struct skb_timeval    tstamp;             //时间戳
    struct net_device    *dev;                //收到报文的网络设备
    struct net_device    *input_dev;         //输入设备,应该是指skbuff里面数据的输入设备吧

    union {
        struct tcphdr    *th;
        struct udphdr    *uh;
        struct icmphdr    *icmph;
        struct igmphdr    *igmph;
        struct iphdr    *ipiph;
        struct ipv6hdr    *ipv6h;
        unsigned char    *raw;
    } h;                                                      //各种头文件指针,主要是传输层

    union {
        struct iphdr    *iph;
        struct ipv6hdr    *ipv6h;
        struct arphdr    *arph;
        unsigned char    *raw;
    } nh;                                                //网络层头文件指针

    union {
          unsigned char     *raw;
    } mac;
        以上三个union结构依次是传输层,网络层,链路层的头部结构指针。这些指
针在网络报文进入这一层时被赋值,其中raw是一个无结构的字符指针,用于
扩展的协议。

    struct  dst_entry    *dst;           //此报文的路由,路由确定后赋此值
    struct    sec_path    *sp;            //

 
    char            cb[48];       //用于在协议栈之间传递参数,参数内容的涵义由使用它的函数确定。

    unsigned int        len,         //此报文的长度,这是指网络报文在不同协议层中的长度,包括头部和数据。在协议栈的不同层,这个长度是不同的。
                data_len,
                mac_len,
                csum;
    __u32            priority;
    __u8            local_df:1,
                cloned:1,
                ip_summed:2,
                nohdr:1,
                nfctinfo:3;
    __u8            pkt_type:3,
                fclone:2,
   
    unsigned int        truesize;
    atomic_t        users;
    unsigned char        *head,
                *data,
                *tail,
                *end;                              //skb的主要四个结构head,data,tail,end.

};  
http://s12/middle/6a18dd2748be05e20824b&690

应该注意的一点是skb在随着传递过程中,他的data指针式不断变化的,其中的ip头和tcp头都是到相应的层之后加入到data区域的。。
file:///C:/Users/Niandong.D/AppData/Local/Temp/moz-screenshot-3.png
http://s6/middle/6a18dd2748be06d755465&690

具体如上图可以看的出来。
还有就是skb的end指针其实后面就对应这另一个结构体skb_share_info,它的结构如下所示:

struct skb_shared_info {
    atomic_t    dataref;
    unsigned short    nr_frags;
    unsigned short    gso_size;
   
    unsigned short    gso_segs;
    unsigned short  gso_type;
    unsigned int    ip6_frag_id;
    struct sk_buff    *frag_list;
    skb_frag_t    frags[MAX_SKB_FRAGS];
};

dataref指示了数据的索引,nr_frags表示碎片的数目,gso_size为每个分片的数据大小;
碎片数组为frags[MAX_SKB_FRAGS];frag_list一般是没有用的,它表示了附属关系。

一般的skb是否有后面的分片视skb自己而定,如果是小数据直接在data区域内就可以全部存储,如果数据表较大那么就会有很多frags来存放数据,这里的一个frag相当于一个内存页。还有的情况就是data区域只存放数据的包头,所有的数据都存储在碎片中。

skb的生成过程可以看How SKB works,这篇文章,写的比较好,比较详细,这里就不啰嗦了。
http://vger.kernel.org/~davem/skb_data.html

操作过程:


sk_buff链表是一个双向链表,它包括一个链表头而且每一个缓冲区都有一个prev和next指针,指向链表中前一个和后一个缓冲区结点。

    void skb_queue_head_init(struct sk_buff_head *list)

初始化sk_buff_head结构,该函数必须在所有的链表操作之前调用,而且不能被重复调用。

    struct sk_buff *skb_dequeue(struct skb_buff_head *list)

这个函数作用是把第一个缓冲区从链表中移走。返回取出的sk_buff,如果队列为空,就返回空指针。添加缓冲区用到skb_queue_head和skb_queue_tail两个例程。

    int skb_peek(struct sk_buff_head *list)

返回指向缓冲区链表第一个节点的指针。

    int skb_queue_empty(struct sk_buff_head *list)

如果链表为空,返回true

   void skb_queue_head(struct sk_buff_head * list,struct sk_buff *newsk)

该函数在链表头部添加一个缓冲区

   void skb_queue_tail(struct sk_buff_head *list,struct sk_buff *newsk)

该函数在链表尾部添加一个缓冲区,这是缓冲区操作函数中最常用的一个。

  __u32 skb_queue_len(struct sk_buff_head * list)

返回队列中排队的缓冲区的数目

这里只是几个简单的函数,具体其它的还可以查源码找到详细的过程。


file:///C:/Users/Niandong.D/AppData/Local/Temp/moz-screenshot.png

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有