From 359e790dd1b422c23d279388b0e9b67819e0d0af Mon Sep 17 00:00:00 2001 From: "randomizedcoder dave.seddon.ca@gmail.com" Date: Wed, 28 Oct 2026 18:56:04 -0700 Subject: [PATCH] Include all of the IPv6 address in homa_qdisc_can_bypass * homa_qdisc_can_bypass hashed the new packet's IPv6 destination as words 0^2^3 but each deferred packet's as 0^1^2^3. For any address whose second word is nonzero the two never match, so a TCP packet could bypass deferred packets of the same flow and be reordered. * The existing test uses IPv4-mapped addresses (word 1 is zero), which hid the mismatch; the new test uses a real IPv6 address. Co-Authored-By: Claude Opus 5.5 --- homa_qdisc.c | 1 + test/unit_homa_qdisc.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/homa_qdisc.c b/homa_qdisc.c index b84ef03c..df511334 100755 --- a/homa_qdisc.c +++ b/homa_qdisc.c @@ -651,6 +651,7 @@ bool homa_qdisc_can_bypass(struct sk_buff *skb, struct homa_qdisc *q) if (ipv6_hdr(skb)->nexthdr != IPPROTO_TCP) return false; daddr = ipv6_hdr(skb)->daddr.in6_u.u6_addr32[0] ^ + ipv6_hdr(skb)->daddr.in6_u.u6_addr32[1] ^ ipv6_hdr(skb)->daddr.in6_u.u6_addr32[2] ^ ipv6_hdr(skb)->daddr.in6_u.u6_addr32[3]; } else { diff --git a/test/unit_homa_qdisc.c b/test/unit_homa_qdisc.c index 9ea5bb8f..e1c93594 100644 --- a/test/unit_homa_qdisc.c +++ b/test/unit_homa_qdisc.c @@ -929,6 +929,26 @@ TEST_F(homa_qdisc, homa_qdisc_can_bypass__test_address_and_ports) kfree_skb(skb); } +TEST_F(homa_qdisc, homa_qdisc_can_bypass__ipv6_address_uses_all_words) +{ + struct in6_addr daddr = unit_get_in_addr("1:2:3::4"); + struct homa_qdisc *q = init_qdisc(self->qdiscs[3]); + struct sk_buff *skb; + + mock_ipv6 = true; + skb = mock_tcp_skb(&self->addr, &daddr, 4000, 100); + homa_qdisc_defer_tcp(q, skb); + + /* Same flow: must not bypass the deferred packet. */ + skb = mock_tcp_skb(&self->addr, &daddr, 5000, 200); + EXPECT_EQ(0, homa_qdisc_can_bypass(skb, q)); + + /* Address differs only in the second 32-bit word. */ + ipv6_hdr(skb)->daddr = unit_get_in_addr("1:2:5::4"); + EXPECT_EQ(1, homa_qdisc_can_bypass(skb, q)); + + kfree_skb(skb); +} TEST_F(homa_qdisc, homa_qdisc_can_bypass__multiple_packets_in_list) { struct homa_qdisc *q = init_qdisc(self->qdiscs[3]);