Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 26 Apr 2026 07:45:07 +0000
From:      Michael Tuexen <tuexen@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Cc:        Timo =?utf-8?Q?V=C3=B6lker?= <timo.voelker@fh-muenster.de>
Subject:   git: bba71b3f7c15 - stable/15 - ip: improve deferred computation of checksums
Message-ID:  <69edc283.253d2.757126ff@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch stable/15 has been updated by tuexen:

URL: https://cgit.FreeBSD.org/src/commit/?id=bba71b3f7c1561fd40d279001536540f43c707c4

commit bba71b3f7c1561fd40d279001536540f43c707c4
Author:     Timo Völker <timo.voelker@fh-muenster.de>
AuthorDate: 2026-01-20 10:30:19 +0000
Commit:     Michael Tuexen <tuexen@FreeBSD.org>
CommitDate: 2026-04-26 07:42:55 +0000

    ip: improve deferred computation of checksums
    
    This patch adds the same functionality for the IPv4 header checksum
    as was done erlier for the SCTP/TCP/UDP transport checksum.
    When the IP implementation sends a packet, it does not compute the
    corresponding checksum but defers that. It will determine whether the
    network interface selected for the packet has the requested capability
    and computes the checksum in software, if the selected network
    interface does not have the requested capability.
    Do this not only for packets being sent by the local IP stack, but
    also when forwarding packets. Furthermore, when such packets are
    delivered to a local IP stack, do not compute or validate the checksum,
    since such packets have never been on the wire. This allows to support
    checksum offloading also in the case of local virtual machines or
    jails. Support for epair interfaces will be added in a separate commit.
    
    Reviewed by:            pouria, tuexen
    Differential Revision:  https://reviews.freebsd.org/D54455
    Event:                  Wiesbaden Hackathon 2026
    
    (cherry picked from commit 6f15ba8004c3fdc2fb12f0cd6618d1b3a40aab7d)
---
 share/man/man9/mbuf.9    |  5 +++--
 sys/netinet/ip_fastfwd.c | 32 +++++++++++++++++++++++---------
 sys/netinet/ip_input.c   |  6 ++++++
 3 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/share/man/man9/mbuf.9 b/share/man/man9/mbuf.9
index e4f30962ccab..265a6dddda98 100644
--- a/share/man/man9/mbuf.9
+++ b/share/man/man9/mbuf.9
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd August 1, 2025
+.Dd January 20, 2026
 .Dt MBUF 9
 .Os
 .\"
@@ -1216,13 +1216,14 @@ in
 is not set, since SCTP does not use a pseudo header checksum.
 .Pp
 If IP delivers a packet with the flags
+.Dv CSUM_IP ,
 .Dv CSUM_SCTP ,
 .Dv CSUM_TCP ,
 or
 .Dv CSUM_UDP
 set in
 .Va csum_flags
-to a local SCTP, TCP, or UDP stack, the packet will be processed without
+to a local IP, SCTP, TCP, or UDP stack, the packet will be processed without
 computing or validating the checksum, since the packet has not been on the
 wire.
 This can happen if the packet was handled by a virtual interface such as
diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c
index c567d28f24f0..ecba083dbb77 100644
--- a/sys/netinet/ip_fastfwd.c
+++ b/sys/netinet/ip_fastfwd.c
@@ -360,15 +360,20 @@ passin:
 	}
 
 	/*
-	 * Decrement the TTL and incrementally change the IP header checksum.
-	 * Don't bother doing this with hw checksum offloading, it's faster
-	 * doing it right here.
+	 * Decrement the TTL.
+	 * If the IP header checksum field contains a valid value, incrementally
+	 * change this value. Don't use hw checksum offloading, which would
+	 * recompute the checksum. It's faster to just change it here
+	 * according to the decremented TTL.
+	 * If the checksum still needs to be computed, don't touch it.
 	 */
 	ip->ip_ttl -= IPTTLDEC;
-	if (ip->ip_sum >= (u_int16_t) ~htons(IPTTLDEC << 8))
-		ip->ip_sum -= ~htons(IPTTLDEC << 8);
-	else
-		ip->ip_sum += htons(IPTTLDEC << 8);
+	if (__predict_true((m->m_pkthdr.csum_flags & CSUM_IP) == 0)) {
+		if (ip->ip_sum >= (u_int16_t) ~htons(IPTTLDEC << 8))
+			ip->ip_sum -= ~htons(IPTTLDEC << 8);
+		else
+			ip->ip_sum += htons(IPTTLDEC << 8);
+	}
 #ifdef IPSTEALTH
 	}
 #endif
@@ -466,9 +471,18 @@ passout:
 		gw = (const struct sockaddr *)dst;
 
 	/*
-	 * If TCP/UDP header still needs a valid checksum and interface will not
-	 * calculate it for us, do it here.
+	 * If the IP/SCTP/TCP/UDP header still needs a valid checksum and the
+	 * interface will not calculate it for us, do it here.
+	 * Note that if we defer checksum calculation, we might send an ICMP
+	 * message later that reflects this packet, which still has an
+	 * invalid checksum.
 	 */
+	if (__predict_false(m->m_pkthdr.csum_flags & CSUM_IP &
+	    ~nh->nh_ifp->if_hwassist)) {
+		ip->ip_sum = 0;
+		ip->ip_sum = in_cksum(m, (ip->ip_hl << 2));
+		m->m_pkthdr.csum_flags &= ~CSUM_IP;
+	}
 	if (__predict_false(m->m_pkthdr.csum_flags & CSUM_DELAY_DATA &
 	    ~nh->nh_ifp->if_hwassist)) {
 		in_delayed_cksum(m);
diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c
index 652aa4a99e79..cc7b35f5d168 100644
--- a/sys/netinet/ip_input.c
+++ b/sys/netinet/ip_input.c
@@ -525,6 +525,12 @@ ip_input(struct mbuf *m)
 
 	if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) {
 		sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID);
+	} else if (m->m_pkthdr.csum_flags & CSUM_IP) {
+		/*
+		 * Packet from local host that offloaded checksum computation.
+		 * Checksum not required since the packet wasn't on the wire.
+		 */
+		sum = 0;
 	} else {
 		if (hlen == sizeof(struct ip)) {
 			sum = in_cksum_hdr(ip);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?69edc283.253d2.757126ff>