Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1371733
  • 博文数量: 284
  • 博客积分: 3251
  • 博客等级: 中校
  • 技术积分: 3046
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-26 17:23
文章分类

全部博文(284)

文章存档

2019年(2)

2018年(5)

2015年(19)

2014年(13)

2013年(10)

2012年(235)

分类: LINUX

2012-12-21 16:23:04

套接字缓冲区用结构体struct sk_buff表示,它用于在网络子系统中的各层之间传递数据,处于一个核心地位,非常之重要。它包含了一组成员数据用于承载网络数据,同时,也定义了在这些数据上操作的一组函数。下面是其完整的定义:
    struct sk_buff {
        struct sk_buff      *next;
        struct sk_buff      *prev;

        struct sock     *sk;
        struct skb_timeval  tstamp;
        struct net_device   *dev;
        struct net_device   *input_dev;

        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;

        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,
                        ipvs_property:1;
        __be16          protocol;

        void            (*destructor)(struct sk_buff *skb);
#ifdef CONFIG_NETFILTER
        __u32           nfmark;
        struct nf_conntrack *nfct;
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
        struct sk_buff      *nfct_reasm;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
        struct nf_bridge_info   *nf_bridge;
#endif
#endif /* CONFIG_NETFILTER */
#ifdef CONFIG_NET_SCHED
        __u16           tc_index;
#ifdef CONFIG_NET_CLS_ACT
        __u16           tc_verd;
#endif
#endif


        unsigned int    truesize;
        atomic_t        users;
        unsigned char   *head,
                        *data,
                        *tail,
                        *end;
    };
    这是一个比较宠大的结构体,为了便于理解,我们分成多块进行分析。
    为了使用套接字缓冲区,内核创建了两个后备高速缓存(looaside cache),它们分别是skbuff_head_cache和skbuff_fclone_cache,协议栈中所使用到的所有的sk_buff结构都 是从这两个后备高速缓存中分配出来的。两者的区别在于skbuff_head_cache在创建时指定的单位内存区域的大小是sizeof(struct sk_buff),可以容纳任意数目的struct sk_buff,而skbuff_fclone_cache在创建时指定的单位内存区域大小是2*sizeof(struct sk_buff)+sizeof(atomic_t),它的最小区域单位是一对strcut sk_buff和一个引用计数,这一对sk_buff是克隆的,即它们指向同一个数据缓冲区,引用计数值是0,1或2,表示这一对中有几个sk_buff 已被使用。
    创建一个套接字缓冲区,最常用的操作是alloc_skb,它在skbuff_head_cache中创建一个struct sk_buff,如果要在skbuff_fclone_cache中创建,可以调用__alloc_skb,通过特定参数进行。
    struct sk_buff的成员head指向一个已分配的空间的头部,该空间用于承载网络数据,end指向该空间的尾部,这两个成员指针从空间创建之后,就不能被修 改。data指向分配空间中数据的头部,tail指向数据的尾部,这两个值随着网络数据在各层之间的传递、修改,会被不断改动。所以,这四个指针指向共同 的一块内存区域的不同位置,该内存区域由__alloc_skb在创建缓冲区时创建,四个指针间存在如下关系:
        head <= data <= tail < end
    那指向的这块内存区域有多大呢?一般由外部根据需要传入。外部设定这个大小时,会根据实际数据量加上各层协议的首部,再加15(为了处理对齐)传入,在 __alloc_skb中根据各平台不同进行长度向上对齐。但是,我们另外还要加上一个存放结构体struct skb_shared_info的空间,也就是说end并不真正指向内存区域的尾部,在end后面还有一个结构体struct skb_shared_info,下面是其定义:
        struct skb_shared_info{
            atomic_t        dataref;    //引用计数。
            unsigned short  nr_frags;   //数据片段的数量。
            unsigned short  tso_size;
            unsigned short  tso_segs;
            unsigned short  ufo_size;
            unsigned int    ip6_frag_id;
            struct sk_buff  *frag_list;     //数据片段的链表。
            skb_frag_t  frags[MAX_SKB_FRAGS];   //每一个数据片段的长度。
        };
    这个结构体存放分隔存储的数据片段,将数据分解为多个数据片段是为了使用分散/聚集I/O。
    如果是在skbuff_fclone_cache中创建,则创建一个struct sk_buff后,还要把紧邻它的一个struct sk_buff的fclone成员置标志SKB_FCLONE_UNAVAILABLE,表示该缓冲区还没有被创建出来,同时置自己的fclone为 SKB_FCLONE_ORIG,表示自己可以被克隆。最后置引用计数为1。
    最后,truesize表示缓存区的整体长度,置为sizeof(struct sk_buff)+传入的长度,不包括结构struct skb_shared_info的长度。
阅读(873) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~