route: retry FetchRIB a few times in case data grows
Fixes golang/go#45736
Change-Id: I7e7926ba1a0ff752ba914429c5886ff2be9801a8
Reviewed-on: https://go-review.googlesource.com/c/net/+/313649
Trust: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/route/route.go b/route/route.go
index e3d6da0..fd0019e 100644
--- a/route/route.go
+++ b/route/route.go
@@ -108,17 +108,28 @@
// an interface index or a set of interface flags. In most cases, zero
// means a wildcard.
func FetchRIB(af int, typ RIBType, arg int) ([]byte, error) {
- mib := [6]int32{sysCTL_NET, sysAF_ROUTE, 0, int32(af), int32(typ), int32(arg)}
- n := uintptr(0)
- if err := sysctl(mib[:], nil, &n, nil, 0); err != nil {
- return nil, os.NewSyscallError("sysctl", err)
+ try := 0
+ for {
+ try++
+ mib := [6]int32{sysCTL_NET, sysAF_ROUTE, 0, int32(af), int32(typ), int32(arg)}
+ n := uintptr(0)
+ if err := sysctl(mib[:], nil, &n, nil, 0); err != nil {
+ return nil, os.NewSyscallError("sysctl", err)
+ }
+ if n == 0 {
+ return nil, nil
+ }
+ b := make([]byte, n)
+ if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil {
+ // If the sysctl failed because the data got larger
+ // between the two sysctl calls, try a few times
+ // before failing. (golang.org/issue/45736).
+ const maxTries = 3
+ if err == syscall.ENOMEM && try < maxTries {
+ continue
+ }
+ return nil, os.NewSyscallError("sysctl", err)
+ }
+ return b[:n], nil
}
- if n == 0 {
- return nil, nil
- }
- b := make([]byte, n)
- if err := sysctl(mib[:], &b[0], &n, nil, 0); err != nil {
- return nil, os.NewSyscallError("sysctl", err)
- }
- return b[:n], nil
}
diff --git a/route/route_test.go b/route/route_test.go
index 2693269..27f05b8 100644
--- a/route/route_test.go
+++ b/route/route_test.go
@@ -11,7 +11,6 @@
"fmt"
"os/exec"
"runtime"
- "time"
)
func (m *RouteMessage) String() string {
@@ -311,15 +310,7 @@
}
func fetchAndParseRIB(af int, typ RIBType) ([]Message, error) {
- var err error
- var b []byte
- for i := 0; i < 3; i++ {
- if b, err = FetchRIB(af, typ, 0); err != nil {
- time.Sleep(10 * time.Millisecond)
- continue
- }
- break
- }
+ b, err := FetchRIB(af, typ, 0)
if err != nil {
return nil, fmt.Errorf("%v %d %v", addrFamily(af), typ, err)
}