校验和卸载

NetAdapterCx 支持在运行时卸载 TCP/IP 校验和任务。

在 TCP/IP 传输将 NET_PACKET 结构传递给客户端驱动程序之前,它会指定与 NET_PACKET_CHECKSUM 数据包扩展中的NET_PACKET关联的校验和信息。

如卸载校验和任务中所述,TCP/IP 传输在卸载 TCP/UDP 数据包的校验和计算之前,计算 TCP/UDP 伪头程序的补 码总和

启用 通用分段卸载 (GSO) 时关闭校验和卸载不会阻止客户端驱动程序计算校验和并在 GSO 功能生成的数据包中插入校验和。 若要完全禁用校验和卸载,还必须禁用 GSO。

用于控制校验和卸载的 INF 关键字

NetAdapterCx 检查注册表关键字,并在启用主动卸载功能时遵循它们。 驱动程序不需要执行任何进一步的操作。

使用注册表值启用和禁用任务卸载中指定的校验和关键字可用于通过注册表项设置启用/禁用校验和卸载。 不支持分组关键字。

关键字 (keyword) 值的类型必须为 REG_SZ

配置校验和卸载

客户端驱动程序首先在网络适配器初始化期间播发其硬件的校验和卸载功能。 在启动网络适配器之前,这可能在其 EvtDevicePrepareHardware 回调中发生。

若要配置传输 (Tx) 校验和卸载,客户端驱动程序:

  1. 分配 NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES 结构。

  2. 调用 NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES_INIT 初始化 结构。

  3. 调用 NetAdapterOffloadSetTxChecksumCapabilities 将结构注册到 NetAdapterCx。

在调用 NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES_INIT 客户端驱动程序会提供指向 EVT_NET_ADAPTER_OFFLOAD_SET_TX_CHECKSUM回调的 指针。 如果活动卸载功能发生更改,系统稍后会调用此回调。

若要配置接收 (Rx) 校验和卸载,客户端驱动程序:

  1. 分配 NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES 结构。

  2. 调用 NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES_INIT 来初始化 结构。

  3. 调用 NetAdapterOffloadSetRxChecksumCapabilities 将结构注册到 NetAdapterCx。

在调用 NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES_INIT 客户端驱动程序提供指向 EVT_NET_ADAPTER_OFFLOAD_SET_RX_CHECKSUM 回调的指针。 如果活动卸载功能发生更改,系统稍后会调用此回调。

用于指示硬件传输校验和功能的规则

  1. 必须设置 NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES 结构中的 Layer3Flags。 设置 Layer4Flags 是可选的。 设置 Layer3Flags 和 Layer4Flags 指示 NIC 能够执行校验和卸载的数据包。

  2. NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES中的 Layer3HeaderOffsetLimit 和 Layer4HeaderOffsetLimit 是可选的。 如果 OS 发送标头偏移量大于指定限制的数据包,则不会请求 NIC 计算该层的校验和。

  3. 如果支持选项/扩展,则必须支持不带选项/扩展的 IP/TCP 数据包。

用于指示硬件接收校验和功能的规则

NetAdapterCx 不需要驱动程序来播发硬件接收校验和功能。 如果启用了校验和卸载,NIC 应对其可以处理的所有数据包执行校验和卸载。 如果 NIC 无法对数据包执行校验和卸载,NetAdapterCx 将在软件中卸载它。

此示例演示客户端驱动程序如何设置其硬件校验和卸载功能:

VOID
MyAdapterSetOffloadCapabilities(
    NETADAPTER NetAdapter
)
{
    // Configure the hardware's Tx checksum offload capabilities
    NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES txChecksumOffloadCapabilities;

    auto const layer3Flags = NetAdapterOffloadLayer3FlagIPv4NoOptions |
        NetAdapterOffloadLayer3FlagIPv4WithOptions |
        NetAdapterOffloadLayer3FlagIPv6NoExtensions |
        NetAdapterOffloadLayer3FlagIPv6WithExtensions;

    auto const layer4Flags = NetAdapterOffloadLayer4FlagTcpNoOptions |
        NetAdapterOffloadLayer4FlagTcpWithOptions |
        NetAdapterOffloadLayer4FlagUdp;

    NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES_INIT(
        &txChecksumOffloadCapabilities,
        layer3Flags,
        EvtAdapterOffloadSetTxChecksum);

    txChecksumOffloadCapabilities.Layer4Flags = layer4Flags;

    txChecksumOffloadCapabilities.Layer4HeaderOffsetLimit = 127;

    // Set the current Tx checksum offload capabilities and register the callback for future changes in active capabilities
    NetAdapterOffloadSetTxChecksumCapabilities(NetAdapter,
        &txChecksumOffloadCapabilities);

    // Configure the hardware's Rx checksum offload capabilities
    NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES rxChecksumOffloadCapabilities;

    NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES_INIT(
        &rxChecksumOffloadCapabilities,
        EvtAdapterOffloadSetRxChecksum);

    // Set the current Rx checksum offload capabilities and register the callback for future changes in active capabilities
    NetAdapterOffloadSetRxChecksumCapabilities(NetAdapter,
        &rxChecksumOffloadCapabilities);
}

更新硬件卸载

如果 TCP/IP 堆栈或上层协议驱动程序请求更改网络适配器的活动功能,NetAdapterCx 会调用客户端驱动程序的 EVT_NET_ADAPTER_OFFLOAD_SET_TX_CHECKSUMEVT_NET_ADAPTER_OFFLOAD_SET_RX_CHECKSUM 适配器初始化期间注册的回调。 在这些函数中,系统在 NETOFFLOAD 对象中提供更新的功能,客户端驱动程序查询该对象以更新其卸载功能。

客户端驱动程序可以调用以下函数来确定启用了哪些校验和卸载:

以下示例演示客户端驱动程序如何更新其 Tx/Rx 校验和卸载功能:

VOID
MyEvtAdapterOffloadSetTxChecksum(
    NETADAPTER  NetAdapter,
    NETOFFLOAD  Offload
)
{
    PMY_NET_ADAPTER_CONTEXT adapterContext = MyGetNetAdapterContext(NetAdapter);

    // Store the updated information in the context
    adapterContext->TxHardwareIpChecksum = NetOffloadIsTxChecksumIPv4Enabled(Offload);
    adapterContext->TxHardwareTcpChecksum = NetOffloadIsTxChecksumTcpEnabled(Offload);
    adapterContext->TxHardwareUdpChecksum = NetOffloadIsTxChecksumUdpEnabled(Offload);

    // Update the new hardware Tx checksum offload capabilities
    MyUpdateHardwareChecksum(adapterContext);
}

VOID
MyEvtAdapterOffloadSetRxChecksum(
    NETADAPTER  NetAdapter,
    NETOFFLOAD  Offload
)
{
    PMY_NET_ADAPTER_CONTEXT adapterContext = MyGetNetAdapterContext(NetAdapter);

    // Store the updated information in the context
    adapterContext->RxHardwareIpChecksum = NetOffloadIsRxChecksumIPv4Enabled(Offload);
    adapterContext->RxHardwareTcpChecksum = NetOffloadIsRxChecksumTcpEnabled(Offload);
    adapterContext->RxHardwareUdpChecksum = NetOffloadIsRxChecksumUdpEnabled(Offload);

    // Update the new hardware Rx checksum offload capabilities
    MyUpdateHardwareChecksum(adapterContext);
}

传输校验和处理

客户端驱动程序通常在传输路径上执行以下校验和处理:

  1. 客户端驱动程序使用数据包索引调用 NetExtensionGetPacketChecksum 函数以获取 NET_PACKET_CHECKSUM 结构。

  2. 客户端驱动程序测试NET_PACKET_CHECKSUM结构中特定于层的标志。

    • 如果该标志为 NetPacketTxChecksumActionPassthrough,则 NIC 不应在该层中执行校验和操作。

    • 如果标志为 NetPacketTxChecksumActionRequired,则客户端驱动程序应使用 NET_PACKET_LAYOUT 结构确定该特定数据包中该层使用的协议,并指示应为数据包计算哪个校验和。

  3. 客户端驱动程序将数据包传递给 NIC,后者计算数据包的相应校验和。

接收校验和处理

在指示执行校验和任务的接收数据包的 NET_PACKET 结构之前,客户端驱动程序会验证校验和并在 NET_PACKET_CHECKSUM 结构中设置适当的标志。

标志可以是下列标志之一:

标志 描述
NetPacketRxChecksumEvaluationNotChecked NIC 无法验证数据包的校验和
NetPacketRxChecksumEvaluationValid 数据包的校验和有效
NetPacketRxChecksumEvaluationInvalid 数据包的校验和无效