net: skip TCP/UDP pseudo-header checksum with hardware offload

When supporting hardware checksum offloading, the network protocol stack
does not perform TCP/UDP pseudo-header checksum calculation.

Skip TCP/UDP pseudo header checksum calculation in network protocol stack

Signed-off-by: daichuan <daichuan@xiaomi.com>
This commit is contained in:
daichuan
2025-08-30 01:18:20 +08:00
committed by Xiang Xiao
parent 42da4e322a
commit 99bf7c3c5f
8 changed files with 237 additions and 137 deletions
+38
View File
@@ -173,6 +173,44 @@ Ioctls for IP Addresses
to manage IPv6 addresses, by which you don't need to care about the
slot it stored.
Hardware Checksum Offload
=========================
The structure :c:struct:`net_driver_s` includes fields to support hardware
checksum offloading. This feature allows the network stack to delegate
checksum calculation to the network device hardware, improving performance.
Checksum Configuration Options
------------------------------
* :c:macro:`CONFIG_NETDEV_CHECKSUM`: Enable support for hardware checksum
offloading in the network stack. This option requires the architecture
to support it (:c:macro:`ARCH_HAVE_NETDEV_CHECKSUM_HW`).
Implementation Details
----------------------
When :c:macro:`CONFIG_NETDEV_CHECKSUM` is enabled, the driver should use the
following helper functions to retrieve checksum offload information:
* :c:func:`netdev_checksum_start`: Get the offset from the beginning of the
packet to the start of the L4 header (checksum calculation start).
* :c:func:`netdev_checksum_offset`: Get the offset from the start of the L4
header to the checksum field.
* :c:func:`netdev_upperlayer_header_checksum`: Calculate the pseudo-header
checksum.
.. code-block:: c
#ifdef CONFIG_NETDEV_CHECKSUM
int netdev_checksum_start(FAR struct net_driver_s *dev);
int netdev_checksum_offset(FAR struct net_driver_s *dev);
uint16_t netdev_upperlayer_header_checksum(FAR struct net_driver_s *dev);
#endif
Drivers that support hardware checksum offloading should use these functions
to configure the hardware accordingly before transmitting the packet.
[1]: https://man7.org/linux/man-pages/man7/netdevice.7.html
[2]: e.g. 'eth0:0' stands for the secondary address on eth0
+4
View File
@@ -575,6 +575,10 @@ config ARCH_HAVE_FETCHADD
bool
default n
config ARCH_HAVE_NETDEV_CHECKSUM_HW
bool
default n
config ARCH_HAVE_RTC_SUBSECONDS
bool
default n
+57 -86
View File
@@ -920,46 +920,6 @@ uint16_t net_chksum_iob(uint16_t sum, FAR struct iob_s *iob,
#ifdef CONFIG_NET_IPv4
/****************************************************************************
* Name: ipv4_upperlayer_header_chksum
*
* Description:
* Perform the checksum calculation over the IPv4, protocol headers,
* IP source and destination addresses
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
*
* Returned Value:
* The calculated checksum with pseudo-header and IP source and
* destination addresses
*
****************************************************************************/
uint16_t ipv4_upperlayer_header_chksum(FAR struct net_driver_s *dev,
uint8_t proto);
/****************************************************************************
* Name: ipv4_upperlayer_payload_chksum
*
* Description:
* Perform the checksum calculation over the iob data payload
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* sum - The default checksum
*
* Returned Value:
* The calculated checksum with iob data payload and default checksum
*
****************************************************************************/
uint16_t ipv4_upperlayer_payload_chksum(FAR struct net_driver_s *dev,
uint16_t sum);
/****************************************************************************
* Name: ipv4_upperlayer_chksum
*
@@ -982,52 +942,6 @@ uint16_t ipv4_upperlayer_chksum(FAR struct net_driver_s *dev, uint8_t proto);
#ifdef CONFIG_NET_IPv6
/****************************************************************************
* Name: ipv6_upperlayer_header_chksum
*
* Description:
* Perform the checksum calculation over the IPv6, protocol headers,
* IP source and destination addresses.
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* The calculated checksum
*
****************************************************************************/
uint16_t ipv6_upperlayer_header_chksum(FAR struct net_driver_s *dev,
uint8_t proto, unsigned int iplen);
/****************************************************************************
* Name: ipv6_upperlayer_payload_chksum
*
* Description:
* Perform the checksum calculation over the iob data payload and
* default checksum.
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* The calculated checksum
*
****************************************************************************/
uint16_t ipv6_upperlayer_payload_chksum(FAR struct net_driver_s *dev,
unsigned int iplen, uint16_t sum);
/****************************************************************************
* Name: ipv6_upperlayer_chksum
*
@@ -1380,4 +1294,61 @@ int netdev_ipv6_foreach(FAR struct net_driver_s *dev,
void netdev_statistics_log(FAR void *arg);
#endif
/****************************************************************************
* Name: netdev_checksum_start
*
* Description:
* Get checksum start offset position with iob, then hardware can
* use to calculate the package payload checksum value.
*
* Input Parameters:
* dev - The driver structure
*
* Returned Value:
* The checksum start offset position, -EINVAL is mean not need calculate
* with hardware
*
****************************************************************************/
#ifdef CONFIG_NETDEV_CHECKSUM
int netdev_checksum_start(FAR struct net_driver_s *dev);
#endif
/****************************************************************************
* Name: netdev_checksum_offset
*
* Description:
* Get checksum field offset with tcp/udp header.
*
* Input Parameters:
* dev - The driver structure
*
* Returned Value:
* The checksum field offset with L4, -EINVAL is mean not need calculate
* with hardware
*
****************************************************************************/
#ifdef CONFIG_NETDEV_CHECKSUM
int netdev_checksum_offset(FAR struct net_driver_s *dev);
#endif
/****************************************************************************
* Name: netdev_upperlayer_header_checksum
*
* Description:
* get upperlayer header checksum with tcp/udp header.
*
* Input Parameters:
* dev - The driver structure
*
* Returned Value:
* The upperlayer header checksum
*
****************************************************************************/
#ifdef CONFIG_NETDEV_CHECKSUM
uint16_t netdev_upperlayer_header_checksum(FAR struct net_driver_s *dev);
#endif
#endif /* __INCLUDE_NUTTX_NET_NETDEV_H */
+2 -1
View File
@@ -100,8 +100,9 @@ config NETDOWN_NOTIFIER
logic.
config NETDEV_CHECKSUM
bool "netdev hardware checksum"
bool "Enable support to netdev checksum in Hardware"
default n
depends on ARCH_HAVE_NETDEV_CHECKSUM_HW
---help---
To support hardware checksum calculation for network cards, we
need to know the starting position of the L4 layer header in
+93
View File
@@ -503,6 +503,99 @@ void netdev_notify_recvcpu(FAR struct net_driver_s *dev,
FAR const void *dst_addr, uint16_t dst_port);
#endif
#ifdef CONFIG_NET_IPv4
/****************************************************************************
* Name: ipv4_upperlayer_header_chksum
*
* Description:
* Perform the checksum calculation over the IPv4, protocol headers,
* IP source and destination addresses
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
*
* Returned Value:
* The calculated checksum with pseudo-header and IP source and
* destination addresses
*
****************************************************************************/
uint16_t ipv4_upperlayer_header_chksum(FAR struct net_driver_s *dev,
uint8_t proto);
/****************************************************************************
* Name: ipv4_upperlayer_payload_chksum
*
* Description:
* Perform the checksum calculation over the iob data payload
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* sum - The default checksum
*
* Returned Value:
* The calculated checksum with iob data payload and default checksum
*
****************************************************************************/
uint16_t ipv4_upperlayer_payload_chksum(FAR struct net_driver_s *dev,
uint16_t sum);
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
/****************************************************************************
* Name: ipv6_upperlayer_header_chksum
*
* Description:
* Perform the checksum calculation over the IPv6, protocol headers,
* IP source and destination addresses.
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* The calculated checksum
*
****************************************************************************/
uint16_t ipv6_upperlayer_header_chksum(FAR struct net_driver_s *dev,
uint8_t proto, unsigned int iplen);
/****************************************************************************
* Name: ipv6_upperlayer_payload_chksum
*
* Description:
* Perform the checksum calculation over the iob data payload and
* default checksum.
*
* Input Parameters:
* dev - The network driver instance. The packet data is in the d_buf
* of the device.
* proto - The protocol being supported
* iplen - The size of the IPv6 header. This may be larger than
* IPv6_HDRLEN the IPv6 header if IPv6 extension headers are
* present.
*
* Returned Value:
* The calculated checksum
*
****************************************************************************/
uint16_t ipv6_upperlayer_payload_chksum(FAR struct net_driver_s *dev,
unsigned int iplen, uint16_t sum);
#endif /* CONFIG_NET_IPv6 */
/****************************************************************************
* Name: netdev_list_lock
*
+35
View File
@@ -194,4 +194,39 @@ int netdev_checksum_offset(FAR struct net_driver_s *dev)
return offset;
}
/****************************************************************************
* Name: netdev_upperlayer_header_checksum
*
* Description:
* get upperlayer header checksum with tcp/udp header.
*
* Input Parameters:
* dev - The driver structure
*
* Returned Value:
* The upperlayer header checksum
*
****************************************************************************/
uint16_t netdev_upperlayer_header_checksum(FAR struct net_driver_s *dev)
{
if (IFF_IS_IPv6(dev->d_flags))
{
FAR struct ipv6_hdr_s *ipv6 = IPv6BUF;
return HTONS(ipv6_upperlayer_header_chksum(dev,
ipv6->proto,
IPv6_HDRLEN));
}
else
{
FAR struct ipv4_hdr_s *ipv4 = IPv4BUF;
return HTONS(ipv4_upperlayer_header_chksum(dev,
ipv4->proto));
}
return 0;
}
#endif /* CONFIG_NETDEV_CHECKSUM */
-26
View File
@@ -204,13 +204,6 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
{
tcp->tcpchksum = ~tcp_ipv6_chksum(dev);
}
else
{
uint16_t chksum = ipv6_upperlayer_header_chksum(dev,
IP_PROTO_TCP,
IPv6_HDRLEN);
tcp->tcpchksum = HTONS(chksum);
}
#endif
#ifdef CONFIG_NET_STATISTICS
@@ -238,12 +231,6 @@ static void tcp_sendcommon(FAR struct net_driver_s *dev,
{
tcp->tcpchksum = ~tcp_ipv4_chksum(dev);
}
else
{
uint16_t chksum = ipv4_upperlayer_header_chksum(dev,
IP_PROTO_TCP);
tcp->tcpchksum = HTONS(chksum);
}
#endif
#ifdef CONFIG_NET_STATISTICS
@@ -530,13 +517,6 @@ void tcp_reset(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
{
tcp->tcpchksum = ~tcp_ipv6_chksum(dev);
}
else
{
uint16_t chksum = ipv6_upperlayer_header_chksum(dev,
IP_PROTO_TCP,
IPv6_HDRLEN);
tcp->tcpchksum = HTONS(chksum);
}
#endif
}
#endif /* CONFIG_NET_IPv6 */
@@ -560,12 +540,6 @@ void tcp_reset(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn)
{
tcp->tcpchksum = ~tcp_ipv4_chksum(dev);
}
else
{
uint16_t chksum = ipv4_upperlayer_header_chksum(dev,
IP_PROTO_TCP);
tcp->tcpchksum = HTONS(chksum);
}
#endif
}
#endif /* CONFIG_NET_IPv4 */
+8 -24
View File
@@ -250,46 +250,30 @@ void udp_send(FAR struct net_driver_s *dev, FAR struct udp_conn_s *conn)
#ifdef CONFIG_NET_UDP_CHECKSUMS
/* Calculate UDP checksum. */
if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
if (IFF_IS_IPv4(dev->d_flags))
if (IFF_IS_IPv4(dev->d_flags))
#endif
{
if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
udp->udpchksum = ~udp_ipv4_chksum(dev);
}
else
{
uint16_t chksum = ipv4_upperlayer_header_chksum(dev,
IP_PROTO_UDP);
udp->udpchksum = HTONS(chksum);
}
}
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
#ifdef CONFIG_NET_IPv4
else
else
#endif
{
if ((dev->d_features & NETDEV_TX_CSUM) == 0)
{
udp->udpchksum = ~udp_ipv6_chksum(dev);
}
else
{
uint16_t chksum = ipv6_upperlayer_header_chksum(dev,
IP_PROTO_UDP,
IPv6_HDRLEN);
udp->udpchksum = HTONS(chksum);
}
}
#endif /* CONFIG_NET_IPv6 */
if (udp->udpchksum == 0)
{
udp->udpchksum = 0xffff;
if (udp->udpchksum == 0)
{
udp->udpchksum = 0xffff;
}
}
#endif /* CONFIG_NET_UDP_CHECKSUMS */