summaryrefslogtreecommitdiff
path: root/src/net
diff options
context:
space:
mode:
authorCuong Manh Le <cuong@orijtech.com>2020-09-22 09:30:31 +0700
committerCuong Manh Le <cuong.manhle.vn@gmail.com>2020-09-23 02:32:24 +0000
commit0a9dd47dd817904ec2b4a80b551e6050218ee8a6 (patch)
tree7bcdb749fca76447145c22b2831cb47ef4e99e4c /src/net
parentd2bd93a01096ac6dc8061112e7a9ac62ec239627 (diff)
downloadgo-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.go62
-rw-r--r--src/net/sock_linux_test.go22
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)
+ }
+}