Skip to content

Commit 0a9dd47

Browse files
Cuong Manh Lecuonglm
Cuong Manh Le
authored andcommitted
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 torvalds/linux@becb74f Fixes #41470 Change-Id: I63a142eb28f3ac3acaca57f0903c085c6cb15a6e Reviewed-on: https://go-review.googlesource.com/c/go/+/255898 Run-TryBot: Cuong Manh Le <[email protected]> TryBot-Result: Go Bot <[email protected]> Trust: Cuong Manh Le <[email protected]> Trust: Emmanuel Odeke <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Emmanuel Odeke <[email protected]>
1 parent d2bd93a commit 0a9dd47

File tree

2 files changed

+80
-4
lines changed

2 files changed

+80
-4
lines changed

src/net/sock_linux.go

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,62 @@ package net
66

77
import "syscall"
88

9+
func kernelVersion() (major int, minor int) {
10+
var uname syscall.Utsname
11+
if err := syscall.Uname(&uname); err != nil {
12+
return
13+
}
14+
15+
rl := uname.Release
16+
var values [2]int
17+
vi := 0
18+
value := 0
19+
for _, c := range rl {
20+
if c >= '0' && c <= '9' {
21+
value = (value * 10) + int(c-'0')
22+
} else {
23+
// Note that we're assuming N.N.N here. If we see anything else we are likely to
24+
// mis-parse it.
25+
values[vi] = value
26+
vi++
27+
if vi >= len(values) {
28+
break
29+
}
30+
}
31+
}
32+
switch vi {
33+
case 0:
34+
return 0, 0
35+
case 1:
36+
return values[0], 0
37+
case 2:
38+
return values[0], values[1]
39+
}
40+
return
41+
}
42+
43+
// Linux stores the backlog as:
44+
//
45+
// - uint16 in kernel version < 4.1,
46+
// - uint32 in kernel version >= 4.1
47+
//
48+
// Truncate number to avoid wrapping.
49+
//
50+
// See issue 5030 and 41470.
51+
func maxAckBacklog(n int) int {
52+
major, minor := kernelVersion()
53+
size := 16
54+
if major > 4 || (major == 4 && minor >= 1) {
55+
size = 32
56+
}
57+
58+
var max uint = 1<<size - 1
59+
if uint(n) > max {
60+
n = int(max)
61+
}
62+
return n
63+
}
64+
965
func maxListenerBacklog() int {
1066
fd, err := open("/proc/sys/net/core/somaxconn")
1167
if err != nil {
@@ -21,11 +77,9 @@ func maxListenerBacklog() int {
2177
if n == 0 || !ok {
2278
return syscall.SOMAXCONN
2379
}
24-
// Linux stores the backlog in a uint16.
25-
// Truncate number to avoid wrapping.
26-
// See issue 5030.
80+
2781
if n > 1<<16-1 {
28-
n = 1<<16 - 1
82+
return maxAckBacklog(n)
2983
}
3084
return n
3185
}

src/net/sock_linux_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2020 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package net
6+
7+
import (
8+
"testing"
9+
)
10+
11+
func TestMaxAckBacklog(t *testing.T) {
12+
n := 196602
13+
major, minor := kernelVersion()
14+
backlog := maxAckBacklog(n)
15+
expected := 1<<16 - 1
16+
if major > 4 || (major == 4 && minor >= 1) {
17+
expected = n
18+
}
19+
if backlog != expected {
20+
t.Fatalf(`Kernel version: "%d.%d", sk_max_ack_backlog mismatch, got %d, want %d`, major, minor, backlog, expected)
21+
}
22+
}

0 commit comments

Comments
 (0)