git: 0a12444b2989 - main - pkt-gen: fix UDP checksum when IPv6 address ranges are used

From: Vincenzo Maffione <vmaffione_at_FreeBSD.org>
Date: Sun, 01 Nov 2026 18:10:05 UTC
The branch main has been updated by vmaffione:

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

commit 0a12444b2989c38a5d2e358e0f9ef01c665cc268
Author:     Vincenzo Maffione <vmaffione@FreeBSD.org>
AuthorDate: 2026-11-01 18:06:13 +0000
Commit:     Vincenzo Maffione <vmaffione@FreeBSD.org>
CommitDate: 2026-11-01 18:06:13 +0000

    pkt-gen: fix UDP checksum when IPv6 address ranges are used
    
    update_ip6() left the UDP checksum stale for most packets. Unlike
    update_ip(), it computed the incremental checksum delta only after the
    source-address wrap, so every earlier "break" (port increment, address
    increment, and both random paths) returned with udp_sum still 0 and no
    correction applied. The trailing delta block also re-read oaddr/naddr
    after they had been reassigned, so the source and destination deltas
    could not both be accounted for.
    
    Fold each delta in with new_udp_sum() before the corresponding break,
    mirroring the structure update_ip() already uses, and drop the stale
    trailing block. IPv4 was not affected.
    
    Verified by driving update_addresses() directly and recomputing every
    checksum from scratch over the real pseudo-header: 128 packets across
    six range configurations, 12 mismatches before, 0 after. IPv4 passes
    both before and after.
    
    Submitted by:   Olivier Cochard-Labbé <olivier@cochard.me>
---
 tools/tools/netmap/pkt-gen.c | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/tools/tools/netmap/pkt-gen.c b/tools/tools/netmap/pkt-gen.c
index c17579a142b9..510f6a3db462 100644
--- a/tools/tools/netmap/pkt-gen.c
+++ b/tools/tools/netmap/pkt-gen.c
@@ -917,7 +917,7 @@ update_ip6(struct pkt *pkt, struct targ *t)
 	struct glob_arg *g = t->g;
 	struct ip6_hdr ip6;
 	struct udphdr udp;
-	uint16_t udp_sum;
+	uint16_t udp_sum = 0;
 	uint16_t oaddr, naddr;
 	uint16_t oport, nport;
 	uint8_t group;
@@ -925,7 +925,6 @@ update_ip6(struct pkt *pkt, struct targ *t)
 	memcpy(&ip6, &pkt->ipv6.ip, sizeof(ip6));
 	memcpy(&udp, &pkt->ipv6.udp, sizeof(udp));
 	do {
-		udp_sum = 0;
 		group = g->src_ip.ipv6.sgroup;
 		naddr = oaddr = ntohs(ip6.ip6_src.s6_addr16[group]);
 		nport = oport = ntohs(udp.uh_sport);
@@ -934,29 +933,28 @@ update_ip6(struct pkt *pkt, struct targ *t)
 			udp.uh_sport = nrand48(t->seed);
 			naddr = ntohs(ip6.ip6_src.s6_addr16[group]);
 			nport = ntohs(udp.uh_sport);
+			udp_sum = new_udp_sum(udp_sum, oaddr, naddr);
+			udp_sum = new_udp_sum(udp_sum, oport, nport);
 			break;
 		}
 		if (oport < g->src_ip.port1) {
 			nport = oport + 1;
 			udp.uh_sport = htons(nport);
+			udp_sum = new_udp_sum(udp_sum, oport, nport);
 			break;
 		}
 		nport = g->src_ip.port0;
 		udp.uh_sport = htons(nport);
+		udp_sum = new_udp_sum(udp_sum, oport, nport);
 		if (oaddr < ntohs(g->src_ip.ipv6.end.s6_addr16[group])) {
 			naddr = oaddr + 1;
 			ip6.ip6_src.s6_addr16[group] = htons(naddr);
+			udp_sum = new_udp_sum(udp_sum, oaddr, naddr);
 			break;
 		}
 		naddr = ntohs(g->src_ip.ipv6.start.s6_addr16[group]);
 		ip6.ip6_src.s6_addr16[group] = htons(naddr);
-
-		/* update checksums if needed */
-		if (oaddr != naddr)
-			udp_sum = cksum_add(~oaddr, naddr);
-		if (oport != nport)
-			udp_sum = cksum_add(udp_sum,
-			    cksum_add(~oport, nport));
+		udp_sum = new_udp_sum(udp_sum, oaddr, naddr);
 
 		group = g->dst_ip.ipv6.egroup;
 		naddr = oaddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
@@ -966,32 +964,32 @@ update_ip6(struct pkt *pkt, struct targ *t)
 			udp.uh_dport = nrand48(t->seed);
 			naddr = ntohs(ip6.ip6_dst.s6_addr16[group]);
 			nport = ntohs(udp.uh_dport);
+			udp_sum = new_udp_sum(udp_sum, oaddr, naddr);
+			udp_sum = new_udp_sum(udp_sum, oport, nport);
 			break;
 		}
 		if (oport < g->dst_ip.port1) {
 			nport = oport + 1;
 			udp.uh_dport = htons(nport);
+			udp_sum = new_udp_sum(udp_sum, oport, nport);
 			break;
 		}
 		nport = g->dst_ip.port0;
 		udp.uh_dport = htons(nport);
+		udp_sum = new_udp_sum(udp_sum, oport, nport);
 		if (oaddr < ntohs(g->dst_ip.ipv6.end.s6_addr16[group])) {
 			naddr = oaddr + 1;
 			ip6.ip6_dst.s6_addr16[group] = htons(naddr);
+			udp_sum = new_udp_sum(udp_sum, oaddr, naddr);
 			break;
 		}
 		naddr = ntohs(g->dst_ip.ipv6.start.s6_addr16[group]);
 		ip6.ip6_dst.s6_addr16[group] = htons(naddr);
+		udp_sum = new_udp_sum(udp_sum, oaddr, naddr);
 	} while (0);
 	/* update checksums */
-	if (oaddr != naddr)
-		udp_sum = cksum_add(udp_sum,
-		    cksum_add(~oaddr, naddr));
-	if (oport != nport)
-		udp_sum = cksum_add(udp_sum,
-		    cksum_add(~oport, nport));
 	if (udp_sum != 0)
-		udp.uh_sum = ~cksum_add(~udp.uh_sum, udp_sum);
+		udp.uh_sum = ~cksum_add(~udp.uh_sum, htons(udp_sum));
 	memcpy(&pkt->ipv6.ip, &ip6, sizeof(ip6));
 	memcpy(&pkt->ipv6.udp, &udp, sizeof(udp));
 }