mirror of
https://github.com/apache/nuttx.git
synced 2026-05-25 09:45:55 +08:00
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:
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
|
||||
*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
|
||||
Reference in New Issue
Block a user