mirror of
https://github.com/slackhq/nebula.git
synced 2026-08-16 20:37:01 +02:00
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:
@@ -8,10 +8,40 @@ import (
|
||||
gvisorchecksum "gvisor.dev/gvisor/pkg/tcpip/checksum"
|
||||
)
|
||||
|
||||
// archImpl names one checksum function under test. The per-arch
|
||||
// export_*_test.go files enumerate the hand-written implementations so the
|
||||
// suite compares each one against gvisor directly, regardless of which one
|
||||
// the public Checksum dispatches to on the running CPU. Testing only the
|
||||
// dispatcher was tautological wherever it resolved to the gvisor fallback
|
||||
// (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
|
||||
}
|
||||
|
||||
// implsUnderTest is the public dispatcher plus every arch implementation.
|
||||
func implsUnderTest() []archImpl {
|
||||
return append([]archImpl{{name: "dispatch", fn: Checksum, available: true}}, archImpls...)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// TestChecksumMatchesGvisor walks lengths from 0 to 4096, with several initial
|
||||
// seeds and a handful of starting alignments, asserting that our local
|
||||
// Checksum matches gvisor's reference bit-for-bit.
|
||||
// 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
|
||||
|
||||
@@ -32,7 +62,7 @@ func TestChecksumMatchesGvisor(t *testing.T) {
|
||||
}
|
||||
buf := pool[off : off+length]
|
||||
want := gvisorchecksum.Checksum(buf, seed)
|
||||
got := 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)
|
||||
@@ -40,12 +70,17 @@ func TestChecksumMatchesGvisor(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestChecksumPatternedBuffers exercises specific byte patterns that have
|
||||
// historically tripped up checksum implementations: all-zero, all-0xff,
|
||||
// alternating, and ascending sequences.
|
||||
func TestChecksumPatternedBuffers(t *testing.T) {
|
||||
for _, impl := range implsUnderTest() {
|
||||
t.Run(impl.name, func(t *testing.T) {
|
||||
requireAvailable(t, impl)
|
||||
for length := 0; length <= 256; length++ {
|
||||
patterns := map[string][]byte{
|
||||
"zeros": make([]byte, length),
|
||||
@@ -56,7 +91,7 @@ func TestChecksumPatternedBuffers(t *testing.T) {
|
||||
for name, buf := range patterns {
|
||||
for _, seed := range []uint16{0, 0xffff, 0x8000} {
|
||||
want := gvisorchecksum.Checksum(buf, seed)
|
||||
got := Checksum(buf, seed)
|
||||
got := impl.fn(buf, seed)
|
||||
if got != want {
|
||||
t.Fatalf("%s len=%d seed=%#x: got %#04x want %#04x",
|
||||
name, length, seed, got, want)
|
||||
@@ -64,6 +99,8 @@ func TestChecksumPatternedBuffers(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func bytes(n int, v byte) []byte {
|
||||
@@ -98,6 +135,9 @@ func ascending(n int) []byte {
|
||||
// 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.
|
||||
func TestChecksumTailPaths(t *testing.T) {
|
||||
for _, impl := range implsUnderTest() {
|
||||
t.Run(impl.name, func(t *testing.T) {
|
||||
requireAvailable(t, impl)
|
||||
rng := rand.New(rand.NewPCG(42, 17))
|
||||
const padFront = 16
|
||||
const maxK = 8
|
||||
@@ -120,7 +160,7 @@ func TestChecksumTailPaths(t *testing.T) {
|
||||
}
|
||||
buf := pool[off : off+length]
|
||||
want := gvisorchecksum.Checksum(buf, seed)
|
||||
got := Checksum(buf, seed)
|
||||
got := impl.fn(buf, seed)
|
||||
if got != want {
|
||||
t.Fatalf("k=%d tail=%d (len=%d) off=%d seed=%#x: got %#04x want %#04x",
|
||||
k, tail, length, off, seed, got, want)
|
||||
@@ -129,6 +169,8 @@ func TestChecksumTailPaths(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// BenchmarkChecksumTailSizes covers payload sizes that aren't clean multiples
|
||||
|
||||
@@ -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},
|
||||
}
|
||||
@@ -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},
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user