Skip to content

Commit

Permalink
Set user timeout for tcp connection
Browse files Browse the repository at this point in the history
This commit sets TCP_USER_TIMEOUT socket option for tcp connection
so that channel write doesn't block indefinitely on network disconnect.

Signed-off-by: Periyasamy Palanisamy <[email protected]>
  • Loading branch information
pperiyasamy committed Nov 9, 2023
1 parent 06c1f43 commit 3867774
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 2 deletions.
21 changes: 19 additions & 2 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/go-logr/logr"
"github.com/go-logr/stdr"
"github.com/ovn-org/libovsdb/cache"
syscall "github.com/ovn-org/libovsdb/internal"
"github.com/ovn-org/libovsdb/mapper"
"github.com/ovn-org/libovsdb/model"
"github.com/ovn-org/libovsdb/ovsdb"
Expand Down Expand Up @@ -352,7 +353,10 @@ func (o *ovsdbClient) tryEndpoint(ctx context.Context, u *url.URL) (string, erro
return "", fmt.Errorf("failed to open connection: %w", err)
}

o.createRPC2Client(c)
err = o.createRPC2Client(c)
if err != nil {
return "", err
}

serverDBNames, err := o.listDbs(ctx)
if err != nil {
Expand Down Expand Up @@ -423,12 +427,24 @@ func (o *ovsdbClient) tryEndpoint(ctx context.Context, u *url.URL) (string, erro
// createRPC2Client creates an rpcClient using the provided connection
// It is also responsible for setting up go routines for client-side event handling
// Should only be called when the mutex is held
func (o *ovsdbClient) createRPC2Client(conn net.Conn) {
func (o *ovsdbClient) createRPC2Client(conn net.Conn) error {
o.stopCh = make(chan struct{})
if o.options.inactivityTimeout > 0 {
o.trafficSeen = make(chan struct{})
}
o.conn = conn
// set TCP_USER_TIMEOUT socket option for connection so that
// channel write doesn't block indefinitely on network disconnect.
var userTimeout time.Duration
if o.options.timeout > 0 {
userTimeout = o.options.timeout * 3
} else {
userTimeout = defaultTimeout
}
err := syscall.SetTCPUserTimeout(conn, userTimeout)
if err != nil {
return err
}
o.rpcClient = rpc2.NewClientWithCodec(jsonrpc.NewJSONCodec(conn))
o.rpcClient.SetBlocking(true)
o.rpcClient.Handle("echo", func(_ *rpc2.Client, args []interface{}, reply *[]interface{}) error {
Expand All @@ -444,6 +460,7 @@ func (o *ovsdbClient) createRPC2Client(conn net.Conn) {
return o.update3(args, reply)
})
go o.rpcClient.Run()
return nil
}

// isEndpointLeader returns true if the currently connected endpoint is leader,
Expand Down
1 change: 1 addition & 0 deletions client/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
defaultTCPEndpoint = "tcp:127.0.0.1:6640"
defaultSSLEndpoint = "ssl:127.0.0.1:6640"
defaultUnixEndpoint = "unix:/var/run/openvswitch/ovsdb.sock"
defaultTimeout = 60 * time.Second
)

type options struct {
Expand Down
31 changes: 31 additions & 0 deletions internal/syscall_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package internal

import (
"fmt"
"net"
"syscall"
"time"

"golang.org/x/sys/unix"
)

// SetTCPUserTimeout sets the TCP user timeout on a connection's socket
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
tcpconn, ok := conn.(*net.TCPConn)
if !ok {
// not a TCP connection. exit early
return nil
}
rawConn, err := tcpconn.SyscallConn()
if err != nil {
return fmt.Errorf("error getting raw connection: %v", err)
}
err = rawConn.Control(func(fd uintptr) {
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond))
})
if err != nil {
return fmt.Errorf("error setting option on socket: %v", err)
}

return nil
}
14 changes: 14 additions & 0 deletions internal/syscall_nonlinux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build !linux
// +build !linux

package internal

import (
"net"
"time"
)

// SetTCPUserTimeout is a no-op function under non-linux environments.
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
return nil
}

0 comments on commit 3867774

Please sign in to comment.