出处: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) 返回缓存区中可用的空间大小