网环元素管理
按照本主题中的指南在网络数据传输期间管理NET_RING结构及其元素。本主题中的规则描述了在不同的数据路径方案下,客户端驱动程序可以修改哪些 net ring 元素的成员以及何时可以修改,并提供了客户端驱动程序在使用这些结构时应牢记的一般信息。
重要
客户端驱动程序应在开发的所有阶段遵循这些方向。如果在使用驱动程序验证程序进行测试时客户端驱动程序不遵循这些指示,驱动程序验证程序会报告冲突,并在测试的设备上触发 bug 检查。
NET_RING
启动NET_RING的父数据包队列时,环中的所有索引将初始化为 0。
下表描述了客户端驱动程序可以修改的 net ring 成员:
| 字段 | 允许修改客户端驱动程序 |
|---|---|
OSReserved1 | 否 |
ElementStride | 否 |
NumberOfElements | 否 |
ElementIndexMask | 否 |
EndIndex | 否 |
OSReserved0 | 否 |
OSReserved2 | 否 |
BeginIndex | 是(必需) |
NextIndex | 是(可选)> 注意:框架永远不会读取NextIndex。 |
Scratch | 是(可选)> 注意:框架永远不会读取Scratch。 |
Buffer | 否 |
客户端驱动程序不得修改此结构中的任何只读成员,在调用EvtPacketQueueAdvance时,也绝不应将BeginIndex增加到超过EndIndex。
有关 net 环中的索引所有权的详细信息,请参阅net 环简介。
NET_PACKET
NET_PACKET中的字段对数据路径运行的不同上下文敏感。是否设置数据包的Ignore字段以及驱动程序是在接收(Rx)还是传输(Tx)数据包,会影响应用于该数据包的规则集。
下表为每种场景中的驱动程序提供指引:
| Rx 或 Tx | Ignore字段被设置由… | 注释 |
|---|---|---|
| Rx | 客户端驱动程序 | 在 Rx 期间,客户端驱动程序会根据需要设置Ignore,框架会读取它。客户端驱动程序无需在 Rx 期间随时读取Ignore。如果客户端驱动程序在 Rx 期间设置 Ignore字段,则:• 取消未成功编程到硬件的任何数据包的 Rx 操作时,客户端驱动程序必须写入 Ignore字段。有关更多信息,请参阅使用网环取消网络数据。• 客户端驱动程序不得将资源与数据包相关联,因为它们不会被释放。 如果客户端驱动程序在 Rx 期间未设置 Ignore字段,则:• 客户端驱动程序必须填充 FragmentIndex、FragmentCount和Layout中的所有字段。• FragmentIndex必须介于片段环中的BeginIndex(包含)和EndIndex(不包含)之间。• FragmentCount不能超过片段环中BeginIndex(包含)和EndIndex(不包含)之间的片段数量。如果客户端驱动程序移动相应的片段环 BeginIndex:• 客户端驱动程序必须移动数据包环 BeginIndex。• 调用 EvtPacketQueueAdvance后,如果客户端驱动程序递增数据包环BeginIndex,则驱动程序还必须将片段环BeginIndex递增,以越过该数据包的片段。换句话说,片段环BeginIndex应移动到上一数据包片段的EndIndex。 |
| Tx | NetAdapterCx | 在 Tx 期间: • 客户端驱动程序不得修改除 Scratch以外的任何数据包中的任何字段。• 客户端驱动程序可以读取 Ignore的值,但绝不能写入它。• 如果忽略 Tx 数据包,驱动程序不得读取任何字段,除非有必要读取 Scratch。 |
关于Ignore字段的简要回顾
在 NetAdapterCx 数据路径中,Ignore字段用于标记应被跳过的数据包:
Tx(传输)场景:
Ignore由 NetAdapterCx 框架设置,用于指示驱动程序应跳过该数据包的传输(例如,数据包已被上层取消)。驱动程序仅可读取此字段。Rx(接收)场景:
Ignore由客户端驱动程序在取消操作期间设置,用于指示框架应忽略该数据包(例如,该数据包从未真正被硬件填充)。驱动程序负责写入此字段,框架负责读取并执行相应操作。
NET_PACKET 布局(Layout)字段
在 Rx 操作期间,NET_PACKET的Layout字段受以下规则的约束:
| 规则编号 | 约束条件 |
|---|---|
| 1 | 除Reserved0之外的所有字段都必须由客户端驱动程序初始化。 |
| 2 | 如果Layer2Type设置为NetPacketLayer2TypeEthernet,则Layer2HeaderLength必须为14 或更高。 |
| 3 | 如果Layer2Type设置为NetPacketLayer2TypeNull,则必须将Layer2HeaderLength设置为0。 |
| 4 | 如果Layer3Type是 IPv4 类型,则Layer3HeaderLength必须为20 或更高。 |
| 5 | 如果Layer3Type是 IPv6 类型,则Layer3HeaderLength必须为40 或更高。 |
| 6 | 如果Layer4Type设置为Tcp,则Layer4HeaderLength必须为40 或更高。 |
| 7 | 如果Layer4Type设置为Udp,则Layer4HeaderLength必须为8 或更高。 |
| 8 | 层类型字段必须位于适当的枚举范围内。 |
注意:Tx 期间不使用
Layout字段。
NET_FRAGMENT
NET_FRAGMENT字段规则取决于驱动程序是接收还是传输,以及片段缓冲区是由驱动程序还是框架附加到数据包:
| Rx 或 Tx | 注释 |
|---|---|
| Rx | • 客户端驱动程序无法写入OsReserved_Bounced字段。•如果驱动程序未附加缓冲区: Capacity不得修改,而ValidLength和Offset必须修改。•如果驱动程序正在附加缓冲区: Capacity、ValidLength和Offset都必须修改。• Offset + ValidLength必须小于Capacity。 |
| Tx | • 客户端驱动程序不能修改除Scratch以外的任何字段。 |
关键规则速查表
| 操作场景 | BeginIndex | NextIndex | Scratch | Ignore(读) | Ignore(写) | Layout 字段 | 片段字段 |
|---|---|---|---|---|---|---|---|
| Tx - 正常 | 只读 | 可写 | 可写 | 可读 | ❌ 禁止 | 不使用 | 只读(除 Scratch) |
| Tx - 取消 | 可写 | 可写 | 可写 | 可读 | ❌ 禁止 | 不使用 | 只读(除 Scratch) |
| Rx - 正常 | 可写 | 只读 | 可写 | 不读取 | 不写入 | 必须初始化 | 可写(见上表) |
| Rx - 取消 | 可写 | 只读 | 可写 | 不读取 | 必须写入 | 无需初始化 | 可写 |