您的位置:首页 > 其它

2.6内核的sk_buff结构分析

2010-10-26 11:58 435 查看
原文

http://andychenkan.blog.163.com/blog/static/56300913200961695519363/

struct sk_buff {

/* These two members must be first. */

//以下两个变量用于将sk_buff链接到一个双向循环链表中

struct sk_buff *next;

struct sk_buff *prev;

//此报文所属的sock结构,此值在本机发出的报文中有效,从网络设备收到

//的报文此值为空

struct sock *sk;

//此报文收到时的时间

ktime_t tstamp;

//收到此报文的网络设备

struct net_device *dev;

//此报文的路由

union {

struct dst_entry *dst;

struct rtable *rtable;

};

struct sec_path *sp;

/*

* 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];

//len表示存储区的数据长度和分片长度之和

unsigned int len,

//da

ta_len表示分片长度

data_len;

//mac_len表示mac头的长度

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

//pkt_type,数据报的类型。这个值在网卡驱动程序中由函数eth_type_trans通过判断

//目的以太网地址来确定。如果目的地址是 FF:FF:FF:FF:FF:FF,则为广播地址,

//pkt_type=PACKET_BROADCAST,如果最高位为1,则为组播地址,pkt_type=PACKET_MULTICAST,

//如果目的mac地址跟本机mac地址不相等,则不是发给本机的数据报,

//pkt_type=PACKET_OTHERHOST,否则就是缺省值PACKET_HOST。

__u8 pkt_type:3,

fclone:2,

ipvs_property:1,

peeked:1,

nf_trace:1;

//protocol, 它的值是以太网首部的第三个成员,即帧类型,对于IP数据来讲,

//就是ETH_P_IP(0x8000),对ARP数据报来讲,就是ETH_P_ARP(0x8086)

__be16 protocol;

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

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

struct nf_conntrack *nfct;

struct sk_buff *nfct_reasm;

#endif

#ifdef CONFIG_BRIDGE_NETFILTER

struct nf_bridge_info *nf_bridge;

#endif

int iif;

__u16 queue_mapping;

#ifdef CONFIG_NET_SCHED

__u16 tc_index; /* traffic control index */

#ifdef CONFIG_NET_CLS_ACT

__u16 tc_verd; /* traffic control verdict */

#endif

#endif

#ifdef CONFIG_IPV6_NDISC_NODETYPE

__u8 ndisc_nodetype:2;

#endif

#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE)

__u8 do_not_encrypt:1;

#endif

/* 0/13/14 bit hole */

#ifdef CONFIG_NET_DMA

dma_cookie_t dma_cookie;

#endif

#ifdef CONFIG_NETWORK_SECMARK

__u32 secmark;

#endif

__u32 mark;

__u16 vlan_tci;

//传输层报文头

sk_buff_da
ta_t transport_header;

//网络报文头

sk_buff_da
ta_t network_header;

//链路报文头

sk_buff_da
ta_t mac_header;

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

//以下四个变量指向此报文的存储区

//网络报文在存储空间里的存放的顺序

//依次是:链路层的头部,网络层的头部,传输层的头部,传输层的数据

//tail指向网络报文的结束地址

sk_buff_data_t tail;

//end指向存储空间的结束地址

sk_buff_data_t end;

//head指向存储空间的起始地址

unsigned char *head,

//data指向网络报文的起始地址

*data;

//truesize表示存储区总长度(即end-head)和sk_buff本身长度之和

unsigned int truesize;

//表示该sk_buff结构实例被引用的计数。这个是结构本身的引用计数,

//而不是其对应的存储区的引用计数。

atomic_t users;

};

用红色标记这三个成员,分别是传输头,网络头以及mac头相对于Sk_buff的head的偏移。有了这三个成员,可以说为内核编程人员提供了更便利的获取传输层、网络层和MAC层头的偏移。并且,内核也新增了几个函数,来提供获取这些偏移的接口:
#ifdef NET_SKBUFF_DATA_USES_OFFSET
如果使用了offset来表示偏移的话,就是说是一个相对偏移的情况:

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

{

return skb->head + skb->transport_header;

}
static inline void skb_reset_transport_header(struct sk_buff *skb)

{

skb->transport_header = skb->data - skb->head;

}
static inline void skb_set_transport_header(struct sk_buff *skb,

const int offset)

{

skb_reset_transport_header(skb);

skb->transport_header += offset;

}
static inline unsigned char *skb_network_header(const struct sk_buff *skb)

{

return skb->head + skb->network_header;

}
static inline void skb_reset_network_header(struct sk_buff *skb)

{

skb->network_header = skb->data - skb->head;

}
static inline void skb_set_network_header(struct sk_buff *skb, const int offset)

{

skb_reset_network_header(skb);

skb->network_header += offset;

}
static inline unsigned char *skb_mac_header(const struct sk_buff *skb)

{

return skb->head + skb->mac_header;

}
static inline int skb_mac_header_was_set(const struct sk_buff *skb)

{

return skb->mac_header != ~0U;

}
static inline void skb_reset_mac_header(struct sk_buff *skb)

{

skb->mac_header = skb->data - skb->head;

}
static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)

{

skb_reset_mac_header(skb);

skb->mac_header += offset;

}
#else /* NET_SKBUFF_DATA_USES_OFFSET */
不使用相对偏移的情况
static inline unsigned char *skb_transport_header(const struct sk_buff *skb)

{

return skb->transport_header;

}
static inline void skb_reset_transport_header(struct sk_buff *skb)

{

skb->transport_header = skb->data;

}
static inline void skb_set_transport_header(struct sk_buff *skb,

const int offset)

{

skb->transport_header = skb->data + offset;

}
static inline unsigned char *skb_network_header(const struct sk_buff *skb)

{

return skb->network_header;

}
static inline void skb_reset_network_header(struct sk_buff *skb)

{

skb->network_header = skb->data;

}
static inline void skb_set_network_header(struct sk_buff *skb, const int offset)

{

skb->network_header = skb->data + offset;

}
static inline unsigned char *skb_mac_header(const struct sk_buff *skb)

{

return skb->mac_header;

}
static inline int skb_mac_header_was_set(const struct sk_buff *skb)

{

return skb->mac_header != NULL;

}
static inline void skb_reset_mac_header(struct sk_buff *skb)

{

skb->mac_header = skb->data;

}
static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)

{

skb->mac_header = skb->data + offset;

}

#endif /* NET_SKBUFF_DATA_USES_OFFSET */

1、TCP层获取相关偏移的函数
static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb)

{

return (struct tcphdr *)skb_transport_header(skb);

}
这个函数用来获得sk_buff结构中TCP头的指针
static inline unsigned int tcp_hdrlen(const struct sk_buff *skb)

{

return tcp_hdr(skb)->doff * 4;

}
这个函数用来获得TCP头的长度
static inline unsigned int tcp_optlen(const struct sk_buff *skb)

{

return (tcp_hdr(skb)->doff - 5) * 4;

}
获取tcp option的长度
2、IP相关的函数
static inline struct iphdr *ip_hdr(const struct sk_buff *skb)

{

return (struct iphdr *)skb_network_header(skb);

}
该函数获得ip头
static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)

{

return (struct iphdr *)skb_transport_header(skb);

}
该函数获得ipip头,实际上偏移已经跑到了传输层的开始
3、MAC相关函数
static inline struct ebt_802_3_hdr *ebt_802_3_hdr(const struct sk_buff *skb)

{

return (struct ebt_802_3_hdr *)skb_mac_header(skb);

}
获取802.3MAC头指针。

static inline struct ethhdr *eth_hdr(const struct sk_buff *skb)

{

return (struct ethhdr *)skb_mac_header(skb);

}

获取以太网MAC头指针。以太网头指针结构体:

struct ethhdr {

unsigned char h_dest[ETH_ALEN]; /* destination eth addr */

unsigned char h_source[ETH_ALEN]; /* source ether addr */

__be16 h_proto; /* packet type ID field */

} __attribute__((packed));

内核中网络地址转化为字符串形式的IP地址的宏定义:

#define NIPQUAD(addr) /

((unsigned char *)&addr)[0], /

((unsigned char *)&addr)[1], /

((unsigned char *)&addr)[2], /

((unsigned char *)&addr)[3]

#define NIPQUAD_FMT "%u.%u.%u.%u"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: