From 3bcbab3f74ef4651264aef8be5fc76d0495943cd Mon Sep 17 00:00:00 2001 From: "Bryan C. Mills" Date: Thu, 24 Feb 2022 16:00:15 -0500 Subject: [PATCH] ipv4: retry ENOBUFS errors in TestPacketConnConcurrentReadWriteUnicast MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is sheer speculation based on the failures observed in golang/go#37319. (A deadlock in the test prevented us from seeing the actual failure mode of golang/go#51342 up until CL 387915, and it isn't obvious to me that we should wait for another failure before trying a likely — and otherwise harmless — fix.) This is a port of CL 376095 to the "ipv4" package. Fixes golang/go#51342. (Maybe.) Change-Id: Idd6d2d785dbb0c98404f99bd98a3c4ddc11cb2cf Reviewed-on: https://go-review.googlesource.com/c/net/+/387916 Trust: Bryan Mills Run-TryBot: Bryan Mills TryBot-Result: Gopher Robot Reviewed-by: Ian Lance Taylor --- ipv4/errors_other_test.go | 14 +++++++++++ ipv4/errors_unix_test.go | 20 +++++++++++++++ ipv4/readwrite_test.go | 51 +++++++++++++++++++++++++++------------ 3 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 ipv4/errors_other_test.go create mode 100644 ipv4/errors_unix_test.go diff --git a/ipv4/errors_other_test.go b/ipv4/errors_other_test.go new file mode 100644 index 00000000..61543539 --- /dev/null +++ b/ipv4/errors_other_test.go @@ -0,0 +1,14 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !(aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris) +// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris + +package ipv4_test + +// isENOBUFS reports whether err is unix.ENOBUFS. +// (Always false on non-Unix platforms.) +func isENOBUFS(err error) bool { + return false +} diff --git a/ipv4/errors_unix_test.go b/ipv4/errors_unix_test.go new file mode 100644 index 00000000..566e070a --- /dev/null +++ b/ipv4/errors_unix_test.go @@ -0,0 +1,20 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris +// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris + +package ipv4_test + +import ( + "errors" + + "golang.org/x/sys/unix" +) + +// isENOBUFS reports whether err is unix.ENOBUFS. +// (Always false on non-Unix platforms.) +func isENOBUFS(err error) bool { + return errors.Is(err, unix.ENOBUFS) +} diff --git a/ipv4/readwrite_test.go b/ipv4/readwrite_test.go index e0176a2e..11281a44 100644 --- a/ipv4/readwrite_test.go +++ b/ipv4/readwrite_test.go @@ -12,6 +12,7 @@ import ( "strings" "sync" "testing" + "time" "golang.org/x/net/internal/iana" "golang.org/x/net/ipv4" @@ -450,12 +451,22 @@ func testPacketConnConcurrentReadWriteUnicast(t *testing.T, p *ipv4.PacketConn, if err := p.SetControlMessage(cf, toggle); err != nil { fatalf("%v", err) } - n, err := p.WriteTo(data, &cm, dst) - if err != nil { - fatalf("%v", err) - } - if n != len(data) { - fatalf("got %d; want %d", n, len(data)) + + backoff := time.Millisecond + for { + n, err := p.WriteTo(data, &cm, dst) + if err != nil { + if n == 0 && isENOBUFS(err) { + time.Sleep(backoff) + backoff *= 2 + continue + } + fatalf("%v", err) + } + if n != len(data) { + fatalf("got %d; want %d", n, len(data)) + } + break } } batchWriter := func(toggle bool) { @@ -476,15 +487,25 @@ func testPacketConnConcurrentReadWriteUnicast(t *testing.T, p *ipv4.PacketConn, Addr: dst, }, } - n, err := p.WriteBatch(ms, 0) - if err != nil { - fatalf("%v", err) - } - if n != len(ms) { - fatalf("got %d; want %d", n, len(ms)) - } - if ms[0].N != len(data) { - fatalf("got %d; want %d", ms[0].N, len(data)) + + backoff := time.Millisecond + for { + n, err := p.WriteBatch(ms, 0) + if err != nil { + if n == 0 && isENOBUFS(err) { + time.Sleep(backoff) + backoff *= 2 + continue + } + fatalf("%v", err) + } + if n != len(ms) { + fatalf("got %d; want %d", n, len(ms)) + } + if ms[0].N != len(data) { + fatalf("got %d; want %d", ms[0].N, len(data)) + } + break } }