]> Cypherpunks repositories - gostls13.git/commitdiff
net: reflect TCP backlog size update of uint16->uint32 on Linux
authorCuong Manh Le <cuong@orijtech.com>
Tue, 22 Sep 2020 02:30:31 +0000 (09:30 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Wed, 23 Sep 2020 02:32:24 +0000 (02:32 +0000)
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>
src/net/sock_linux.go
src/net/sock_linux_test.go [new file with mode: 0644]

index 7bca37605ec215b66d1186124c578ff1730124f9..4d9100193795a711e21e2b71fd74a13eb184745c 100644 (file)
@@ -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 (file)
index 0000000..5df0293
--- /dev/null
@@ -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)
+       }
+}