141 struct sk_buff *frag_list 135 unsigned short nr_frags 142 skb_frag_t frags[MAX_SKB_FRAGS] nr_frags, frags和frag_list与IP分片的存储有关。通常数据都存储在线性区域中,但当为了支持聚合分散I/O,数据需要存储在支持聚合分散I/O的区域中。frags和frag_list支持聚合分散I/O数据,而“零拷贝”技术也是需要聚合分散I/O支持的。 那什么是聚合分散I/O呢?网络中创建一个发送报文的过程包括组合多个片。报文数据必须从用户空间拷贝到内核空间,同时加上由网络协议栈各层的首部。这个组合可能要求相当数量的数据拷贝。但如果发送报文的网络接口能够支持聚合分散I/O,报文就无需组装成一个单块,可避免大量拷贝。聚合分散I/O从用户空间启动“零拷贝”网络发送。内核传递发送报文给hard_start_xmit()之前需要判断网络设置是否支持NETIF_F_SG,不然只能对分散的报文进行线性化处理,再聚合成一个单独的报文。如果网络设备已经设置了该标志, 接下来就要检查nr_frags的值,因为该字段确定了片段数,这些分散的片段用关联的方式存储在frags数组中。 接下来再来看一下skb_frag_struct结构。 120#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 2) 121 122typedef struct skb_frag_struct skb_frag_t; 123 124struct skb_frag_struct { 125 struct page *page; 126 __u16 page_offset; 127 __u16 size; 128}; 120 #defineMAX_SKB_FRAGS (65536/PAGE_SIZE + 2) MAX_SKB_FRAGS为frags数组的大小,因此最多可支持到64K个分片。 125 struct page *page 指向文件系统缓存页的指针。 126 __u16 page_offset 数据起始地址在文件系统缓存页中的偏移。 127 __u16 size 数据在文件系统缓存页面中使用的长度。 frag_list有以下几种使用方法: 1)使用于在接收分片组后,链接多个分片,组成一个完成IP数据报; 2)在UDP数据报的输出中,将待分片的SKB链接到第一个SKB中,然后在输出过程中能够快速的分片; 3)用于存放FRAGLIST类型的聚合分散I/O的数据包,如果输出网络设备支持FRAGLIST类型的聚合分散I/O(目前只有回环设备支持),则可以直接输出。 frags和nr_frags用于支持SG类型的聚合分散I/O分片。frags是用于存放聚合分散I/O分片的数组。nr_frags为当前使用聚合分散I/O分片的数量,即为frags数组中使用的数量,不超过MAX_SKB_FRAGS。 skb_is_nonlinear()用来测试SKB的缓冲区聚合分散I/O缓存区,实际上就是判断sk_buff的data_len成员。而skb_linearize()可以把含有聚合分散I/O缓存区中的数据线性化到线性缓冲区中。线性过程中涉及到数据复制,所以如果多次进行数据的复制,将严重影响系统性能,因此在没有必要的时候,建议不要进行数据的线性化。 |