在 NetAdapterCx 中, 数据包描述符 是描述网络数据包的小型、紧凑、运行时可扩展的结构。 每个数据包都需要以下各项:
- 一个核心描述符
- 一个或多个片段描述符
- 零个或多个数据包扩展
数据包 的核心描述符 是 NET_PACKET 结构。 它仅包含适用于所有数据包的最基本元数据,例如给定数据包的框架布局以及数据包的第一个片段描述符的索引。
每个数据包还必须具有一个或多个 片段描述符或 NET_FRAGMENT 结构,用于描述数据包数据所在的系统内存中的位置。
扩展 是可选的,用于每个数据包或每个片段的特定场景功能的元数据。 例如,数据包扩展可以保留校验和卸载信息、大型发送卸载(LSO)、接收段合并(RSC)的卸载信息,也可以保留特定于应用程序的详细信息。 片段扩展可以保存虚拟地址信息、逻辑 DMA 地址信息或片段的其他信息。
这些描述符和扩展一起保存有关网络数据包的所有元数据。 下面是描述数据包的方式的两个示例。 第一个图显示了一个场景,其中整个数据包被存储在单个内存片中,并且校验和卸载功能已启用。
第二个图显示了一个数据包存储在两个内存片段中,启用 RSC 和校验和卸载功能。
数据包描述符存储和访问
数据包描述符和片段描述符都存储在 NET_RING 结构中。 NIC 客户端驱动程序通过调用 Net Ring 迭代器接口访问网络通道并对其进行操作,该接口使驱动程序能够与 NetAdapterCx 协作,将网络数据发布到硬件,并将已完成的数据返回到操作系统。
有关 net ring 和 Net Ring 迭代器接口的详细信息,请参阅 net ring 简介。
数据包描述符扩展性
扩展性是 NetAdapterCx 数据包描述符的核心功能,构成了描述符的可版本性和性能的基础。 在运行时,操作系统会将每个数据包队列的所有数据包描述符及任何可用扩展一起,分配在一个连续块中。 每个扩展块紧跟在核心描述符后面,如下图所示:
不允许 NIC 客户端驱动程序对任何扩展块的偏移量进行硬编码。 相反,它们必须在运行时查询任何特定扩展的偏移量。 例如,驱动程序可能会查询扩展 B 的偏移量,并返回 70 个字节,如下图所示:
创建数据包队列及其描述符后,系统保证其所有扩展偏移量都是恒定的,因此驱动程序不必经常重新查询偏移量。 此外,由于所有扩展都是在初始化数据包队列时由系统在块中预先分配的,因此无需对块进行运行时分配、搜索特定描述符的列表,或者必须存储指向每个数据包扩展的指针。
数据包描述符的可版本性
在未来版本中,通过将新字段添加到末尾,可以轻松扩展 NetAdapterCx 的核心数据包描述符,如下图所示:
了解 V2 字段的较新的客户端驱动程序可以访问它们,而较旧的仅限 V1 的驱动程序将使用扩展偏移来跳过 V2 字段,以便可以访问他们理解的字段。 此外,可以采用相同的方式对每个扩展进行版本控制,如下图所示:
了解新扩展的客户端驱动程序可以使用它。 其他客户端驱动程序可以跳过新字段。 这允许单独对数据包描述符的不同部分进行版本控制。
数据包描述符和数据路径性能
前面提到的扩展性功能提供了一些优势,帮助客户端驱动程序满足支持每秒数百千兆位速度和数千个队列的网络接口卡的性能需求。
- 数据包描述符尽可能紧凑,以提高 CPU 缓存命中率,因为未使用的功能和扩展占用描述符中的 0 字节空间。
- 没有指针解引用,只有偏移运算,因为扩展是内联的,这不仅节省空间,而且有助于提高 CPU 缓存命中率。
- 扩展是在队列创建时分配的,因此驱动程序不必在活动数据路径中分配和解除分配内存,也不必处理上下文块的旁观列表。
使用数据包扩展
重要
目前,客户端驱动程序仅限于 操作系统定义的预定义的数据包扩展。
注册数据包扩展
在 NIC 客户端驱动程序中使用数据包扩展的第一步是声明受支持的硬件卸载功能。 你宣传对校验和和 LSO 等卸载的支持时,NetAdapterCx 会自动为您注册关联的数据包扩展。
有关宣传硬件卸载的代码示例,请参阅 硬件卸载简介。
查询数据路径队列中数据包扩展的偏移量
通过声明硬件卸载支持来注册数据包扩展后,在处理数据包时,需要使用扩展偏移量来访问每个扩展。 若要减少对驱动程序的调用并提高性能,可以在 EvtNetAdapterCreateTx(Rx)队列 回调函数期间查询扩展的偏移量,并将偏移信息存储在队列上下文中。
有关查询扩展偏移并将其存储在队列上下文中的示例,请参阅 传输和接收队列。
在运行时获取包扩展
在队列上下文中存储扩展偏移量后,可以随时在扩展中需要信息时使用它们。 例如,在为传输队列的硬件编程描述符时,可以调用 NetExtensionGetPacketChecksum 方法:
// Get the extension offset from the device context
PMY_TX_QUEUE_CONTEXT queueContext = GetMyTxQueueContext(txQueue);
NET_EXTENSION checksumExtension = queueContext->ChecksumExtension;
// Get the checksum info for this packet
NET_PACKET_CHECKSUM* checksumInfo = NetExtensionGetPacketChecksum(checksumExtension, packetIndex);
// Do work with the checksum info
if (packet->Layout.Layer3Type == NET_PACKET_LAYER3_TYPE_IPV4_NO_OPTIONS ||
packet->Layout.Layer3Type == NET_PACKET_LAYER3_TYPE_IPV4_WITH_OPTIONS ||
packet->Layout.Layer3Type == NET_PACKET_LAYER3_TYPE_IPV4_UNSPECIFIED_OPTIONS)
{
if(checksumInfo->Layer4 == NET_PACKET_TX_CHECKSUM_REQUIRED)
{
...
}
}
...
预定义的数据包扩展常量和帮助程序方法
NetAdapterCx 提供已知数据包扩展常量的定义。
| 恒定 | 定义 |
|---|---|
| NET_PACKET_EXTENSION_INVALID_OFFSET | 防范无效的偏移大小。 |
| NET_PACKET_EXTENSION_CHECKSUM_NAME NET_PACKET_EXTENSION_CHECKSUM_VERSION_1 | 校验和数据包扩展的名称和版本。 |
| NET_PACKET_EXTENSION_LSO_NAME NET_PACKET_EXTENSION_LSO_VERSION_1 | 大型发送卸载(LSO)数据包扩展的名称和版本。 |
| NET_PACKET_EXTENSION_RSC_NAME NET_PACKET_EXTENSION_RSC_VERSION_1 | 接收段合并(RSC)数据包扩展的名称和版本。 |
此外,NetAdapterCx 还提供帮助程序方法,这些方法充当 NetExtensionGetData 方法周围的包装器。 其中每个方法都返回指向相应结构类型的指针。
| 方法 | 结构 |
|---|---|
| NetExtensionGetPacketChecksum | NET_PACKET_CHECKSUM |
| NetExtensionGetGso | NET_PACKET_GSO |
| NetExtensionGetPacketRsc | NET_PACKET_RSC |
使用片段扩展
重要
目前,客户端驱动程序仅限于操作系统定义的预先存在的碎片扩展。
注册片段扩展
NetAdapterCx 通过解释驱动程序的表示功能自动注册大多数片段扩展。 例如,如果驱动程序表示它支持 DMA,框架将自动添加 DMA 编程所需的NET_FRAGMENT_LOGICAL_ADDRESS扩展。
查询数据路径队列的片段扩展偏移量
若要访问片段扩展,可以遵循相同的过程来访问 查询数据路径队列的数据包扩展偏移量中概述的数据包扩展。
预定义的片段扩展常量
NetAdapterCx 为已知的片段扩展常量提供定义。
| 恒定 | 定义 |
|---|---|
| NET_FRAGMENT_EXTENSION_DATA_BUFFER_NAME NET_FRAGMENT_EXTENSION_DATA_BUFFER_VERSION_1 | 数据缓冲区片段扩展的名称和版本。 |
| NET_FRAGMENT_EXTENSION_LOGICAL_ADDRESS_NAME NET_FRAGMENT_EXTENSION_LOGICAL_ADDRESS_VERSION_1 | 逻辑地址片段扩展的名称和版本。 |
| NET_FRAGMENT_EXTENSION_MDL_NAME NET_FRAGMENT_EXTENSION_MDL_VERSION_1 | MDL 片段扩展的名称和版本。 |
| NET_FRAGMENT_EXTENSION_RETURN_CONTEXT_NAME NET_FRAGMENT_EXTENSION_RETURN_CONTEXT_VERSION_1 | 返回上下文片段扩展的名称和版本。 |
| NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_NAME NET_FRAGMENT_EXTENSION_VIRTUAL_ADDRESS_VERSION_1 | 虚拟地址片段扩展的名称和版本。 |