非常详细的详谈struct sk_buff
排版太慢
难看的话可以下载WOR文档
专门详解struct_sk_buff
链接: http://pan.baidu.com/s/1gf8VNKR 密码: pquc
注:本文大部分内容来源于网络收集加上自己理解,如有不托之处,请指出,本人无任何版权!
全称socket buffers,简称skb,中文名字叫套接字缓存。它作为网络数据包的存放地点,使得协议栈中每个层都可以对数据进行操作,从而实现了数据包自底向上的传递。该结构维护一个收到的或者要发送的网络包。但其本身并不包含存放网络包的数据的存储区。存储区是另外单独分配的内存空间,但该结构说明了如何访问存储区空间,如何维护多个存储区空间以及存储网络包解析的成果。
所有的sk_buff是通过一个双向链表进行维护的。需要说明的是该双向链表中的一个元素是struct sk_buff_head类型。它相当于该双向链表的表头,其中有锁,链表元素个数等维护链表的相关信息。链表中其它的元素都是sk_buff类型。
这个结构被网络的不同层(MAC或者其他二层链路协议,三层的IP,四层的TCP或UDP等)使用,并且其中的成员变量在结构从一层向另一层传递时改变。 L4向L3传递前会添加一个L4的头部,同样,L3向L2传递前,会添加一个L3的头部。添加头部比在不同层之间拷贝数据的效率更高。由于在缓冲区的头部添加数据意味着要修改指向缓冲区的指针,这是个复杂的操作,所以内核提供了一个函数skb_reserve来完成这个功能。协议栈中的每一层在往下一层传递缓冲区前,第一件事就是调用skb_reserve在缓冲区的头部给协议头预留一定的空间。
skb_reserve同样被设备驱动使用来对齐接收到包的包头。如果缓冲区向上层协议传递,旧的协议层的头部信息就没什么用了。例如,L2的头部只有在网络驱动处理L2的协议时有用,L3是不会关心它的信息的。但是,内核并没有把L2的头部从缓冲区中删除,而是把有效荷载的指针指向L3的头部,这样做,可以节省CPU时间。
有些sk_buff成员变量的作用是方便查找或者是连接数据结构本身。内核可以把sk_buff组织成一个双向链表。当然,这个链表的结构要比常见的双向链表的结构复杂一点。就像任何一个双向链表一样,sk_buff中有两个指针next和prev,其中,next指向下一个节点,而prev指向上一个节点。在第一个节点前面会插入另一个结构sk_buff_head,这是一个辅助节点(作为sk_buff双向链表的头),它的定义如下:
struct sk_buff_head {
struct sk_buff -*next;
struct sk_buff -*prev;
__u32 qlen;
spinlock_t lock;
};
qlen代表链表元素的个数
lock用于防止对链表的并发访问
sk_buff和sk_buff_head的前两个元素是一样的:next和prev指针。这使得它们可以放到同一个链表中,尽管sk_buff_head要比sk_buff小得多。另外,相同的函数可以同样应用于sk_buff和sk_buff_head。
以下是truct sk_buff 数据结构(源代码)
truct sk_buff - socket buffer
struct sk_buff {
/* These two members must be first. */
struct sk_buff *next;//@next: Next buffer in list 链表中下一个缓存
struct sk_buff *prev;@prev: Previous buffer in list链表中前一个缓存
struct sk_buff_head *list;@list: List we are on//当前链表
struct sock *sk;@sk: Socket we are owned by//所属socket
struct timeval stamp;@stamp: Time we arrived(分组)到达的时间
struct net_device *dev;@dev: Device we arrived on/are leaving by分组离开的设备
struct net_device *input_dev;@input_dev: Device we arrived on
struct net_device *real_dev;@real_dev: The real device we areusing
union {
struct tcphdr *th;@nh: Network layer header
struct udphdr *uh;
struct icmphdr *icmph;
struct igmphdr *igmph;
struct iphdr *ipiph;
struct ipv6hdr *ipv6h;
unsigned char *raw;
} h;@h: Transport layer header传输层头标(tcp,udp,icmp,igmp,spx,raw)
union {
struct iphdr *iph;
struct ipv6hdr *ipv6h;
struct arphdr *arph;
unsigned char *raw;
} nh;@nh: