出处:http://ericxiao.cublog.cn/
------------------------------------------
sk_buff结构分析
sk_buff是我们遇到的第二个重要的结构,在内核中经常被缩写成skb.在linux 2.6.21它被定义成:
struct sk_buff {
//指向下一个skb
struct sk_buff *next;
//上一个skb
struct sk_buff *prev;
struct sk_buf0f_head *list;
//对应的sock。这也是个重要的结构,在传输层的时候我们再来分析
struct sock *sk;
//接收或者发送时间戳
struct timeval stamp;
//接收或者发送时对应的net_device
struct net_device *dev;
//接收的net_device
struct net_device *input_dev;
//数据包对应的真实net_device.关于虚拟设备可以在之后的网桥模式分析中讨论
struct net_device *real_dev;
//ip层的相关信息
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;
/*
* 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[40];
//各层的数据长度
unsigned int len,
data_len,
mac_len,
csum;
unsigned char local_df,
cloned,
pkt_type,
ip_summed;
__u32 priority;
unsigned short protocol,
security;
void (*destructor)(struct sk_buff *skb);
#ifdef CONFIG_NETFILTER
unsigned long nfmark;
__u32 nfcache;
__u32 nfctinfo;
struct nf_conntrack *nfct;
#ifdef CONFIG_NETFILTER_DEBUG
unsigned int nf_debug;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
struct nf_bridge_info *nf_bridge;
#endif
#endif /* CONFIG_NETFILTER */
#if defined(CONFIG_HIPPI)
union {
__u32 ifield;
} private;
#endif
#ifdef CONFIG_NET_SCHED
__u32 tc_index; /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
__u32 tc_verd; /* traffic control verdict */
__u32 tc_classid; /* traffic control classid */
#endif
#endif
/* These elements must be at the end, see alloc_skb() for details. */
unsigned int truesize;
//引用计数
atomic_t users;
//存储空间的起始地址
unsigned char *head,
//网络数据的起始起址
*data,
//存放网络数据的结束地址
*tail,
//存储空间的结束地址
*end;
}
对应我们上面的网卡驱动分析。接收到的数据是存放在data至tail之间的区域。
Skb通常还有常用的几个函数,一一列举分析如下:
struct sk_buff *alloc_skb(unsigned int size,int gfp_mask)
分配存储空间为sixe的skb,内存分配级别为gfp_mask.注意这里的存储空间的含义,即为skb->data至skb->tail的区域
struct sk_buff *skb_clone(struct sk_buff *skb, int priority)
克隆出的skb指向同一个结构,同时会增加skb的引用计数
struct sk_buff *skb_copy(const struct sk_buff *skb, int priority)
复制一个全新的skb
void kfree_skb(struct sk_buff *skb)
当skb的引用计数为1的时候,释放此skb
unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
使skb的存储空间扩大len.即使tail指针下移
unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
push,即推出一段数据,使data指针下层。
void skb_reserve(struct sk_buff *skb, unsigned int len)
该操作使data指针跟tail指针同时下移,即扩大存储区域之前的空间
int skb_headroom(const struct sk_buff *skb)
返回data之前可用的空间数量
int skb_tailroom(const struct sk_buff *skb)
返回缓存区中可用的空间大小