为什么 GRO 更高效?

Why is GRO more efficient?

Generic Receive Offload (GRO) 是 Linux 中的一种软件技术,用于聚合属于同一流的多个传入数据包。链接的文章声称 CPU 利用率降低了,因为不是每个数据包单独遍历网络堆栈,而是单个聚合数据包遍历网络堆栈。

但是,如果看一下 GRO 的源代码,感觉这本身就是一个网络堆栈。例如,传入的 TCP/IPv4 数据包需要经过:

每个函数都执行解封装并查看各自的 frame/network/transport headers,正如 "regular" 网络堆栈所期望的那样。

假设机器不执行 firewall/NAT 或其他明显昂贵的 per-packet 处理,"regular" 网络堆栈中的什么东西如此缓慢以至于 "GRO network stack" 可以加速?

简短回答:GRO 是在接收流程的早期完成的,因此它基本上减少了 ~(GRO 会话大小/MTU) 的操作数。

更多详情: 最常见的 GRO 函数是 napi_gro_receive()。几乎所有网络驱动程序都使用了 93 次(在内核 4.14 中)。通过在 NAPI 级别使用 GRO,驱动程序很早就在接收完成处理程序中对大型 SKB 进行聚合。这意味着接收堆栈中的所有下一个函数做的处理要少得多。

这是 Mellanox ConnectX-4Lx NIC 的 RX 流程的一个很好的可视化表示(抱歉,这是我可以访问的):

如您所见,GRO 聚合位于调用堆栈的最底部。您还可以查看之后完成了多少工作。想象一下,如果这些功能中的每一个都在单个 MTU 上运行,您将拥有多少开销。

希望这对您有所帮助。