diff options
| author | Cuong Manh Le <cuong@orijtech.com> | 2020-09-22 09:30:31 +0700 |
|---|---|---|
| committer | Cuong Manh Le <cuong.manhle.vn@gmail.com> | 2020-09-23 02:32:24 +0000 |
| commit | 0a9dd47dd817904ec2b4a80b551e6050218ee8a6 (patch) | |
| tree | 7bcdb749fca76447145c22b2831cb47ef4e99e4c /src/net | |
| parent | d2bd93a01096ac6dc8061112e7a9ac62ec239627 (diff) | |
| download | go-git-0a9dd47dd817904ec2b4a80b551e6050218ee8a6.tar.gz | |
net: reflect TCP backlog size update of uint16->uint32 on Linux
The sk_max_ack_backlog was increased from uint16 to uint32 in kernel
version 4.1 and above, so adopt that change to maxListenerBacklog.
See https://github.com/torvalds/linux/commit/becb74f0acca19b5abfcb24dc602530f3deea66a
Fixes #41470
Change-Id: I63a142eb28f3ac3acaca57f0903c085c6cb15a6e
Reviewed-on: https://go-review.googlesource.com/c/go/+/255898
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Trust: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Diffstat (limited to 'src/net')
| -rw-r--r-- | src/net/sock_linux.go | 62 | ||||
| -rw-r--r-- | src/net/sock_linux_test.go | 22 |
2 files changed, 80 insertions, 4 deletions
diff --git a/src/net/sock_linux.go b/src/net/sock_linux.go index 7bca37605e..4d91001937 100644 --- a/src/net/sock_linux.go +++ b/src/net/sock_linux.go @@ -6,6 +6,62 @@ package net import "syscall" +func kernelVersion() (major int, minor int) { + var uname syscall.Utsname + if err := syscall.Uname(&uname); err != nil { + return + } + + rl := uname.Release + var values [2]int + vi := 0 + value := 0 + for _, c := range rl { + if c >= '0' && c <= '9' { + value = (value * 10) + int(c-'0') + } else { + // Note that we're assuming N.N.N here. If we see anything else we are likely to + // mis-parse it. + values[vi] = value + vi++ + if vi >= len(values) { + break + } + } + } + switch vi { + case 0: + return 0, 0 + case 1: + return values[0], 0 + case 2: + return values[0], values[1] + } + return +} + +// Linux stores the backlog as: +// +// - uint16 in kernel version < 4.1, +// - uint32 in kernel version >= 4.1 +// +// Truncate number to avoid wrapping. +// +// See issue 5030 and 41470. +func maxAckBacklog(n int) int { + major, minor := kernelVersion() + size := 16 + if major > 4 || (major == 4 && minor >= 1) { + size = 32 + } + + var max uint = 1<<size - 1 + if uint(n) > max { + n = int(max) + } + return n +} + func maxListenerBacklog() int { fd, err := open("/proc/sys/net/core/somaxconn") if err != nil { @@ -21,11 +77,9 @@ func maxListenerBacklog() int { if n == 0 || !ok { return syscall.SOMAXCONN } - // Linux stores the backlog in a uint16. - // Truncate number to avoid wrapping. - // See issue 5030. + if n > 1<<16-1 { - n = 1<<16 - 1 + return maxAckBacklog(n) } return n } diff --git a/src/net/sock_linux_test.go b/src/net/sock_linux_test.go new file mode 100644 index 0000000000..5df02935c3 --- /dev/null +++ b/src/net/sock_linux_test.go @@ -0,0 +1,22 @@ +// Copyright 2020 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. + +package net + +import ( + "testing" +) + +func TestMaxAckBacklog(t *testing.T) { + n := 196602 + major, minor := kernelVersion() + backlog := maxAckBacklog(n) + expected := 1<<16 - 1 + if major > 4 || (major == 4 && minor >= 1) { + expected = n + } + if backlog != expected { + t.Fatalf(`Kernel version: "%d.%d", sk_max_ack_backlog mismatch, got %d, want %d`, major, minor, backlog, expected) + } +} |
