{S,G}etsockopt for TCP_KEEPCNT option.

TCP_KEEPCNT is used to set the maximum keepalive probes to be
sent before dropping the connection.

WANT_LGTM=jchacon
PiperOrigin-RevId: 315758094
This commit is contained in:
Nayana Bidari
2020-06-10 13:37:27 -07:00
committed by gVisor bot
parent a5a4f80487
commit 4b9652d63b
3 changed files with 98 additions and 11 deletions
+1
View File
@@ -57,4 +57,5 @@ const (
const (
MAX_TCP_KEEPIDLE = 32767
MAX_TCP_KEEPINTVL = 32767
MAX_TCP_KEEPCNT = 127
)
+24 -11
View File
@@ -1246,6 +1246,18 @@ func getSockOptTCP(t *kernel.Task, ep commonEndpoint, name, outLen int) (interfa
return int32(time.Duration(v) / time.Second), nil
case linux.TCP_KEEPCNT:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
v, err := ep.GetSockOptInt(tcpip.KeepaliveCountOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
case linux.TCP_USER_TIMEOUT:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
@@ -1786,6 +1798,17 @@ func setSockOptTCP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *
}
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.KeepaliveIntervalOption(time.Second * time.Duration(v))))
case linux.TCP_KEEPCNT:
if len(optVal) < sizeOfInt32 {
return syserr.ErrInvalidArgument
}
v := usermem.ByteOrder.Uint32(optVal)
if v < 1 || v > linux.MAX_TCP_KEEPCNT {
return syserr.ErrInvalidArgument
}
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.KeepaliveCountOption, int(v)))
case linux.TCP_USER_TIMEOUT:
if len(optVal) < sizeOfInt32 {
return syserr.ErrInvalidArgument
@@ -2115,30 +2138,20 @@ func emitUnimplementedEventTCP(t *kernel.Task, name int) {
switch name {
case linux.TCP_CONGESTION,
linux.TCP_CORK,
linux.TCP_DEFER_ACCEPT,
linux.TCP_FASTOPEN,
linux.TCP_FASTOPEN_CONNECT,
linux.TCP_FASTOPEN_KEY,
linux.TCP_FASTOPEN_NO_COOKIE,
linux.TCP_KEEPCNT,
linux.TCP_KEEPIDLE,
linux.TCP_KEEPINTVL,
linux.TCP_LINGER2,
linux.TCP_MAXSEG,
linux.TCP_QUEUE_SEQ,
linux.TCP_QUICKACK,
linux.TCP_REPAIR,
linux.TCP_REPAIR_QUEUE,
linux.TCP_REPAIR_WINDOW,
linux.TCP_SAVED_SYN,
linux.TCP_SAVE_SYN,
linux.TCP_SYNCNT,
linux.TCP_THIN_DUPACK,
linux.TCP_THIN_LINEAR_TIMEOUTS,
linux.TCP_TIMESTAMP,
linux.TCP_ULP,
linux.TCP_USER_TIMEOUT,
linux.TCP_WINDOW_CLAMP:
linux.TCP_ULP:
t.Kernel().EmitUnimplementedEvent(t)
}
@@ -524,6 +524,7 @@ TEST_P(TCPSocketPairTest, SetTCPKeepintvlZero) {
// Copied from include/net/tcp.h.
constexpr int MAX_TCP_KEEPIDLE = 32767;
constexpr int MAX_TCP_KEEPINTVL = 32767;
constexpr int MAX_TCP_KEEPCNT = 127;
TEST_P(TCPSocketPairTest, SetTCPKeepidleAboveMax) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
@@ -575,6 +576,78 @@ TEST_P(TCPSocketPairTest, SetTCPKeepintvlToMax) {
EXPECT_EQ(get, MAX_TCP_KEEPINTVL);
}
TEST_P(TCPSocketPairTest, TCPKeepcountDefault) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
int get = -1;
socklen_t get_len = sizeof(get);
EXPECT_THAT(
getsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, 9); // 9 keepalive probes.
}
TEST_P(TCPSocketPairTest, SetTCPKeepcountZero) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
constexpr int kZero = 0;
EXPECT_THAT(setsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT, &kZero,
sizeof(kZero)),
SyscallFailsWithErrno(EINVAL));
}
TEST_P(TCPSocketPairTest, SetTCPKeepcountAboveMax) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
constexpr int kAboveMax = MAX_TCP_KEEPCNT + 1;
EXPECT_THAT(setsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT,
&kAboveMax, sizeof(kAboveMax)),
SyscallFailsWithErrno(EINVAL));
}
TEST_P(TCPSocketPairTest, SetTCPKeepcountToMax) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
EXPECT_THAT(setsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT,
&MAX_TCP_KEEPCNT, sizeof(MAX_TCP_KEEPCNT)),
SyscallSucceedsWithValue(0));
int get = -1;
socklen_t get_len = sizeof(get);
EXPECT_THAT(
getsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, MAX_TCP_KEEPCNT);
}
TEST_P(TCPSocketPairTest, SetTCPKeepcountToOne) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
int keepaliveCount = 1;
EXPECT_THAT(setsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT,
&keepaliveCount, sizeof(keepaliveCount)),
SyscallSucceedsWithValue(0));
int get = -1;
socklen_t get_len = sizeof(get);
EXPECT_THAT(
getsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, keepaliveCount);
}
TEST_P(TCPSocketPairTest, SetTCPKeepcountToNegative) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
int keepaliveCount = -5;
EXPECT_THAT(setsockopt(sockets->first_fd(), IPPROTO_TCP, TCP_KEEPCNT,
&keepaliveCount, sizeof(keepaliveCount)),
SyscallFailsWithErrno(EINVAL));
}
TEST_P(TCPSocketPairTest, SetOOBInline) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());