博客首页 注册 建议与交流 排行榜 加入友情链接
推荐 投诉 搜索: 帮助

Free Gentux

Free & Open
   xiaosuo.cublog.cn
关于作者  
姓名:xiaosuo
职业:Linuxer
年龄:Not very young
位置:TianJin
个性介绍:Free & Open.

我的分类  




Large Receive Offload
前不久Linus发布了Linux-2.6.24,这个版本中加入了支持TCP协议的通用Large Receive Offload功能,它通过将多个TCP数据整合在一个skb结构中,并在稍后的某个时刻作为一个大的数据包交付给上层的网络协议栈,以减少上层协议栈处理skb的开销,提高Linux系统接收TCP数据包的能力。

当然,这一切都是需要网卡驱动程序支持的。不过,对于Linux社区来说,并不是什么问题,相信很快就会有大量的网卡驱动程序支持LRO。

要想理解LRO的工作原理,理解sk_buff结构体是必须的,这方面可以参考David S. Miller写的How SKBs work,它详细介绍了sk_buff结构体中每个成员的作用。有一点需要注意,sk_buff最多可以有三种方式保存数据:
  1. 数据被保存在skb->data指向的由kmalloc申请的内存缓冲区中,这个数据区通常被称为线性数据区,数据区的长度可由函数skb_headlen给出。
  2. 数据被保存在紧随于skb线性数据区尾部的共享结构体skb_shared_info中的成员frags所表示的内存页面中,skb_frag_t的数目由nr_frags给出,skb_frags_t中有数据在内存页面中的偏移量和数据区的大小。注意,因为这里直接引用的是内存页面,所以可以在它的基础上实现零拷贝的高效网络。
  3. 数据被保存于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负担的减轻也是很显然的。

 发表于: 2008-01-31,修改于: 2008-01-31 23:29 已浏览658次,有评论8条 推荐 投诉

  网友评论
  本站网友 时间:2008-08-14 05:34:19 IP地址:222.131.41.★
借这个改变也问个问题,请博主解答一下
2.6.24 改变了 netfilter 的 target 部分,调用时由 **pskb 变成了 *skb,这样的话如果想在 netfilter module 中 clone 一个包作处理,然后返回给系统自己制作的包,是不是就无法实现了?
2.6.24 为什么要作这样的改变决定呢?我查了很多资料都没找到答案

  xiaosuo 时间:2008-08-14 08:59:07 IP地址:60.29.39.★
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=3db05fea51cdb162cfa8f69e9cfb9e228919d2a9
从上面的记录来看,是Herbert Xu做出的更改,原因是没人用了。

至于你的问题,给你看一段注释(include/linux/netfilter/x_tables.h):
        /* Returns verdict. Argument order changed since 2.6.9, as this
           must now handle non-linear skbs, using skb_copy_bits and
           skb_ip_make_writable. */
        unsigned int (*target)(struct sk_buff *skb,

  本站网友 时间:2008-08-14 14:21:51 IP地址:219.143.94.★
博主你好,很高兴你能在百忙之中回答我的问题,而且说的这么详细
假如我现在有这样一个需求,我在 IP_FORWARD 中注册一个钩子,利用 conntrack 的特性这里得到的数据包应该已经是 defrag 过的,我要把数据包 IP 层后的 payload 部分扩展到 65535bytes,然后再放走(后面填充自己的内容,校验和自己重新计算),再利用 conntrack 的功能自动分片。
在 2.6.23 内核中,我可以利用 skb_copy_expand 做出一个符合我大小的数据包,之后填充正确的结构,kfree_skb 掉之前的,返回系统正确的 skb 指针。
在 2.6.24 以后的内容中该如何作呢?虽然可以用 skb_put 来增加尾部数据空间,但 tailroom 不够的话怎么办啊?

  xiaosuo 时间:2008-08-14 15:56:05 IP地址:60.29.39.★
参考这个函数: int skb_make_writable(struct sk_buff *skb, unsigned int writable_len)

  本站网友 时间:2008-08-14 16:39:37 IP地址:219.143.80.★
这样的话实现起来好像比原来复杂了很多,性能也会下降很多,是这样的吗?我不是很确定

  xiaosuo 时间:2008-08-14 16:50:42 IP地址:221.238.108.★
我观点与你恰恰相反。

  本站网友 时间:2008-08-14 17:39:02 IP地址:219.143.95.★
对不起我实在是没有明白,能不能详细讲解一下
我参考了 yfydz 写的关于 skb_make_writable 的文章,http://blog.chinaunix.net/u/12313/showart_164455.html
他分析的是 2.6.17,与我的内核 2.6.25 有些不同,2.6.25 中没有了 copy_skb 部分,更主要的工作在 __pskb_pull_tail 函数中,该函数可以实现对空间的扩充,是这样的吗?
另外,你的观点恰恰与我相反,是不是指性能会提升?这个又是为什么呢?
刚接触内核不久,很多东西都没入门呢,还请指点一下吧,谢谢了!

  xiaosuo 时间:2008-08-14 21:00:19 IP地址:218.69.98.★
skb_copy_expand是肯定要有数据拷贝的,而skb_make_writable则只有必要的时候才有拷贝。


  发表评论



Copyright © 2001-2006 ChinaUnix.net All Rights Reserved

感谢所有关心和支持过ChinaUnix的朋友们
页面生成时间:0.0751

京ICP证041476号