RSS,RPS和RFS之间的主要区别是什么?

Ale*_*lex 2 linux performance networking tcp linux-kernel

众所周知,有:https://www.kernel.org/doc/Documentation/networking/scaling.txt

  • RSS:接收侧缩放
  • RPS:接收数据包控制
  • RFS:接收流量转向

这是否意味着:

  • RSS - 允许我们使用许多CPU-Cores来处理来自以太网的Soft-irq(每个以太网队列一个CPU-Core)
  • RPS - 允许我们在同一个CPU核心上处理来自同一连接的所有数据包的Soft-irq
  • RFS - 允许我们处理来自同一个CPU-Core上同一个连接的所有数据包的Soft-irq,我们的应用程序的线程在这个CPU上运行此连接

那是对的吗?

osg*_*sgx 5

报价来自https://www.kernel.org/doc/Documentation/networking/scaling.txt.

  • RSS:接收侧缩放 - 是硬件实现的并且散列一些字节的数据包("通过网络和/或传输层报头的散列函数 - 例如,通过IP地址和数据包的TCP端口的4元组散列").实现是不同的,有些可能不会过滤最有用的字节,或者可能以其他方式受到限制.这种过滤和队列分配很快(在分组中只需要几个额外的周期来分类),但在某些网卡之间不能移植,或者不能与隧道数据包或一些罕见的协议一起使用.有时,您的硬件不支持足够的队列数,以便为每个逻辑CPU核心获取一个队列.

当延迟是一个问题或接收中断处理形成瓶颈时,应该启用RSS.在CPU之间传播负载会减少队列长度.

  • 接收分组控制(RPS)"在逻辑上是RSS的软件实现.在软件中,它必须在数据路径中稍后调用." 因此,这是硬件RSS的替代软件(仍会解析一些字节以将它们哈希到队列ID中),当您使用没有RSS的硬件或者想要基于比hw更复杂的规则进行分类时,或者具有无法解析的协议HW RSS分类器.但是使用RPS会使用更多的CPU资源,并且还会有额外的CPU间流量.

RPS比RSS具有一些优势:1)它可以与任何NIC一起使用,2)软件过滤器可以很容易地添加到新协议的哈希上,3)它不会增加硬件设备中断率(虽然它确实引入了处理器间中断(的IPI)).

  • RFS:接收流指导就像RSS(具有更多CPU开销的软件机制),但它不仅仅是散列到伪随机队列ID中,而是"考虑应用程序本地性".(因此,由于良好的局部性,数据包处理可能会更快).跟踪队列对于将处理接收数据的线程更加本地化,​​并且将数据包传递到正确的CPU核心.

RFS的目标是通过将数据包的内核处理引导到消耗数据包的应用程序线程正在运行的CPU来增加数据访问率.RFS依赖于相同的RPS机制将数据包排入另一个CPU的积压并唤醒该CPU....在RFS中,数据包不会直接通过其散列值转发,但散列用作流查找表的索引.此表将流映射到正在处理这些流的CPU.

  • 加速RFS - 具有hw支持的RFS.(检查您的网络驱动程序ndo_rx_flow_steer)"加速RFS是RFS到RPS的RSS:一种硬件加速的负载平衡机制,它使用软状态来根据消耗每个流的数据包的应用程序线程的运行情况来引导流."

类似的数据包传输方法(但数据包已经生成并准备发送,只需选择最佳队列发送它 - 以及更容易的后处理,如释放skb)

  • XPS:传输数据包控制:"记录从CPU到硬件队列的映射.此映射的目标通常是将队列专门分配给CPU的子集,其中这些队列的传输完成在CPU内处理这套"


Tgi*_*gul 5

osgx 的答案涵盖了主要差异,但需要指出的是,也可以同时使用 RSS 和 RPS。

RSS 控制用于接收数据包流的选定硬件队列。一旦满足某些条件,就会向软件发出中断。由 NIC 驱动程序定义的中断处理程序将是处理接收到的数据包的软件起点。那里的代码将从相关接收队列轮询数据包,可能执行初始处理,然后移动数据包以进行更高级别的协议处理。

此时可能会使用 RPS 机制(如果已配置)。驱动程序调用 netif_receive_skb(),它(最终)将检查 RPS 配置。如果存在,它将把 SKB 排入队列以便在选定的 CPU 上继续处理:

int netif_receive_skb(struct sk_buff *skb)
{
        ...
        return netif_receive_skb_internal(skb);
}

static int netif_receive_skb_internal(struct sk_buff *skb)
{
        ...
                int cpu = get_rps_cpu(skb->dev, skb, &rflow);

                if (cpu >= 0) {
                        ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail);
                        rcu_read_unlock();
                        return ret;
                }
        ...
}
Run Code Online (Sandbox Code Playgroud)

在某些情况下,明智的做法是同时使用 RSS 和 RPS,以避免接收端出现 CPU 利用率瓶颈。IPoIB(Infiniband IP)就是一个很好的例子。无需深入探讨太多细节,IPoIB 有一种只能打开单个通道的模式。这意味着所有传入流量将由单个核心处理。通过正确配置 RPS,部分处理负载可以由多个核心分担,从而显着提高此场景的性能。

既然提到了发送,值得注意的是,由接收过程(ACK、转发)产生的数据包传输将从 netif_receive_skb() 选择的同一核心进行处理。

希望这可以帮助。