链表管理
在对skb链表的操作中,为了防止被其他异步操作打断,在操作前都必须现获取SKB头节点中(sk_buff_head结构)的自旋锁,然后才能访问队列中的元素。该链表头结构如下:
struct sk_buff_head {
/* These two members must be first. */
struct sk_buff *next;
struct sk_buff *prev;
/*链表中的节点数,即队列长度*/
__u32 qlen;
/*用来控制SKB链表并发操作的自旋锁*/
spinlock_t lock;
};
对链表操作也增加了很多函数,包括初始化、入队列、出队列等等,也在skbuff.h中。
Skb_shared_info结构
在alloc_skb()看到,其中中分配数据部分分配了一个该结构,在数据缓存区的末尾,保存了数据块的附加信息。如下:
#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end))
该结构定义如下:
struct skb_shared_info {
/*引用计数,当一个数据缓存区被多个SKB的描述符引用时
就会设置相应的计数*/
atomic_t dataref;
/*ip分片的存储有关,片段数*/
unsigned short nr_frags;
/*生成GSO段时的MSS,因为GSO段的长度是与发送该段的套接口中
合适MSS的整数倍*/
unsigned short gso_size;
/* Warning: this field is not always filled in (UFO)! */
/*GSO段的长度是gso_size的整数倍,即用gso_size来分割大段时
产生的段数*/
unsigned short gso_segs;
/*该SKB中的数据支持的GSO类型*/
unsigned short gso_type;
__be32 ip6_frag_id;
/*ip分片的存储有关,使用情况如下:
1,用于在接收分片组后连接多核分片,组成一个完整的IP数据报;
2,在UDP数据报的传输中,将待分片的SKB连接到第一个SKB中,然后在
传输过程中能够快速的分片;
3,用于存放FRAGLIST类型的聚合分散I/O的数据包,如果输出网络设备支持
FRAGLIST类型的聚合分散I/O,则可以直接输出*/
struct sk_buff *frag_list;
/*ip分片的存储有关,片段以关联的方式存储在该数组中*/
skb_frag_t frags[MAX_SKB_FRAGS];
};
其中skb_frag_t类型如下:
struct skb_frag_struct {
/*指向文件系统缓存页的指针*/
struct page *page;
/*数据起始地址在文件系统缓存页中的偏移*/
__u16 page_offset;
/*数据在文件系统缓存页面中使用的长度*/
__u16 size;
};
关于该结构的操作在后面的协议分析中碰到后进行阅读。接下来依着协议栈的层次进行分析和学习,从驱动一直到传输层。只会涉及最基本的几个协议(TCP、IP、UDP、ICMP以及ARP等)。