接收端缩放版本 2 (RSSv2)

接收端缩放可提高与处理多处理器系统上网络数据相关的系统性能。 NDIS 6.80 及更高版本支持 RSS 版本 2 (RSSv2),它通过提供队列按 VPort 动态分布来扩展 RSS。

概述

与 RSSv1 相比,RSSv2 缩短了 CPU 负载测量和更新间接表之间的时间,从而避免了高流量情况下速度变慢。 为此,RSSv2 在处理请求的处理器上下文中,以 IRQL = DISPATCH_LEVEL 执行其操作,并且仅在指向当前处理器的间接表条目的子集上进行操作。 这意味着 RSSv2 可以比 RSSv1 更快速地将接收队列动态分散到多个处理器上。

RSSv2 中为微型端口驱动程序引入了两个 OID:OID_GEN_RECEIVE_SCALE_PARAMETERS_V2OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES,分别用于设置适当的 RSS 功能和控制间接表。 OID_GEN_RECEIVE_SCALE_PARAMETERS_V2 是一个常规 OID,而 OID_GEN_RSS_SET_INDIRECTION_ENTRIES 是一个同步 OID,不能返回 NDIS_STATUS_PENDING。 有关这些 OID 的详细信息,请参阅其单独的参考页。 有关同步 OID 的详细信息,请参阅 NDIS 6.80 中的同步 OID 请求接口。

RSSv2 术语

本文使用以下术语:

Term 定义
RSSv1 第一代接收方缩放机制。 使用 OID_GEN_RECEIVE_SCALE_PARAMETERS
RSSv2 本文中所述的第二代接收端缩放机制在 Windows 10 版本 1803 及更高版本中受支持。
缩放实体 本地 RSS 模式下的微型端口适配器本身,或 RSSv2 模式下的 VPort。
ITE 给定缩放实体的间接表项 (ITE)。 在 VMQ 模式下,每个 VPort 的 ITE 总数不能超过 NumberOfIndirectionTableEntriesPerNonDefaultPFVPort or NumberOfIndirectionTableEntriesForDefaultVPort;在本地 RSS 模式下,不能超过 128。 NumberOfIndirectionTableEntriesPerNonDefaultPFVPortNumberOfIndirectionTableEntriesForDefaultVPortNDIS_NIC_SWITCH_CAPABILITIES 结构的成员。
缩放模式 每个端口 vmswitch 策略,用于控制运行时如何处理 ITE。 这可能是静态的(由于负载更改而没有 ITE 移动)或动态(扩展和合并,具体取决于当前的流量负载)。
队列 一个基础硬件对象(队列),用于备份 ITE。 根据硬件和间接表的不同,配置队列可能支持多个 ITE。 队列总数(包括默认队列使用的队列)不能超过通常由管理员设置的预配置限制。
默认处理器 一种用于接收无法计算哈希的数据包的处理器。 每个 VPort 都有一个默认处理器。
主处理器 在创建 VPort 时,处理器被指定为 NDIS_NIC_SWITCH_VPORT_PARAMETERS 结构中的 ProcessorAffinity 成员。 可以在运行时更新此处理器,并指定 VMQ 流量的定向位置。
源 CPU ITE 当前映射的处理器。
目标 CPU 正在重新映射 ITE 的处理器(使用 RSSv2)。
行动者 CPU 要对其发出 RSSv2 请求的处理器。

在微型端口驱动程序中播发 RSSv2 功能

微型端口驱动程序通过在 NDIS_RECEIVE_SCALE_CAPABILITIES 结构的 CapabilitiesFlags 成员中设置 NDIS_RSS_CAPS_SUPPORTS_INDEPENDENT_ENTRY_MOVE 标志来宣传 RSSv2 支持。 要启用 RSSv2 的 CPU 负载均衡功能,就必须具备这一功能,同时还必须具备 NDIS_RECEIVE_FILTER_DYNAMIC_PROCESSOR_AFFINITY_CHANGE_SUPPORTED 标志,以启用 RSSv1 对非默认 VP 端口 (VMQ) 的动态均衡功能。

注意

上层协议假定默认 VPort 的主处理器可能会被移动,以用于 RSSv2 微型端口驱动程序。

如果微型端口适配器未播发 RSSv2 功能,即使请求这些 VPort 执行动态分布,所有已启用 VMQ 的 VPort 都保持静态分布模式。 RSSv1 OID 用于配置 RSS 参数(OID_GEN_RECEIVE_SCALE_PARAMETERS),适用于仍处于静态分布模式的 VPort。

微型端口驱动程序只需实现一个 RSS 控制机制 - RSSv1 或 RSSv2。 如果驱动程序宣布支持 RSSv2,则 NDIS 将根据需要将 RSSv1 OID 转换为 RSSv2 OID,以配置每个VPort的分配。 微型端口驱动程序必须支持这两个新的 OID,并修改 RSSv1 OID_GEN_RECEIVE_SCALE_PARAMETERS OID 的行为,如下所示:

处理 RSSv2 OID

OID_GEN_RECEIVE_SCALE_PARAMETERS 仅用于查询给定缩放实体的当前 RSS 参数。 在 RSSv1 中,此 OID 用于设置参数。 对于支持 RSSv2 的微型端口驱动程序,NDIS 会自动为驱动程序执行此角色转换,并发出以下两个 OID 来设置参数。

OID_GEN_RECEIVE_SCALE_PARAMETERS_V2 是一个常规 OID,其处理方法与 RSSv1 中处理 OID_GEN_RECEIVE_SCALE_PARAMETERS OID 的方法相同。 在 NDIS 6.80 之前,NDIS 轻型筛选器驱动程序(LWFs)无法看到此 OID。

OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES 是一个同步 OID,不能返回 NDIS_STATUS_PENDING。 此 OID 必须在发起该 OID 的处理器上下文中执行并完成。 与 OID_GEN_RECEIVE_SCALE_PARAMETERS_V2 一样,在 NDIS 6.80 之前的 NDIS LWF 中也看不到它。 NDIS 6.80 及更高版本中的 LWF 不允许延迟此 OID 或移动到其他处理器。 其有效负载包含一个简单的“移动 ITE”操作数组,每个操作都包含一条命令,用于将缩放实体的单个 ITE 移动到不同的目标 CPU。 数组的元素可以引用不同的缩放实体 (VPorts)。

每种 NDIS 驱动程序、微型端口、筛选器和协议都有支持同步 OID 请求接口的入口点:

NDIS 驱动程序类型 同步 OID 处理程序 用于发起同步 OID 的函数
微型端口 MiniportSynchronousOidRequest N/A
滤波器 NdisFSynchronousOidRequest
协议 N/A NdisSynchronousOidRequest

RSS 状态转换、ITE 更新和主/默认处理器

转向参数

在 RSSv2 中,不同的参数用于根据 RSS 状态(启用或禁用)将流量定向到正确的 CPU。 禁用 RSS 后,仅使用主处理器来定向流量。 启用 RSS 后,默认处理器和所有 ITE 都用于定向流量。 这些 转向参数 标记为“活动”或“非活动”,如下表所述:

转向参数 RSS 已禁用 已启用 RSS
主处理器 活动 无效
默认处理器 无效 活动
ITE[0..N] 无效 活动

当转向参数处于活动状态时,它会引导流量。 从 RSS 状态转换使参数 非活动的那一刻起,微型端口驱动程序必须跟踪参数的更改,直到反向转换再次激活它。 这意味着,当缩放实体禁用 RSS 时,微型端口驱动程序需要跟踪默认处理器和间接表项的所有更新。 启用 RSS 后,默认处理器和间接表的当前跟踪状态应生效。

例如,考虑软件 vRSS 已启用的情况。 在这种情况下,间接表已存在于上层协议中,并且由上层的软件分布代码主动使用。 如果在硬件 RSS 启用过程中,所有条目都开始指向主处理器,然后才向硬件发出并由硬件执行移动间接表条目更新,则主处理器可能会出现短时卡顿。 如果微型端口驱动程序跟踪了默认处理器和 ITE 信息,则可以将流量定向到上层已预期到的位置。

虽然微型端口驱动程序必须跟踪非活动转向参数的所有更新,但它们应推迟对这些参数的验证,直到 RSS 状态更改试图使这些参数活动时才进行验证。 例如,在禁用硬件 RSS 时进行软件传播时,上层协议可以使用任何处理器进行传播(包括适配器的 RSS 集外部)。 上层可确保在 RSS 状态转换时,所有 非活动 参数对新的 RSS 状态有效。 但是,微型端口驱动程序仍应验证参数,如果发现任何跟踪的 非活动 转向参数无效,则应终止 RSS 状态转换。

指导参数的初始状态和更新

下表描述了创建后缩放实体的初始状态(例如 VPort 创建后),以及如何更新参数:

参数 描述
主处理器
  • 使用 VPort 创建期间指定的 Affinity 处理器进行初始化。
  • 可使用设置了 NDIS_RSS_SET_INDIRECTION_ENTRY_FLAG_PRIMARY_PROCESSOR 标记的 OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES OID 进行更新。
  • 可以使用设置了 NDIS_NIC_SWITCH_VPORT_PARAMS_PROCESSOR_AFFINITY_CHANGED 标志的 OID_NIC_SWITCH_VPORT_PARAMETERS OID 来更新(这是现有 cmdlet 的兼容路径)。
  • 可使用带有 NDIS_NIC_SWITCH_VPORT_PARAMS_PROCESSOR_AFFINITY_CHANGED 标记的 OID_NIC_SWITCH_VPORT_PARAMETERS OID 来读取(这是现有 cmdlet 的兼容路径)。
  • 主处理器的初始化后移动不会影响默认处理器或间接表的内容。
默认处理器
  • 使用 VPort 创建期间指定的 Affinity 处理器进行初始化。
  • 可使用设置了 NDIS_RSS_SET_INDIRECTION_ENTRY_FLAG_DEFAULT_PROCESSOR 标记的 OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES OID 进行更新。
间接表

对 ITE 和主/默认处理器的更新(使用 OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES)是从相应条目当前指向的处理器调用的。 对于给定的 VPort,上层会确保在这些情况下不会发出用于移动 ITE 或设置主/默认处理器的 OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES:

  1. OID_GEN_RECEIVE_SCALE_PARAMETERS_V2 正在进行时。
  2. 启动 VPort 删除序列后。 例如,上层只有在移动 ITE 的最后一个 OID 完成后才会发出设置过滤器 OID。

RSS 禁用

在 RSS 禁用期间,上层协议可以选择将所有 ITE 指向主处理器,然后发出 OID 以禁用 RSS,或者选择将间接表保留 as-is 并禁用 RSS。 无论哪种情况,接收流量都应面向主处理器。

RSSv2 维护 RSSv1 的要求,该要求允许上层协议在不首先禁用 RSS 的情况下删除 VPort。 上层可以将 VPort 上的接收筛选器设置为零,从而确保没有接收流量流经 VPort,然后在不禁用 RSS 的情况下继续删除 VPort。 上层保证在删除 VPort 期间或之后不会发出 OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES。

在禁用 RSS 和删除 VPort 的过程中,微型端口驱动程序应处理因之前队列移动而可能存在的任何待处理内部操作。

RSSv2 不变量

上层协议确保在执行管理功能或进行 ITE 移动之前不会违反重要的不变量。 例如:

  1. 在减少队列数之前,上层可确保间接表引用的处理器数不会超过 VPort 的新队列数。
  2. 上层不应请求间接表更新,该更新违反了 VPort 当前配置的队列数。 微型端口驱动程序应强制实施此规则并返回一个失败状态。
  3. 在更改 VMMQ-RESTRICTED 适配器的间接表条目数之前,上层会确保间接表的内容归一化为 2 的幂。

OID_GEN_RECEIVE_SCALE_PARAMETERS_V2

OID_GEN_RSS_SET_INDIRECTION_TABLE_ENTRIES

NDIS 6.80 中的同步 OID 请求接口