Checksum and TCP Segmentation Offloading
Contents
General Description
Some devices support a combination of receive checksum offload, send checksum offload, and/or TCP segmentation offload for different type of packets. The stack can be configured on a per interface basis to take advantage of the offload hardware capabilities.
Compile-time Configuration
First, some macros need to be defined to enable all of the offload capabilities in the stack as shown below.
Run-time Configuration
When one or both of these macros are enabled, at run time, when an interface is opened, the stack will query the corresponding driver (calling the driver IOCTL with TM_DEV_IOCTL_OFFLOAD_GET) for its offload capabilities, and then will let the driver know of the driver's offload capabilities (with the driver IOCTL TM_DEV_IOCTL_OFFLOAD_SET). Offloading should only be performed by the driver according to the driver's offload capabilities as set in the driver IOCTL call with TM_DEV_IOCTL_OFFLOAD_SET.
Recv Checksum Offload
When the recv offload macro is enabled, the driver recv functions take an extra parameter that should be ignored by drivers that do not support offload, and that should be filled in by the drivers that do support offload as explained below.
Send Checksum Offload/TCP Segmentation Offload
When the send offload macro is enabled, for drivers that support send and/or TCP segmentation offload, then the driver should supply a scattered send single call for the driver send routine as explained in Chapter 4: Integrating Turbo Treck Real-Time Protocols Into Your Environment.
Related Macros
Reception: Checksum Offload
To enable the recv checksum offload add the following macro definition to <trsystem.h>:
#define TM_DEV_RECV_OFFLOAD
In that case all driver recv functions take an extra parameter. If the driver does not support offloading, then it ignores the extra parameter.
Transmission: Checksum and TCP Segmentation Offload
To enable the send checksum and TCP segmentation offload add the following macro definition to <trsystem.h>:
#define TM_DEV_SEND_OFFLOAD
Transmission: TM_USE_DRV_ONE_SCAT_SEND Macro
Note that when TM_DEF_SEND_OFFLOAD is defined, then the macro TM_USE_DRV_ONE_SCAT_SEND is automatically defined, because to be able to use send checksum offload/TCP segmentation offload on a device, the driver needs to supply the single send call per frame function as explained in Adding a Device Driver.
Run-time Configuration
Device Driver IOCTL Function
Driver IOCTL with TM_DEV_IOCTL_OFFLOAD_GET Flag
When the user opens the interface, and if one of the 2 offload macros has been defined, then the stack will call the driver IOCTL function with the TM_DEV_IOCTL_OFFLOAD_GET flag to get the offload capabilities of the device driver. A pointer to an offload structure is passed as 3rd parameter. The offload structure is initialized by the driver.
Upon return, the device driver will set one or more of the below flags in the offloadFlags field of the ttDevIoctlOffloadStruct structure to indicate what the device supports.
Driver IOCTL with TM_DEV_IOCTL_OFFLOAD_SET Flag
After having called the device driver IOCTL with the TM_DEV_IOCTL_OFFLOAD_GET flag, and if that function returns TM_ENOERROR, then the stack will immediately call the device driver IOCTL function with the TM_DEV_IOCTL_OFFLOAD_SET flag passing the pointer to the offload structure with its fields as set by the device driver. When this function is called, the driver and the stack have both agreed on what offload capabilities they both support.
The stack will let the driver know which of the above flags returned by TM_DEV_IOCTL_OFFLOAD_GET it will support in the offloadFlags field of the ttDevIoctlOffloadStruct structure to indicate what the device should support.
Driver IOCTL Offload Structure
A pointer to the following structure is passed as 3rd parameter of the device driver IOCTL:
typedef struct tsDevIoctlOffloadStruct { ttUser16Bit offloadFlags; ttUser16Bit offloadMaxSize; } ttDevIoctlOffloadStruct; typedef ttDevIoctlOffloadStruct TM_FAR * ttDevIoctlOffloadPtr;
Members
- (ttUser16Bit) offloadFlags
- One or more bits set to indicate the offload capabilities of the driver as described below.
- (ttUser16Bit) offloadMaxSize
- Maximum size of a TCP packet (including IP header and Ethernet header) that the driver can segment.
Flags
- TM_DEVO_PACKET_RECV_CHKSUM_COMPUTE
- Legacy: Device calculates recv checksum on the entire packet (hardware will append the recv checksum on the entire packet (minus the MAC layer) at the end of the data in network byte order. Note that some drivers append the checksum in little endian order; in this case the recv checksum should be flipped by the driver.
- TM_DEVO_IP_RECV_CHKSUM_VALIDATE
- Hardware validates the recv IPv4 header checksum
- TM_DEVO_TCP_RECV_CHKSUM_VALIDATE
- Hardware validates the recv TCP header checksum
- TM_DEVO_UDP_RECV_CHKSUM_VALIDATE
- Hardware validates the recv UDP header checksum
- TM_DEVO_ICMP6_RECV_CHKSUM_VALIDATE
- Hardware validates the ICMPv6 header checksum
- TM_DEVO_DITCH_BAD_CHECKSUM_PACKETS
- Device driver will not pass up the stack packets that have bad checksums.
- TM_DEVO_TCP_CHKSUM_OFFLOAD
- Device supports TCP checksum offload only (no segmentation offload)
- TM_DEVO_UDP_CHKSUM_OFFLOAD
- Device supports UDP checksum offload
- TM_DEVO_ICMP6_CHKSUM_OFFLOAD
- Device supports ICMPV6 checksum offload
- TM_DEVO_IP_CHKSUM_OFFLOAD
- Device supports IPv4 checksum offload
- TM_DEVO_TCP_SEGMENT_OFFLOAD_V4
- Device supports TCP Segmentation offload for IPv4 packets, note that, whenever TCP segment is enabled, TM_DEVO_IP_CHKSUM_OFFLOAD is enabled automatically.
- TM_DEVO_TCP_SEGMENT_OFFLOAD_V6
- Device supports TCP Segmentation offload for IPv6 packets
Recv Checksum Offload
The stack will support different degrees of device checksum capabilities. Some devices are only capable of computing a checksum on the entire packet (legacy). Others are able to completely validate the IPv4 header checksum, TCP header checksum, etc. To get that information from the driver, the driver recv function has been modified to take an extra parameter.
Modified Driver Recv Function
When TM_DEV_RECV_OFFLOAD is enabled, then the driver recv function takes an extra parameter, a pointer to a recv offload structure:
| int devRecv | ( |
| ttUserInterface interfaceHandle, | |
| char ** dataPtr, | |
| int * dataLength, | |
| ttUserBufferPtr userBufferHandlePtr, | |
| ttDevRecvOffloadPtr devRecvOffloadPtr | |
| ); |
Modified Driver Scattered Recv Function
When TM_DEV_RECV_OFFLOAD is enabled, then the driver scattered recv function takes an extra parameter, a pointer to a recv offload structure:
| int devRecv | ( |
| ttUserInterface interfaceHandle, | |
| ttDruBlockPtrPtr uDevBlockPtrPtr, | |
| int * uDevBlockCountPtr, | |
| int * flagPtr, | |
| ttDevRecvOffloadPtr devRecvOffloadPtr | |
| ); |
Recv Offload Structure
typedef struct tsDevRecvOffloadStruct { /* * One of more of the TM_DEVOR_XXX flags as defined below. */ ttUser16Bit devoRFlags; /* Recv checksum as computed by the board */ ttUser16Bit devoRecvXsum; /* Offset to start of checksum computation */ ttUser16Bit devoRecvXsumOffset; /* Checksum done on this amount of data */ ttUser16Bit devoRecvXsumLength; } ttDevRecvOffloadStruct; typedef ttDevRecvOffloadStruct TM_FAR * ttDevRecvOffloadPtr;
Members
- (ttUser16Bit) devoRFlags
- One of more of the TM_DEVOR_XXX flags as defined below.
- (ttUser16Bit) devoRecvXsum
- Recv checksum as computed by the hardware in network byte order (legacy).
- (ttUser16Bit) devoRecvXsumOffset
- Offset to start of checksum computation (legacy).
- (ttUser16Bit) devoRecvXsumLength
- Checksum done on this amount of data (legacy).
Flags
- TM_DEVOR_PACKET_RECV_CHKSUM_COMPUTED
- recv checksum has been computed (legacy)
- TM_DEVOR_IP_RECV_CHKSUM_VALIDATED
- recv IP header checksum has been validated
- TM_DEVOR_TCP_RECV_CHKSUM_VALIDATED
- recv TCP header checksum has been validated
- TM_DEVOR_UDP_RECV_CHKSUM_VALIDATED
- recv TCP header checksum has been validated
- TM_DEVOR_ICMP6_RECV_CHKSUM_VALIDATED
- recv TCP header checksum has been validated
- TM_DEVOR_IP_RECV_CHKSUM_FAILED
- recv IPv4 header checksum failed
- TM_DEVOR_TCP_RECV_CHKSUM_FAILED
- recv TCP header checksum failed
- TM_DEVOR_UDP_RECV_CHKSUM_FAILED
- recv UDP header checksum failed
- TM_DEVOR_ICMP6_RECV_CHKSUM_FAILED
- recv ICMPv6 header checksum failed
Transmission
When data is sent to the device driver, the stack needs to indicate to the device driver what checksum computations have been made, and information about TCP segmentation offload. That information is conveyed in a ttDevSendOffloadStruct structure as shown below.
The stack will pre-compute the pseudo header checksum for TCP, UDP, and ICMPv6 packets in the checksum field. It will indicate to the board the offset to that field in the packet, offset to first byte of data, and last byte of data to be checksum'ed. Note that if the board supports TCP segmentation, and TCP is sending a segment bigger than the MSS, then the stack will indicate to the board that TCP segmentation needs to be performed. In that case the pseudo-header checksum does not include the length. Also in that case, three additional fields are filled in by the stack as shown below.
If the board supports IP header checksum, the stack will not compute the IP header checksum, and will indicate to the board the offset to the IP header checksum, to the first byte of the IP header, and last byte of the IP header.
Single Send Call Driver Function
The driver needs to support the single send call driver function.
Modified ttUserPacket Structure
The single send call driver function takes a ttUserPacketPtr parameter. The ttUserPacket structure takes an additional field used to convey the offload performed on the packet. It is a pointer to a ttDevSendOffloadStruct.
#define trsocket.h /* * Data type used for the linked list of packets passed to the device * driver single call scattered send function prototype. */ typedef struct tsUserPacket { /* Next tsUserPacket for scattered data */ /* struct tsUserPacket TM_FAR *pktuLinkNextPtr; */ void TM_FAR *pktuLinkNextPtr; /* Pointer to data */ ttUser8BitPtr pktuLinkDataPtr; #ifdef TM_DSP /* byte offset of start of data, in word pointed to by pktuLinkDataPtr */ int pktuLinkDataByteOffset; #endif /* TM_DSP */ #if defined(TM_DEV_SEND_OFFLOAD) || defined(TM_DEV_RECV_OFFLOAD) ttUserVoidPtr pktuDevOffloadPtr; #endif /* TM_DEV_SEND_OFFLOAD || TM_DEV_RECV_OFFLOAD */ /* Size of data pointed by pktuLinkDataPtr */ ttPktLen pktuLinkDataLength; /* * Total packet length (of chained scattered data). Valid in first link * only */ ttPktLen pktuChainDataLength; /* * Number of links linked to this one (not including this one). * Valid in first link only. */ int pktuLinkExtraCount; #ifdef TM_USE_USER_PARAM /* User-defined data */ ttUserGenericUnion pktuUserParam; #endif /* TM_USE_USER_PARAM */ } ttUserPacket; typedef ttUserPacket TM_FAR * ttUserPacketPtr;
Device Send Offload Structure
In ttUserPacket, the pktuDevOffloadPtr points to the following structure:
typedef struct tsDevSendOffloadStruct { /* * One of more of the device offload flags as defined in the * TM_DEV_IOCTL_OFFLOAD_SET tfIoctlInterface(). * Note that a TM_DEVO_TCP_SEGMENT_OFFLOAD_V4 flag, indicates an IPv4 protocol * and a TM_DEVO_TCP_SEGMENT_OFFLOAD_V6 indicates an IPv6 protocol (needed for * segmentation) */ ttUser16Bit devoFlags; /* TCP/IP or UDP/IP header length to be used in each frame */ ttUser16Bit devoFrameHdrLen; /* Total TCP payload (used in segmentation) not including header */ ttUser32Bit devoPayload; /* Maximum TCP or UDP payload segment per frame not including header */ ttUser16Bit devoFramePayload; /* UDP/TCP header checksum */ ttUser16Bit devoTucss; /* offset to first byte to be included in Xsum */ ttUser16Bit devoTucso; /* Offset to Xsum field */ ttUser16Bit devoTucse; /* Offset to last byte to be in included in Xsum */ #ifdef TM_USE_IPV4 /* IP header checksum */ ttUser16Bit devoIpcss; /* offset to first byte to be included in Xsum */ ttUser16Bit devoIpcso; /* Offset to Xsum field */ ttUser16Bit devoIpcse; /* Offset to last byte to be in included in Xsum */ #endif /* TM_USE_IPV4 */ } ttDevSendOffloadStruct; typedef ttDevSendOffloadStruct TM_FAR * ttDevSendOffloadPtr;
Members
- (ttUser16Bit) devoFlags
- One of more of the device offload flags as shown below.
- (ttUser16Bit) devoFrameHdrLen
- TCP/IP header length to be used in each frame (segmentation).
- (ttUser32Bit) devoPayload
- Total TCP payload not including header (segmentation).
- (ttUser16Bit) devoFramePayload
- Maximum TCP payload segment per frame not including header (segmentation).
- (ttUser16Bit) devoTucss
- UDP/TCP/ICMPV6 header checksum: offset to first byte to be included in Xsum.
- (ttUser16Bit) devoTucso
- UDP/TCP/ICMPV6 header checksum: Offset to Xsum field.
- (ttUser16Bit) devoTucse
- UDP/TCP/ICMPV6 header checksum: Offset to last byte to be in included in Xsum. Note that 0 means offset to last byte of the entire packet.
- (ttUser16Bit) devoIpcss
- IPv4 header checksum: offset to first byte to be included in Xsum.
- (ttUser16Bit) devoIpcso
- IPv4 header checksum: Offset to Xsum field.
- (ttUser16Bit) devoIpcse
- IPv4 header checksum: Offset to last byte to be in included in Xsum.
Flags
- TM_DEVO_TCP_CHKSUM_OFFLOAD
- TCP checksum is to be offloaded (no segmentation offload)
- TM_DEVO_UDP_CHKSUM_OFFLOAD
- UDP checksum is to be offloaded
- TM_DEVO_ICMP6_CHKSUM_OFFLOAD
- ICMPV6 checksum is to be offloaded
- TM_DEVO_IP_CHKSUM_OFFLOAD
- IPv4 checksum is to be offloaded
- TM_DEVO_TCP_SEGMENT_OFFLOAD_V4
- TCP Segmentation offload for IPv4 packets. Note that whenever TCP segment is enabled, TM_DEVO_IP_CHKSUM_OFFLOAD is enabled automatically.
- TM_DEVO_TCP_SEGMENT_OFFLOAD_V6
- TCP Segmentation offload for IPv6 packet
Examples
The source code contains one driver that support different degrees of offloading capabilities:
| Board | Type of Offload Supported | Location |
|---|---|---|
| Intel Xscale 80321 | Recv checksum validation | source/drivers/8254x/tr8254x.c |
| Recv checksum computation if TM_DEVO_PACKET_RECV_CHKSUM_COMPUTE is set in the offloadFlags field of the ttDevIoctlOffloadStruct structure when the stack calls the driver IOCTL with the TM_DEV_IOCTL_OFFLOAD_SET flag parameter. Note that the stack will set the flags retrieved from the driver IOCTL function call with TM_DEV_IOCTL_OFFLOAD_GET. So this happens if TM_DEVO_PACKET_RECV_CHKSUM_COMPUTE is set in the offladFlags field of the ttDevIoctlOffloadStruct structure in the driver IOCTL function. | ||
| TCP segmentation if the macro TM_LEGACY_OFFLOAD is not defined in that driver. | ||
| TCP/UDP/ICMPv6 checksum offload. | ||
| IP header checksum offload if the macro TM_LEGACY_OFFLOAD is not defined in that driver. |