您的位置:首页 > 理论基础 > 数据结构算法

Linux内核--网络协议栈深入分析(一)--与sk_buff有关的几个重要的数据结构

2013-04-13 13:36 609 查看
本文分析基于Linux Kernel 3.2.1

原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7971463

更多请查看专栏http://blog.csdn.net/column/details/linux-kernel-net.html

作者:闫明

几个月之前做了关于Linux内核版本1.2.13网络栈的结构框架分析并实现了基于Netfilter的包过滤防火墙,这里以内核3.2.1内核为例来进一步分析,更全面的分析网络栈的结构。

1、先说一下sk_buff结构体

这个结构体是套接字的缓冲区,详细记录了一个数据包的组成,时间、网络设备、各层的首部及首部长度和数据的首尾指针。

下面是他的定义,挺长

[cpp] view
plaincopy

struct sk_buff {

/* These two members must be first. */

struct sk_buff *next;

struct sk_buff *prev;

ktime_t tstamp;

struct sock *sk;

struct net_device *dev;

/*

* This is the control buffer. It is free to use for every

* layer. Please put your private variables there. If you

* want to keep them across layers you have to do a skb_clone()

* first. This is owned by whoever has the skb queued ATM.

*/

char cb[48] __aligned(8);

unsigned long _skb_refdst;

#ifdef CONFIG_XFRM

struct sec_path *sp;

#endif

unsigned int len,

data_len;

__u16 mac_len,

hdr_len;

union {

__wsum csum;

struct {

__u16 csum_start;

__u16 csum_offset;

};

};

__u32 priority;

kmemcheck_bitfield_begin(flags1);

__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;

kmemcheck_bitfield_end(flags1);

__be16 protocol;

void (*destructor)(struct sk_buff *skb);

#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)

struct nf_conntrack *nfct;

#endif

#ifdef NET_SKBUFF_NF_DEFRAG_NEEDED

struct sk_buff *nfct_reasm;

#endif

#ifdef CONFIG_BRIDGE_NETFILTER

struct nf_bridge_info *nf_bridge;

#endif

int skb_iif;

#ifdef CONFIG_NET_SCHED

__u16 tc_index; /* traffic control index */

#ifdef CONFIG_NET_CLS_ACT

__u16 tc_verd; /* traffic control verdict */

#endif

#endif

__u32 rxhash;

__u16 queue_mapping;

kmemcheck_bitfield_begin(flags2);

#ifdef CONFIG_IPV6_NDISC_NODETYPE

__u8 ndisc_nodetype:2;

#endif

__u8 ooo_okay:1;

__u8 l4_rxhash:1;

kmemcheck_bitfield_end(flags2);

/* 0/13 bit hole */

#ifdef CONFIG_NET_DMA

dma_cookie_t dma_cookie;

#endif

#ifdef CONFIG_NETWORK_SECMARK

__u32 secmark;

#endif

union {

__u32 mark;

__u32 dropcount;

};

__u16 vlan_tci;

sk_buff_data_t transport_header;

sk_buff_data_t network_header;

sk_buff_data_t mac_header;

/* These elements must be at the end, see alloc_skb() for details. */

sk_buff_data_t tail;

sk_buff_data_t end;

unsigned char *head,

*data;

unsigned int truesize;

atomic_t users;

};

可以看到新版本内核中发生了很多变化,其中数据包的首部在早期版本是以union的形式定义的,例如mac_header的定义方式如下:

[cpp] view
plaincopy

union{

struct ethhdr *ethernet;

unsigned char *raw;

}mac;

这里是以指针的形式给出的

[cpp] view
plaincopy

#ifdef NET_SKBUFF_DATA_USES_OFFSET

typedef unsigned int sk_buff_data_t;

#else

typedef unsigned char *sk_buff_data_t;

#endif

这里主要说明下后面几个后面的四个属性的含义head、data、tail、end

head是缓冲区的头指针,data是数据的起始地址,tail是数据的结束地址,end是缓冲区的结束地址。



char cb[48] __aligned(8);中的48个字节是控制字段,配合各层协议工作,为每层存储必要的控制信息。

2、sk_buff_head结构体

[cpp] view
plaincopy

struct sk_buff_head {

/* These two members must be first. */

struct sk_buff *next;

struct sk_buff *prev;

__u32 qlen;

spinlock_t lock;

};

这个结构体比较简单,前面两个指针是用于和sk_buff结构串成双向链表,用于管理sk_buff双链表,qlen属性表示该链表中sk_buff的数目,lock是自旋锁。

3、skb_shared_info结构体

[cpp] view
plaincopy

struct skb_shared_info {

unsigned short nr_frags;

unsigned short gso_size;//尺寸

/* Warning: this field is not always filled in (UFO)! */

unsigned short gso_segs;//顺序

unsigned short gso_type;

__be32 ip6_frag_id;

__u8 tx_flags;

struct sk_buff *frag_list;//分片的sk_buff列表

struct skb_shared_hwtstamps hwtstamps;//硬件时间戳

/*

* Warning : all fields before dataref are cleared in __alloc_skb()

*/

atomic_t dataref;//使用计数

/* Intermediate layers must ensure that destructor_arg

* remains valid until skb destructor */

void * destructor_arg;

/* must be last field, see pskb_expand_head() */

skb_frag_t frags[MAX_SKB_FRAGS];

};

该类型用来管理数据包分片信息,通过宏可以表示与skb的关系

[cpp] view
plaincopy

#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB)))

[cpp] view
plaincopy

#ifdef NET_SKBUFF_DATA_USES_OFFSET

static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)

{

return skb->head + skb->end;

}

#else

static inline unsigned char *skb_end_pointer(const struct sk_buff *skb)

{

return skb->end;

}

#endif

可以看到如果用户没有自己使用偏移量,就是skb的end属性指针,也就是该信息存储在缓冲区之后。

下篇将看有关sk_buff的操作函数的实现。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐