Chinaunix首页 | 论坛 | 博客
  • 博客访问: 114135
  • 博文数量: 39
  • 博客积分: 1680
  • 博客等级: 上尉
  • 技术积分: 395
  • 用 户 组: 普通用户
  • 注册时间: 2009-10-10 12:42
文章分类

全部博文(39)

文章存档

2011年(1)

2010年(8)

2009年(30)

我的朋友

分类: LINUX

2009-11-20 10:47:29

**********The Socket Buffer:sk_buff Structure

sk_buff
    layout Fields:

        sk_buff位于双向链表之中,指向一个sk_buff_head结构。(一个socket拥有一个这样的链表是吗?)
            struct sk_buff_head { struct sk_buff *next; struct sk_buff *prev; __u32 qlen;    ......};
                next指向第一个sk_buff元素;prev指向最后一个sk_buff元素;qlen记录链表中sk_buff元素数量
        next指针:指向下一个sk_buff元素,最后一个则指向sk_buff_head;
        prev指针:指向前一个sk_buff元素,第一个则指向sk_buff_head;(指针类型的统一是依靠void*实现的吗?)
        list指针:指向sk_buff_head

        struct sock *sk:指向拥有该buffer的socket结构,若该buffer仅仅用于forward,则NULL;
        unsigned int len:数据域的长度,包括main buffer和fragments中的总和,还包括协议首部长度
        unsigned int data_len:在fragments中的data size
        unsigned int mac_len:MAC 首部大小
        atomic_t users:使用该sk_buff buffer的实体计数器,在free的时候须其为0,否则减值而不free;须为原子操作;
        unsigned int truesize:sk_buff的实际大小,即len+sizeof(sk_buff),在len发生变化时,它也要随之更新;

        unsigned char *head;unsigned char *end;unsigned char *data;unsigned char *tail;
        数据域系列指针,在真实数据的首尾之外还有一段headroom(首部在其中)和tailroom。data和tail指向真实数据域的始末地址,而head和end指向两个room之外的始末地址。
        void (*desructor)(...):函数指针,当buffer移除的时候进行的操作(sock_rfree or sock_wfree)。


    General Fields:
        struct timeval stamp:收包时戳
        struct net_device *dev:记录着收包设备,或者发包设备,取决于该包是要发还是刚收
        struct net_device *input_dev:记录刚刚所收包从哪个设备来,若该包是本地产生的,则NULL
        struct net_device *real_dev:虚拟设备所用,记录其依附的真实设备

        union {...} h; union {...} nh; union{...} mac;
        分别指向着传输层,路由层,MAC层的包首部地址,这些首部信息之后便是data指针所指地址;在层次之间传递时,这些指针会随着首部的增减而发生变化。
        struct dst_entry dst:用于routing subsystem,以后介绍
        char cb[40]:“control buffer”和private information记录
        unsigned int csum, unsigned char ip_summed:checksum和associated status flag,以后介绍
        unsigned char cloned:boolean flag,打开表明本结构是另一个sk_buff的clone
        unsigned char pkt_type:根据MAC目标地址的类别信息,可取值定义在
        __u32 priority:用于QoS;包产生时,由socket层来定义该值;包传递时,由rt_tos2priority函数来确定该值;
        unsigned short protocol:MAC层的上一层的协议类型(IP,IPv6,ARP,),用于driver(调用netif_rx函数)通知上一层用何handler

    Management Functions
    (do_someting 是 __do_something 的wrapper,添加了一些sanity check或 locking mechanisms;内层函数通常是不直接调用的)
        alloc_skb:allocation of buffers的主函数,它的工作包括data buffer和sk_buff struct二者的allocation;
             它通过kem_cache_alloc(原型?)函数从cache中获得一个sk_buff结构,再通过kmalloc获得一个data buffer
                 skb = kmem_cache_alloc(skbuff_head_cache, gfp_mask & ~_ _GFP_DMA);
                  ... ... ...
                  size = SKB_DATA_ALIGN(size);
                  data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
             skb_shared_info结构用于处理IP fragments,以后介绍


        dev_alloc_skb:提供给device drivers在interrupt mode下使用,它里面会调用alloc_skb。
         kfree_skb & dev_kfree_skb: 用于free sk_buff,仅当skb->users为1时,才会真正释放cache,否则users--;
            sk_buff 可以具有一个dst_entry结构,利用dst_release函数来free之;另外destructor函数指针初始化的话也在此调用。

        skb_put(a), skb_push(b), skb_pull(c),skb_reserve(d)

        skb_reserve:在dota buffer的headroom预留一定空间,用于插入首部,或aligned on some boundary,一般在allocation之后不久调用,此时data和tail还是一样的;

             TCP会在headroom预留足够的空间用于存放所有层的首部(TCP,IP,link layer),MAX_TCP_HEADER表示最大的所有层首部大小(考虑最坏情况);TCP会将payload拷贝到自己的buffer中并加上自己的header,然后向下发并让各层加上首部;以下各层会更新skb->data和skb->len,如图:

        skb_shared_info & skb_shinfo:位于data block的尾部之后
            struct skb_shared_info {
              atomic_t        dataref;   //表示该datablock的user数量,与cloning有关
              unsigned int    nr_frags; //与IP fragments有关
              unsigned short tso_size;
              unsigned short tso_seqs;
              struct sk_buff *frag_list; //与IP fragments有关
              skb_frag_t      frags[MAX_SKB_FRAGS]; //与IP fragments有关
            };
            #define skb_shinfo(SKB)    ((struct skb_shared_info *)((SKB)->end))
            该函数用于引用skb_shared_info结构

        skb_clone函数:当一个data buffer需要供给多个对象使用时,使用该函数可以产生一个sk_buff结构拷贝,它们均指向同一个data域(包括head,data,sk_shared_info,其他data fragments);需要增加sk_shared_info->dataref;skb->cloned在两者中均设置为1,skb->users在副本中设置为1;该操作之后data块不能被写(即无需锁,但之前data块可写么?应该是可写的)


        pskb_copy & skb_copy:因为clone操作造成无法写data,这两个操作实现data块的拷贝并且可写;
            当仅需修改skb->start到skb->end之间内容时,使用pskb_copy;
            当还需要修改其他data分片的内容时,使用skb_copy;

        list management functions:用于处理sk_buff_head和相应的sk_buff队列的一系列函数,它们都必须是原子操作。
            skb_queue_head_init: 初始化sk_buff_head,空队列;
            skb_queue_head & skb_quere_tail: 把一个sk_buff加到头部或尾部;
            skb_dequeue & skb_dequeue_tail: 从头部或尾部移除一个sk_buff;
            skb_queue_purge: 清空队列
            skb_queue_walk: 循环访问队列的每个元素

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