Checksum offload

NetAdapterCx supports offloading TCP/IP checksum tasks at run time.

Before the TCP/IP transport passes a NET_PACKET structure to the client driver, it specifies the checksum information associated with the NET_PACKET in a NET_PACKET_CHECKSUM packet extension.

The TCP/IP transport calculates the one's complement sum for the TCP/UDP pseudoheader before offloading the checksum calculation for a TCP/UDP packet, as described in Offloading Checksum Tasks.

Turning off checksum offloads when Generic Segmentation Offload (GSO) is enabled doesn't prevent the client driver from computing and inserting checksums in packets generated by the GSO feature. To completely disable checksum offloads you must also disable GSO.

INF keywords for controlling checksum offload

NetAdapterCx checks the registry keywords and honors them when enabling the active offload capabilities. The driver doesn't need to take any further action.

The checksum keywords specified in Using Registry Values to Enable and Disable Task Offloading can be used to enable/disable the checksum offload with a registry key setting. Grouped keywords are not supported.

The keyword values must be of type REG_SZ.

Configuring checksum offload

Client drivers first advertise their hardware's checksum offload capabilities during net adapter initialization. This might occur within their EvtDevicePrepareHardware callback before starting a net adapter.

To configure transmit (Tx) checksum offload, the client driver:

  1. Allocates a NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES structure.

  2. Calls NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES_INIT to initialize the structure.

  3. Calls NetAdapterOffloadSetTxChecksumCapabilities to register the structure with NetAdapterCx.

During the call to NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES_INIT the client driver provides a pointer to the EVT_NET_ADAPTER_OFFLOAD_SET_TX_CHECKSUM callback. The system invokes this callback later if active offload capabilities change.

To configure receive (Rx) checksum offload, the client driver:

  1. Allocates a NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES structure.

  2. Calls NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES_INIT to initialize the structure.

  3. Calls NetAdapterOffloadSetRxChecksumCapabilities to register the structure with NetAdapterCx.

During the call to NET_ADAPTER_OFFLOAD_RX_CHECKSUM_CAPABILITIES_INIT the client driver provides a pointer to the EVT_NET_ADAPTER_OFFLOAD_SET_RX_CHECKSUM callback. The system invokes this callback later if active offload capabilities change.

Rules for indicating hardware transmit checksum capabilities

  1. The Layer3Flags in the NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES structure must be set. Setting the Layer4Flags is optional. Setting the Layer3Flags and Layer4Flags indicates the packets on which the NIC is capable of performing checksum offload.

  2. The Layer3HeaderOffsetLimit and Layer4HeaderOffsetLimit in NET_ADAPTER_OFFLOAD_TX_CHECKSUM_CAPABILITIES are optional. If the OS sends a packet with a header offset greater than the limit specified, it won't request the NIC to calculate the checksum for that layer.

  3. IP/TCP packets without options/extensions must be supported if options/extensions are supported.

Rules for indicating hardware receive checksum capabilities

NetAdapterCx doesn't require the driver to advertise the hardware receive checksum capabilities. If checksum offload is enabled, the NIC should perform checksum offload on all the packets it can handle. If the NIC can't perform checksum offload on a packet, NetAdapterCx will offload it in software.

This example shows how a client driver might set up its hardware checksum offload capabilities:

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);
}

Updating hardware offloads

If the TCP/IP stack or an overlying protocol driver requests a change to the net adapter's active capabilities, NetAdapterCx invokes the client driver's EVT_NET_ADAPTER_OFFLOAD_SET_TX_CHECKSUM or EVT_NET_ADAPTER_OFFLOAD_SET_RX_CHECKSUM callback that was registered during adapter initialization. In these functions, the system supplies updated capabilities in the NETOFFLOAD object which the client driver queries to update its offload capabilities.

Client drivers can call the following functions to determine which checksum offloads are enabled:

The following example shows how a client driver might update its Tx/Rx checksum offload capabilities:

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);
}

Transmit checksum processing

A client driver typically does the following checksum processing on the transmit path:

  1. The client driver calls the NetExtensionGetPacketChecksum function with the packet index to obtain a NET_PACKET_CHECKSUM structure.

  2. The client driver tests the layer-specific flags in the NET_PACKET_CHECKSUM structure.

    • If the flag is NetPacketTxChecksumActionPassthrough, the NIC shouldn't perform checksum operations in that layer.

    • If the flag is NetPacketTxChecksumActionRequired, the client driver should determine the protocol being used at that layer in that specific packet using the NET_PACKET_LAYOUT structure and indicate to the NIC which checksum it should calculate for the packet.

  3. The client driver passes the packet to the NIC, which calculates the appropriate checksums for the packet.

Receive checksum processing

Before indicating a NET_PACKET structure for a receive packet on which it performs checksum tasks, the client driver validates the checksums and sets the appropriate flags in the NET_PACKET_CHECKSUM structure.

The flags can be one of the following:

Flag Description
NetPacketRxChecksumEvaluationNotChecked The NIC could not validate the checksum of the packet
NetPacketRxChecksumEvaluationValid The checksum of the packet is valid
NetPacketRxChecksumEvaluationInvalid The checksum of the packet is invalid