也谈UDP GSO和GRO

shixudong@163.com

近期偶而关注了一下Linux的网卡卸载技术,无奈网上相关资料大多已经过时,如同鸡肋。几经筛选,终于发现tailscale有三篇文章结合实际应用对TSO/GRO介绍得比较深入,最主要的还是紧密结合linux新内核特性,更有实用价值。本人也结合自己的理解做一些解读,对TSO/GRO的基本概念就不再展开,以供随时备查。

一、背景

TSO/LRO/UFO需要硬件支持,TSO针对TCP发送,UFO针对UDP发送(早已废弃),LRO针对数据接收(从未进入主流,事实上已废弃,被内核实现的GRO所取代)。GSO/GRO由内核实现,GRO是早期硬件LRO的软件升级版,虽然GRO是由内核实现,但仍需修改网卡驱动以调用内核GRO接口,网卡才能真正支持GRO功能,目前绝大部分在用网卡驱动都已完成支持GRO的升级。

GSO/GRO号称更加通用,主要是两个特征,一是因为纯软件实现,不需要专用硬件支持,并且GRO实现较硬件来说,因身处内核,掌握信息更多,接收卸载更为准确,这也直接导致了纯硬件接收卸载(LRO)的没落;二是不仅支持TCP,未来还能支持UDP,然而GSO/GRO对UDP的支持迟迟没有实现。随着QUIC逐步被数据中心采用,内核从v4.18才开始支持UDP GSO,对UDP GRO的支持更是到v5.0才提供。尽管如此,GSO/GRO对UDP的支持力度还是不够,一是不像TSO,对网络应用是透明的,UDP GSO/GRO对网络应用不透明,需要应用程序重新编码并设置相应的socket选项以启用GSO/GRO。其次目前流行的各种虚拟网络通常建立在UDP隧道虚拟设备之上,而最初的UDP GSO/GRO实现对虚拟设备的支持还不够完善。

二、TCP卸载抓包效果

网上资料虽然带有丰富的TCP卸载效果图,但通过tcpdump抓包实际观察各种卸载技术并进行对比分析更有意义,有助于进一步加深印象,此处不描述具体的抓包和分析过程,而是结合卸载技术的实现逻辑分析不同因素对抓包效果的影响。

1、抓包位置影响

根据tcpdump在内核的抓包位置,由于GRO在网卡驱动层面就被调用,GRO收包发生在抓包位置之前,可以观察到GRO开关效果。鉴于GRO开关在网络驱动调用的GRO接口里判断,如某个逻辑网卡驱动(如bridge)没有必要调用GRO,自然缺乏GRO判断机制,该网卡对应的GRO开关就无实际意义。

在早期内核,GSO拆包发生在抓包位置之后,抓包工具能观察到GSO开关效果,较新内核将GSO拆包调整到了抓包位置之前,就再也不能通过抓包观察GSO的开关效果了。

TSO开关在内核实际执行GSO拆包动作前判断,无论GSO开关与否,如TSO关或不支持TSO,tcpdump只能抓到分段后的小包,如TSO为on,总能抓到未分段的大包。对于逻辑网卡,TSO与硬件特性无关,表示其透传大包能力,只要ethtool能控制开关,也能被抓包观察。

2、多层网络影响

多层网络环境下(如中间有bridge),每层都是一个网络驱动程序,有自己的抓包位置和ethtool控制开关,每层抓包位置的逻辑不变,网络卸载则按如下逻辑发挥作用:在发送路径包含多个网络驱动时,如离内核更近的环节TSO为off,对大包进行了拆分操作,那么后续环节的TSO开关将失去实际意义,再也不能将其合并为大包。与之相对应,在接收路径包含多个网络驱动时,如离外部网络更近的环节GRO为on,对小包进行了合并操作,那么后续环节的GRO开关将失去实际意义,再也不能将其恢复小包。

3、同机转发路径影响

主机上层应用程序根据应用层逻辑,发出去的TCP包可为大包,也可为小包,对于TCP大包,由内核根据TSO开关控制发送到网卡驱动的数据包拆分与否。对于转发包,入口处是否合并取决于入口网卡GRO开关,转发环节上不做拆分与合并动作(二层桥转发允许GSO大包通过),出口处是否拆分取决于出口网卡TSO开关。如出口网卡在桥上,bridge和物理网卡的TSO都能影响出口包是否拆分。

三、UDP GSO/GRO

如前所述,自v4.18以来,内核开始支持UDP GSO,鉴于启用UDP GSO和传统GSO的方式不一致,需要在应用程序设置相应的socket选项显式启用,所以UDP GSO不用受ethtool的GSO开关控制。v4.18还新引入了与UDP GSO相配套的硬件特性tx-udp-segmentation,类似TSO,内核支持硬件卸载UDP发送,该特性刚发布时,仅个别物理网卡支持。对于逻辑网卡来说,该特性表示其UDP大包透传能力,从 v4.18到v5.10,部分逻辑网卡如bridge能充分利用该特性,透明转发UDP大包。自v5.11起,内核优化了逻辑网卡支持该特性的方式,独立虚拟网卡如wireguard等也开始支持该特性。然而美中不足的是,v5.11的修改,导致先前已支持该特性的部分逻辑网卡如bridge反而不再支持该特性(除非下挂的物理网卡也支持该特性)。UDP GSO虽然不受GSO开关控制,但同样使用了传统GSO的底层框架和机制,所以仅在网卡支持并开启tx-udp-segmentation特性时,才能使用抓包工具直观验证UDP GSO效果。

自v5.0起,内核开始支持UDP GRO,同样需要应用程序显式启用UDP GRO,同时因UDP GRO收包动作和传统GRO一致,由网卡驱动调用GRO接口实现,所以还受到网卡GRO开关的控制,这点和UDP GSO稍有区别。自v5.6起,支持UDP fraglist GRO/GSO(此处GSO主要配套用于转发),应用程序无需重新编码显式启用UDP GRO也能接收UDP GRO大包,只需入口网卡rx-gro-list为on,并且也适用于UDP GRO大包转发,大大拓展了UDP GRO的使用场景。自v5.12起,支持普通UDP GRO大包的转发(入口网卡rx-gro-list为off、rx-udp-gro-forwarding为on)。

三、wireguard-go的UDP GSO/GRO

本文开头提到的Tailscale关于wireguard-go优化的三篇文章,第一篇实现了wireguard-go对上层TCP应用的TSO/GRO支持,第二篇基于v4.18/v5.0的UDP GSO/GRO功能,实现了对底层UDP GSO/GRO支持,用于卸载wireguard协议本身。第三篇依赖v6.2内核tun驱动对UDP GSO/GRO的全面支持,自行实现了wg网卡可像TSO那样为上层应用透明提供UDP GRO大包接收和转发服务的支持。Wireguard-go在实现上述TCP/UDP GRO支持时,除了对底层UDP GRO的支持需要依托底层网卡的GRO机制外,对上层应用的GRO支持(包括TCP/UDP),无需依赖内核TCP/UDP GRO接口调用,所以该wg网卡与GRO相关的ethtool控制开关(如gro、rx-gro-list、rx-udp-gro-forwarding等)并无实际作用。

至于第三篇介绍的wireguard-go对上层应用的UDP GSO支持,亮点就是借助v6.2内核tun驱动,实现了wg网卡的tx-udp-segmentation特性(默认打开),允许wg网卡透明发送UDP GSO大包(内核wg自v5.11就支持了)。然而对于上层应用来说,要支持UDP GSO依然需要重新编码,否则就无法享受wg网卡的tx-udp-segmentation特性。此外wireguard-go在实现底层UDP GSO支持时,主要目标是为了给上层TSO/UDP GSO锦上添花,当上层不使用TSO或不支持UDP GSO功能时,底层即使支持UDP GSO也无法将上层多个TCP/UDP包合并为底层一个UDP大包。这个不足实际上是由GSO/GRO的内在机制造成的,GSO只负责硬件不支持时的数据包拆分,不负责发送路径上的数据包合并,而GRO则正好相反,只负责接收路径上的数据包合并。

四、rx-gro-list与rx-udp-gro-forwarding的区别

UDP GSO由于无法实现对UDP应用的透明支持,大规模推广存在一定困难,然而内核对UDP GRO的透明支持却越加完善,用户空间wireguard-go也是如此,如前所述,rx-gro-list可支持接收和转发UDP GRO大包,rx-udp-gro-forwarding可支持转发UDP GRO大包。在提供UDP大包转发服务时,与出口网卡的tx-udp-segmentation特性相结合,可大大提高UDP GRO大包的转发效率。

虽然rx-gro-list和rx-udp-gro-forwarding都能支持UDP GRO大包转发,但他们的处理方式有所区别,前者需要兼顾接收服务,采用了fraglist功能,后者仅用于转发,无需其他额外功能。针对处理方式的不同,转发UDP GRO大包时对出口网卡的特性要求也是不同的,rx-udp-gro-forwarding只要求出口网卡打开tx-udp-segmentation特性即可,而rx-gro-list要求出口网卡除了打开该特性外,还得同时打开tx-gso-list和tx-scatter-gather-fraglist特性。现代物理网卡如支持tx-udp-segmentation特性,基本上也会同时支持tx-gso-list和tx-scatter-gather-fraglist特性,然而对于逻辑网卡来说,估计是历史原因,目前尚不能同时支持这三种特性,晚于v5.11的wireguard,目前还不支持tx-scatter-gather-fraglist,晚于v6.2的tun(wireguard-go),目前还不支持tx-gso-list。因此如出口网卡由具备tx-udp-segmentation特性的逻辑网卡充当时,为提高UDP GRO的大包转发效率,入口网卡应启用rx-udp-gro-forwarding而非rx-gro-list开关。
Tailscale的第三篇文章也专门指出了这一点,不过描述得更神秘:“We recommend leaving rx-gro-list disabled. With rx-gro-list taking precedence over rx-udp-gro-forwarding, the effects of UDP GRO will be limited, reducing UDP throughput. rx-gro-list is a compelling, performance-enhancing feature, but the Linux kernel does not currently support a method to carry its benefits through the TUN driver. Instead, packets are segmented before being transmitted out a TUN device.”。事实上,我在wsl环境下重新编译wsl内核增加了wireguard网卡的tx-scatter-gather-fraglist特性后,wg作为出口网卡提供UDP GRO大包转发时,确实不再区分入口网卡的rx-udp-gro-forwarding和rx-gro-list不同处理方式了,而且如果出于效率考虑的话,此种情形下更应优先选择rx-gro-list而非rx-udp-gro-forwarding。这是因为当wireguard作为出口网卡提供转发服务时,针对的是上层应用,其底层wireguard协议数据包性质上始终属于本地接收包,如入口网卡选择rx-udp-gro-forwarding(仅适用转发)时,wg网卡的底层UDP就无法使用UDP GRO大包接收服务了,而入口网卡选择rx-gro-list的话,即能兼顾wg网卡底层的UDP GRO接收,又能兼顾其上层的UDP GRO转发。
当wireguard-go作为入口网卡,与出口网卡的tx-udp-segmentation特性配合使用时,因其在用户空间自行实现UDP GRO功能,前面已提过,rx-gro-list和rx-udp-gro-forwarding开关对其压根没有意义,也就不存在类似内核UDP GRO机制的两难选择。
最后补充一下,UDP GSO/GRO使用的底层框架和传统GSO/GRO完全一致,故TCP卸载抓包验证效果同样适用于UDP。内核引入的UDP GSO/GRO新特性,如网卡支持的话,tx-udp-segmentation将默认开启,其他特性默认关闭,需要手动开启。wireguard-go实现的UDP GRO,默认启用并且无开关控制,而其GSO实现,完全基于内核,tx-udp-segmentation也是默认开启,可以手动关闭。
此外顺便提一下,对于业务实时性要求高、但吞吐量要求不高的场合,开启UDP GRO将引入不必要的延时,建议同时关闭UDP GRO的本机接收和转发功能。

                
  • 19
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRO (Large Receive Offload) 和 GRO (Generic Receive Offload) 是网络协议栈中的两种技术,用于优化数据包的接收处理。 LRO 主要用于 TCP,而 GRO 则适用于所有传输协议 。 LRO 是一种在网卡上进行数据包处理的技术,它将多个接收到的小数据包合并成一个大的数据包,减少了处理的开销。这种技术可以有效地提高网络性能和吞吐量。然而,LRO 只适用于 TCP 协议 。 GRO 是在内核网络协议栈中实现的技术,它通过合并接收到的数据包来减少处理的开销,提高网络性能。与 LRO 不同,GRO 可以应用于所有传输协议,而不仅限于 TCP。GRO 还保留了每个接收到的数据包的熵信息,这对于像路由器这样的应用非常重要。通过匹配条件,如源/目的地址、TOS/协议字段、源/目的端口等,可以进行适当的数据包合并 。 TSO (TCP Segmentation Offload) 和 GSO (Generic Segmentation Offload) 是用于发送数据包的技术。它们的作用是将大的数据包分割成更小的片段,以提高传输效率。TSO 主要用于 TCP,而 GSO 则适用于所有传输协议 。 总结起来,LRO 和 GRO 是用于接收数据包的技术,通过合并数据包减少处理的开销。TSO 和 GSO 是用于发送数据包的技术,通过分割大的数据包提高传输效率。这些技术都在 Linux 内核的网络协议栈中发挥着重要的作用,提高了网络性能和吞吐量 。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Linux环境中的网络分段卸载技术 GSO/TSO/UFO/LRO/GRO](https://blog.csdn.net/Rong_Toa/article/details/108748689)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值