前不久Linus了Linux-2.6.24,这个版本中加入了支持TCP协议的通用功能,它通过将多个TCP数据整合在一个skb结构中,并在稍后的某个时刻作为一个大的数据包交付给上层的网络协议栈,以减少上层协议栈处理skb的开销,提高Linux系统接收TCP数据包的能力。
当然,这一切都是需要网卡驱动程序支持的。不过,对于Linux社区来说,并不是什么问题,相信很快就会有大量的网卡驱动程序支持LRO。
要想理解LRO的工作原理,理解sk_buff结构体是必须的,这方面可以参考写的,它详细介绍了sk_buff结构体中每个成员的作用。有一点需要注意,sk_buff最多可以有三种方式保存数据:
- 数据被保存在skb->data指向的由kmalloc申请的内存缓冲区中,这个数据区通常被称为线性数据区,数据区的长度可由函数skb_headlen给出。
- 数据被保存在紧随于skb线性数据区尾部的共享结构体skb_shared_info中的成员frags所表示的内存页面中,skb_frag_t的数目由nr_frags给出,skb_frags_t中有数据在内存页面中的偏移量和数据区的大小。注意,因为这里直接引用的是内存页面,所以可以在它的基础上实现零拷贝的高效网络。
- 数据被保存于skb_shared_info中的成员frag_list所表示的skb分片队列中。
以上数据区在读取的时候是从上往下依此进行的(可以参考函数skb_copy_datagram_iovec的实现),这也就要求保存数据的时候也要按序。
如果理解了以上部分,那么如何将多个skb数据包合并于一个数据包中就比较容易了。lro_receive_skb就是将一个skb表示的数据放在第3种缓冲区中,lro_receive_frags是为那些本身就把数据直接放在内存页面的网卡驱动设计的,它将数据放在第2种缓冲区中。
合并了N个skb的skb,能够一次性通过网络协议栈,而不是N次,对CPU负担的减轻也是很显然的。
阅读(8144) | 评论(8) | 转发(2) |