This is an automated email from the ASF dual-hosted git repository. xiaoxiang pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 99bf7c3c5f657d991099646163d51d098ed1f5f2 Author: daichuan <[email protected]> AuthorDate: Sat Aug 30 01:18:20 2025 +0800 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 <[email protected]> --- Documentation/components/net/netdev.rst | 38 +++++++++ arch/Kconfig | 4 + include/nuttx/net/netdev.h | 143 +++++++++++++------------------- net/netdev/Kconfig | 3 +- net/netdev/netdev.h | 93 +++++++++++++++++++++ net/netdev/netdev_checksum.c | 35 ++++++++ net/tcp/tcp_send.c | 26 ------ net/udp/udp_send.c | 32 ++----- 8 files changed, 237 insertions(+), 137 deletions(-) diff --git a/Documentation/components/net/netdev.rst b/Documentation/components/net/netdev.rst index 1075ff9b30e..47aaaac50c2 100644 --- a/Documentation/components/net/netdev.rst +++ b/Documentation/components/net/netdev.rst @@ -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 diff --git a/arch/Kconfig b/arch/Kconfig index 7e3396308ad..17daa230344 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -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 diff --git a/include/nuttx/net/netdev.h b/include/nuttx/net/netdev.h index cfb9c84f901..34699a0c4e9 100644 --- a/include/nuttx/net/netdev.h +++ b/include/nuttx/net/netdev.h @@ -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 */ diff --git a/net/netdev/Kconfig b/net/netdev/Kconfig index 9e293e15747..2ef6287564c 100644 --- a/net/netdev/Kconfig +++ b/net/netdev/Kconfig @@ -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 diff --git a/net/netdev/netdev.h b/net/netdev/netdev.h index 5f50d6dad4c..b5c24b0e770 100644 --- a/net/netdev/netdev.h +++ b/net/netdev/netdev.h @@ -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 * diff --git a/net/netdev/netdev_checksum.c b/net/netdev/netdev_checksum.c index 24ad4ac9f8d..d2c2cac7fe3 100644 --- a/net/netdev/netdev_checksum.c +++ b/net/netdev/netdev_checksum.c @@ -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 */ diff --git a/net/tcp/tcp_send.c b/net/tcp/tcp_send.c index 574691e935e..1eae474bba4 100644 --- a/net/tcp/tcp_send.c +++ b/net/tcp/tcp_send.c @@ -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 */ diff --git a/net/udp/udp_send.c b/net/udp/udp_send.c index aaa1c5a09df..39bade48f0a 100644 --- a/net/udp/udp_send.c +++ b/net/udp/udp_send.c @@ -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 */
