数据包描述符和扩展

在 NetAdapterCx 中, 数据包描述符 是小型、紧凑、运行时可扩展的结构,用于描述网络数据包。 每个数据包都需要以下各项:

  • 一个核心描述符
  • 一个或多个片段描述符
  • 零个或多个数据包扩展

数据包 的核心描述符NET_PACKET 结构。 它仅包含适用于所有数据包的最基本元数据,例如给定数据包的帧布局和数据包的第一个片段描述符的索引。

每个数据包还必须具有一个或多个 片段描述符NET_FRAGMENT 结构,用于描述数据包数据所在的系统内存中的位置。

扩展 是可选的,用于保存特定于场景的功能的每个数据包或每个片段的元数据。 例如,数据包扩展可以保留校验和的卸载信息、大型发送卸载 (LSO) 和接收段合并 (RSC) ,或者可以保存特定于应用程序的详细信息。 片段扩展可以保存虚拟地址信息、逻辑 DMA 地址信息或片段的其他信息。

这些描述符和扩展共同保存有关网络数据包的所有元数据。 下面是它们如何描述数据包的两个示例。 第一个图显示了一个场景,即整个数据包存储在单个内存片段中,并且已打开校验和卸载。

显示具有 1 个片段和 1 个扩展的数据包布局的关系图。

第二个图显示了存储在两个内存片段中的数据包,同时启用了 RSC 和校验和卸载。

显示包含 2 个片段和 2 个扩展的数据包布局的关系图。

数据包描述符存储和访问

数据包描述符和片段描述符都存储在 NET_RING 结构中。 NIC 客户端驱动程序通过调用 Net Ring 迭代器接口来访问网络环并对其执行操作,这使驱动程序能够使用 NetAdapterCx 将网络数据发布到硬件,并将完成的数据排回 OS。

有关 net Ring 和 Net Ring 迭代器接口的详细信息,请参阅 net Ring 简介

数据包描述符扩展性

扩展性是 NetAdapterCx 数据包描述符的核心功能,为描述符的版本性和性能奠定了基础。 在运行时,操作系统会为连续块中的每个数据包队列分配所有数据包描述符,以及任何可应用的扩展。 每个扩展块紧跟在核心描述符后面,如下图所示:

此图显示了包含 3 个扩展块的 NetAdapterCx 数据包描述符布局。

不允许 NIC 客户端驱动程序将偏移量硬编码到任何扩展块。 相反,它们必须在运行时查询任何特定扩展的偏移量。 例如,驱动程序可能会查询到扩展 B 的偏移量并返回 70 个字节,如下图所示:

显示查询核心数据包描述符扩展的偏移量的示意图。

创建数据包队列及其描述符后,系统保证其所有扩展偏移量都是恒定的,因此驱动程序不必经常重新查询偏移量。 此外,由于所有扩展都是在数据包队列初始化时由系统在块中预先分配的,因此无需对块进行运行时分配、搜索列表以查找特定描述符或必须存储指向每个数据包扩展的指针。

数据包描述符可版本性

NetAdapterCx 的核心数据包描述符可以在将来的版本中通过向末尾添加新字段来轻松扩展,如下图所示:

显示 NetAdapterCx 核心数据包描述符版本控制的关系图。

了解 V2 字段的较新客户端驱动程序可以访问它们,而仅使用 V1 的较旧的驱动程序将使用扩展偏移跳过 V2 字段,以便可以访问他们确实理解的字段。 此外,每个扩展都可以采用相同的方式进行版本控制,如下图所示:

显示 NetAdapterCx 数据包扩展版本控制的关系图。

了解新扩展的客户端驱动程序可以使用它。 其他客户端驱动程序可以跳过新字段。 这允许单独对数据包描述符的不同部分进行版本控制。

数据包描述符和数据路径性能

前面概述的扩展性功能提供了一些好处,可帮助客户端驱动程序满足每秒数百千兆位的 NIC 的性能要求,其中包含数千个队列:

  1. 数据包描述符尽可能紧凑,以提高 CPU 缓存命中率,因为未使用的功能和扩展在描述符中占用 0 个字节的空间。
  2. 没有指针取消引用,只有偏移算术,因为扩展是内联的,这不仅节省空间,而且有助于 CPU 缓存命中。
  3. 扩展是在队列创建时分配的,因此驱动程序不必在活动数据路径中分配和解除分配内存,也不必处理上下文块的旁观列表。

使用数据包扩展

重要

目前,客户端驱动程序仅限于 操作系统定义的预先存在的数据包扩展

注册数据包扩展

在 NIC 客户端驱动程序中使用数据包扩展的第一步是声明受支持的硬件卸载。 当你播发对卸载(如校验和和 LSO)的支持时,NetAdapterCx 会自动代表你注册关联的数据包扩展。

有关播发硬件卸载的代码示例,请参阅 硬件卸载简介

查询数据路径队列的数据包扩展偏移量

通过声明硬件卸载支持来注册数据包扩展后,需要扩展偏移量才能在处理数据包时访问每个扩展。 若要减少对驱动程序的调用并提高性能,可以在 EvtNetAdapterCreateTx (Rx) Queue 回调函数期间查询扩展的偏移量,并将偏移信息存储在队列上下文中。

有关查询扩展偏移量并将其存储在队列上下文中的示例,请参阅 传输和接收队列

在运行时获取数据包扩展

在队列上下文中存储扩展偏移后,可以随时在扩展中需要信息时使用它们。 例如,可以在将描述符编程为传输队列的硬件时调用 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 虚拟地址片段扩展的名称和版本。