overlay/checksum: test each arch implementation directly

The correctness sweeps only exercised the public Checksum dispatcher, so
wherever it resolved to the gvisor fallback (non-AVX2 amd64, fallback
architectures) the suite compared gvisor against itself and the AVX2
assembly went untested -- silently green. Per-arch export_test.go files
now enumerate the hand-written implementations and every sweep runs
against the dispatcher plus each of them, skipping with an explicit
message when the running CPU can't execute one.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
JackDoan
2026-07-27 15:55:28 -05:00
parent 8cebecc087
commit 865dc9725c
4 changed files with 132 additions and 64 deletions
+106 -64
View File
@@ -8,37 +8,69 @@ import (
gvisorchecksum "gvisor.dev/gvisor/pkg/tcpip/checksum" gvisorchecksum "gvisor.dev/gvisor/pkg/tcpip/checksum"
) )
// TestChecksumMatchesGvisor walks lengths from 0 to 4096, with several initial // archImpl names one checksum function under test. The per-arch
// seeds and a handful of starting alignments, asserting that our local // export_*_test.go files enumerate the hand-written implementations so the
// Checksum matches gvisor's reference bit-for-bit. // suite compares each one against gvisor directly, regardless of which one
func TestChecksumMatchesGvisor(t *testing.T) { // the public Checksum dispatches to on the running CPU. Testing only the
rng := rand.New(rand.NewPCG(1, 2)) // dispatcher was tautological wherever it resolved to the gvisor fallback
const padFront = 16 // (non-AVX2 amd64, fallback architectures) — gvisor compared with itself,
// assembly untested, suite green.
type archImpl struct {
name string
fn func([]byte, uint16) uint16
available bool
}
// Random pool large enough for the longest case + alignment slop. // implsUnderTest is the public dispatcher plus every arch implementation.
pool := make([]byte, 4096+padFront) func implsUnderTest() []archImpl {
for i := range pool { return append([]archImpl{{name: "dispatch", fn: Checksum, available: true}}, archImpls...)
pool[i] = byte(rng.Uint32()) }
// requireAvailable skips loudly when the running CPU can't execute an
// implementation — visible in test output, unlike the old silent tautology.
func requireAvailable(t *testing.T, impl archImpl) {
t.Helper()
if !impl.available {
t.Skipf("%s not supported on this CPU; its assembly is NOT tested in this run", impl.name)
} }
}
seeds := []uint16{0, 0x0001, 0xabcd, 0xffff, 0x1234, 0xfedc} // TestChecksumMatchesGvisor walks lengths from 0 to 4096, with several initial
offsets := []int{0, 1, 2, 3, 4, 5, 7, 8, 15, 16} // seeds and a handful of starting alignments, asserting that each local
// implementation matches gvisor's reference bit-for-bit.
func TestChecksumMatchesGvisor(t *testing.T) {
for _, impl := range implsUnderTest() {
t.Run(impl.name, func(t *testing.T) {
requireAvailable(t, impl)
rng := rand.New(rand.NewPCG(1, 2))
const padFront = 16
for length := 0; length <= 4096; length++ { // Random pool large enough for the longest case + alignment slop.
for _, seed := range seeds { pool := make([]byte, 4096+padFront)
for _, off := range offsets { for i := range pool {
if off+length > len(pool) { pool[i] = byte(rng.Uint32())
continue }
}
buf := pool[off : off+length] seeds := []uint16{0, 0x0001, 0xabcd, 0xffff, 0x1234, 0xfedc}
want := gvisorchecksum.Checksum(buf, seed) offsets := []int{0, 1, 2, 3, 4, 5, 7, 8, 15, 16}
got := Checksum(buf, seed)
if got != want { for length := 0; length <= 4096; length++ {
t.Fatalf("len=%d off=%d seed=%#x: got %#04x want %#04x", for _, seed := range seeds {
length, off, seed, got, want) for _, off := range offsets {
if off+length > len(pool) {
continue
}
buf := pool[off : off+length]
want := gvisorchecksum.Checksum(buf, seed)
got := impl.fn(buf, seed)
if got != want {
t.Fatalf("len=%d off=%d seed=%#x: got %#04x want %#04x",
length, off, seed, got, want)
}
}
} }
} }
} })
} }
} }
@@ -46,23 +78,28 @@ func TestChecksumMatchesGvisor(t *testing.T) {
// historically tripped up checksum implementations: all-zero, all-0xff, // historically tripped up checksum implementations: all-zero, all-0xff,
// alternating, and ascending sequences. // alternating, and ascending sequences.
func TestChecksumPatternedBuffers(t *testing.T) { func TestChecksumPatternedBuffers(t *testing.T) {
for length := 0; length <= 256; length++ { for _, impl := range implsUnderTest() {
patterns := map[string][]byte{ t.Run(impl.name, func(t *testing.T) {
"zeros": make([]byte, length), requireAvailable(t, impl)
"ones": bytes(length, 0xff), for length := 0; length <= 256; length++ {
"alternating": pattern(length, []byte{0xa5, 0x5a}), patterns := map[string][]byte{
"ascending": ascending(length), "zeros": make([]byte, length),
} "ones": bytes(length, 0xff),
for name, buf := range patterns { "alternating": pattern(length, []byte{0xa5, 0x5a}),
for _, seed := range []uint16{0, 0xffff, 0x8000} { "ascending": ascending(length),
want := gvisorchecksum.Checksum(buf, seed) }
got := Checksum(buf, seed) for name, buf := range patterns {
if got != want { for _, seed := range []uint16{0, 0xffff, 0x8000} {
t.Fatalf("%s len=%d seed=%#x: got %#04x want %#04x", want := gvisorchecksum.Checksum(buf, seed)
name, length, seed, got, want) got := impl.fn(buf, seed)
if got != want {
t.Fatalf("%s len=%d seed=%#x: got %#04x want %#04x",
name, length, seed, got, want)
}
}
} }
} }
} })
} }
} }
@@ -98,36 +135,41 @@ func ascending(n int) []byte {
// and k=1 (one main loop iter, then tail). It's explicit coverage for // and k=1 (one main loop iter, then tail). It's explicit coverage for
// payload sizes that are odd, not divisible by 4, by 8, or by 32. // payload sizes that are odd, not divisible by 4, by 8, or by 32.
func TestChecksumTailPaths(t *testing.T) { func TestChecksumTailPaths(t *testing.T) {
rng := rand.New(rand.NewPCG(42, 17)) for _, impl := range implsUnderTest() {
const padFront = 16 t.Run(impl.name, func(t *testing.T) {
const maxK = 8 requireAvailable(t, impl)
rng := rand.New(rand.NewPCG(42, 17))
const padFront = 16
const maxK = 8
pool := make([]byte, 64*maxK+padFront+64) pool := make([]byte, 64*maxK+padFront+64)
for i := range pool { for i := range pool {
pool[i] = byte(rng.Uint32()) pool[i] = byte(rng.Uint32())
} }
seeds := []uint16{0, 0xffff, 0xabcd} seeds := []uint16{0, 0xffff, 0xabcd}
offsets := []int{0, 1, 3, 7, 15} // mix of aligned and odd starts offsets := []int{0, 1, 3, 7, 15} // mix of aligned and odd starts
for k := 0; k <= maxK; k++ { for k := 0; k <= maxK; k++ {
for tail := 0; tail < 64; tail++ { for tail := 0; tail < 64; tail++ {
length := 64*k + tail length := 64*k + tail
for _, seed := range seeds { for _, seed := range seeds {
for _, off := range offsets { for _, off := range offsets {
if off+length > len(pool) { if off+length > len(pool) {
continue continue
} }
buf := pool[off : off+length] buf := pool[off : off+length]
want := gvisorchecksum.Checksum(buf, seed) want := gvisorchecksum.Checksum(buf, seed)
got := Checksum(buf, seed) got := impl.fn(buf, seed)
if got != want { if got != want {
t.Fatalf("k=%d tail=%d (len=%d) off=%d seed=%#x: got %#04x want %#04x", t.Fatalf("k=%d tail=%d (len=%d) off=%d seed=%#x: got %#04x want %#04x",
k, tail, length, off, seed, got, want) k, tail, length, off, seed, got, want)
}
}
} }
} }
} }
} })
} }
} }
+11
View File
@@ -0,0 +1,11 @@
package checksum
// archImpls exposes every hand-written implementation on this architecture
// so the tests exercise them directly, independent of what the public
// Checksum dispatches to on the running CPU. Without this, running the
// suite on a non-AVX2 machine compared gvisor against itself and left the
// assembly untested — silently. available=false makes the test skip loudly
// instead.
var archImpls = []archImpl{
{name: "avx2", fn: checksumAVX2, available: hasAVX2},
}
+8
View File
@@ -0,0 +1,8 @@
package checksum
// archImpls exposes every hand-written implementation on this architecture
// for direct testing; see export_amd64_test.go for the rationale. NEON is
// mandatory in armv8, so it is always available.
var archImpls = []archImpl{
{name: "neon", fn: checksumNEON, available: true},
}
+7
View File
@@ -0,0 +1,7 @@
//go:build !amd64 && !arm64
package checksum
// No hand-written implementations on this architecture; the dispatcher is
// pure gvisor and there is nothing separate to test.
var archImpls []archImpl