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 */
 

Reply via email to