From a8786c07c1db7fecdb22fe524ae0072e302a5d67 Mon Sep 17 00:00:00 2001 From: Lukasz Szaszkiewicz Date: Mon, 23 Nov 2020 12:36:05 +0100 Subject: [PATCH] improve DefaultClientDialContext wrapping the DialContext method and setting the socket options on a copy of the file descriptor is not deterministic. as per documentation attempting to change properties of the original using this duplicate may or may not have the desired effect. instead we should set the options on the original file descriptor. --- pkg/network/dialer_linux.go | 42 +++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/pkg/network/dialer_linux.go b/pkg/network/dialer_linux.go index e3cd3f4d3c..b8ff8db85e 100644 --- a/pkg/network/dialer_linux.go +++ b/pkg/network/dialer_linux.go @@ -3,41 +3,38 @@ package network import ( - "context" "net" "os" "syscall" "time" "golang.org/x/sys/unix" + + utilerrors "k8s.io/apimachinery/pkg/util/errors" ) func dialerWithDefaultOptions() DialContext { nd := &net.Dialer{ // TCP_USER_TIMEOUT does affect the behaviour of connect() which is controlled by this field so we set it to the same value Timeout: 25 * time.Second, - } - return wrapDialContext(nd.DialContext) -} - -func wrapDialContext(dc DialContext) DialContext { - return func(ctx context.Context, network, address string) (net.Conn, error) { - conn, err := dc(ctx, network, address) - if err != nil { - return conn, err - } - - if tcpCon, ok := conn.(*net.TCPConn); ok { - tcpFD, err := tcpCon.File() + // KeepAlive must to be set to a negative value to stop std library from applying the default values + // by doing so we ensure that the options we are interested in won't be overwritten + KeepAlive: time.Duration(-1), + Control: func(network, address string, con syscall.RawConn) error { + var errs []error + err := con.Control(func(fd uintptr) { + optionsErr := setDefaultSocketOptions(int(fd)) + if optionsErr != nil { + errs = append(errs, optionsErr) + } + }) if err != nil { - return conn, err + errs = append(errs, err) } - if err := setDefaultSocketOptions(int(tcpFD.Fd())); err != nil { - return conn, err - } - } - return conn, nil + return utilerrors.NewAggregate(errs) + }, } + return nd.DialContext } // setDefaultSocketOptions sets custom socket options so that we can detect connections to an unhealthy (dead) peer quickly. @@ -58,6 +55,11 @@ func setDefaultSocketOptions(fd int) error { // specifies the threshold for sending the first KEEP ALIVE probe in seconds tcpKeepIdle := int(roundDuration(2*time.Second, time.Second)) + // enable keep-alive probes + if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil { + return wrapSyscallError("setsockopt", err) + } + if err := syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, tcpUserTimeoutInMilliSeconds); err != nil { return wrapSyscallError("setsockopt", err) }