合并 TCP/IP 段的规则
本部分定义规则,这些规则指定接收段合并 (支持 RSC) 的微型端口驱动程序必须合并给定 TCP 连接的段。 如果违反任何规则,则会生成异常,并且微型端口驱动程序必须中止段的合并。
微型端口驱动程序必须更新单个合并单元的 IP 和 TCP 标头 (SCU) 。 微型端口驱动程序必须通过 SCU 重新计算 TCP 和 IPv4 校验和,并链接 TCP 有效负载。
以下两个流程图中的第一个描述了合并段和更新 TCP 标头的规则。 此流程图是指用于区分有效重复 ACK 和窗口更新的机制。 第二个流程图描述了这些机制。
提供这些流程图作为了解 RSC 规则的参考。 只要保持正确性,硬件实现就可以优化流程图。
流程图中使用以下术语:
术语 | 说明 |
---|---|
Seg。SEQ | 传入段的序列号。 |
H.SEQ | 当前跟踪的 SCU 的序列号。 |
Seg。Ack | 传入段的确认编号。 |
H.ACK | 当前跟踪的 SCU 的确认编号。 |
Seg。WND | 由传入段播发的窗口。 |
H.WND | 当前跟踪的 SCU 播发的窗口。 |
Seg。莱恩 | 传入段的 TCP 有效负载长度。 |
H.LEN | 当前跟踪的 SCU 的 TCP 有效负载长度。 |
Seg。Nxt | SEG 的总和。SEQ 和 SEG。LEN. |
H.NXT | H.SEQ 和 H.LEN 的总和。 |
H.DupAckCount | 已合并到 SCU 中的重复 ACK 的数目。 此数字应该为 0。 |
Seg。Tsval | 当前接收的段中的 时间戳 值。 此值的格式在 RFC 1323 中定义。 |
H.Tsval | 当前跟踪的 SCU 中的 时间戳 值。 |
Seg。TSecr | 当前收到的段中的 时间戳回显回复 。 |
H.TSecr | 当前跟踪的 SCU 中的 时间戳回显回复 。 |
流程图显示微型端口驱动程序可能会将段与不同的 ACK 编号合并在一起。 但是,微型端口驱动程序必须遵守以下有关 ACK 编号的规则,如上面的第一个流程图所示:
执行序列号检查后,如果传入的纯 ACK 满足以下一个或两个条件,则可能会合并到当前跟踪的 SCU 中:
H.ACK == Seg。ACK。
正在跟踪的合并段中的重复 ACK 计数为零。 换句话说, H.DupAckCount == 0。
换句话说,任何不是重复 ACK 或窗口更新的纯 ACK 都会触发异常,并且不得合并。 所有此类纯 ACK 都必须指示为单个段。 此规则可确保 RSC 不会影响 Windows TCP 拥塞控制算法的行为或性能。
传入数据段 (SEG。ACK == H.ACK) 或传入的 ACK 支持 ACK (SEG。如果满足以下两个条件,则 ACK >H.ACK) 可能会合并到当前跟踪的 SCU 中:
- 段与序列空间中的 SCU 相邻。 换句话说, SEG。SEQ == H.NXT。
- 正在跟踪的合并段中的重复 ACK 计数为零。 换句话说, H.DupAckCount == 0。
有关重复 ACK 合并的其他说明
重复的 ACK 行为
微型端口驱动程序应处理等效于纯 ACK 的重复 ACK 段,而不是合并它。 在这种情况下,如果有任何) 指示,它必须完成当前 SCU (,并将重复的 ACK 段指示为单个段。 由于 Windows 客户端默认使用选择性确认 (SACK) ,因此重复的 ACK 段可能会生成异常。 有关 示例,请参阅接收段合并 示例。 如果指示具有 DupAckCount> 0 的段,NDIS 将在接口上禁用 RSC。
在跟踪包含数据段的 SCU 时处理重复的 ACK
使用 H.LEN> 0 (跟踪 SCU 时,即) 包含数据的合并段,如果接下来出现重复的 ACK,则应按如下所示完成跟踪 SCU:
应从重复的 ACK 开始跟踪新的 SCU。
新 SCU 的 DupAckCount 应设置为零。
如果收到其他重复 ACK,则 DupAckCount 应递增。
在这种情况下, DupAckCount 将比重复 ACK 数少 1。 主机堆栈将正确处理计数。
在跟踪由纯累积 ACK 组成的 SCU 时处理重复 ACK
跟踪由单个纯累积 ACK (规则(禁止合并多个纯 ACK) )组成的 SCU 时,如果接下来出现重复的 ACK,则跟踪 SCU 的 DupAckCount 应递增。 如果收到其他重复的 ACK,它也应该递增。 在这种情况下, DupAckCount 将等于合并的重复 ACK 数。
当 DPC 中收到的第一个段是重复的 ACK 时
在这种情况下,NIC 无法确定接收的段是否为重复的 ACK,因为它不保持任何状态。 因此,段应被视为纯 ACK,如下所示:
应从此段开始跟踪新的 SCU。
新 SCU 的 DupAckCount 应设置为零。
对于收到的每个附加重复 ACK, DupAckCount 应按 1 递增。
在这种情况下, DupAckCount 将等于 1 比重复 ACK 的实际数量少 1。 主机堆栈将正确处理计数。
重复的 ACK 豁免
微型端口驱动程序可以处理等效于纯 ACK 的重复 ACK 段,而不是合并它。 在这种情况下,如果有任何) 指示,它必须完成当前 SCU (,并将重复的 ACK 段指示为单个段。 由于 Windows 客户端默认使用 SACK,因此重复的 ACK 段可能会生成异常。 有关示例,请参阅 接收段合并的示例。 此豁免不适用于窗口更新段。
使用 Timestamp 选项合并段
TCP 时间戳选项是唯一可以合法合并的选项。 使用此选项合并段将保留为特定于实现的决策。 如果微型端口驱动程序将段与 timestamp 选项合并,则它必须遵循以下流程图中概述的规则:
注意
检查 SEG。TSval>= H.TSval 必须使用类似于用于 TCP 序列号的取模 232 算法执行。 请参阅 RFC 793 第 3.3 节。
指示合并段时,必须通过设置描述合并段的 NET_BUFFER_LIST 结构的 NetBufferListInfo 成员来指示以下带外信息:
合并的段数必须存储在 NetBufferListInfo[TcpRecvSegCoalesceInfo] 中。CoalescedSegCount 成员。 此数字仅表示已合并的数据段。 禁止纯 ACK 合并,窗口更新段不得计入此字段。
重复的 ACK 计数必须存储在 NetBufferListInfo[TcpRecvSegCoalesceInfo] 中。DupAckCount 成员。 上面的第一个流程图说明了如何计算此值。
合并具有 TCP 时间戳选项的段时,必须使用构成 SCU 的合并段序列中看到的最早和最新 TCP 时间戳值之间的绝对增量填充 NetBufferListInfo[RscTcpTimestampDelta]。 SCU 本身应包含合并段序列中看到的最新 TCP 时间戳值。
仅当 CoalescedSegCount 成员大于零时,才会解释 DupAckCount 和 RscTcpTimestampDelta 成员。 如果 CoalescedSegCount 为零,则段被视为非合并的非 RSC 段。
有关 NetBufferListInfo 成员的内容的信息,请参阅 NDIS_NET_BUFFER_LIST_INFO 和 NDIS_RSC_NBL_INFO。
对于所有合并段,PSH 位应为 ORed。 换句话说,如果在任何单个段中设置了 PSH 位,微型端口驱动程序应在 SCU 中设置 PSH 位。
完成 SCU 涉及:
重新计算 TCP,并重新计算 IPv4 校验和(如果适用)。
更新合并段的 IP 标头中所述的 IP 标头。
将 TCP 和 IP 标头中的 ECN 位和 ECN 字段设置为在各个段中设置的相同值。
处理 TCP/IP IPsec 段
网络卡可能会报告 RSC 和 IPsec 任务卸载功能。 (请参阅 确定网络适配器的 RSC 功能。) 但是,如果它支持 IPsec 任务卸载,则它不得尝试合并受 IPsec 保护的段。