diff options
author | Bhasker Hariharan <bhaskerh@google.com> | 2021-02-09 21:52:50 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-02-09 21:55:16 -0800 |
commit | 298c129cc151e197db35a927f9676cc40ec80d5c (patch) | |
tree | ab9ef4a5992e53a5020522018b1ea48b8a86bcbf /test | |
parent | 2de36e44ed753c4cef2f9d71499fad6d87cb8b86 (diff) |
Add support for setting SO_SNDBUF for unix domain sockets.
The limits for snd/rcv buffers for unix domain socket is controlled by the
following sysctls on linux
- net.core.rmem_default
- net.core.rmem_max
- net.core.wmem_default
- net.core.wmem_max
Today in gVisor we do not expose these sysctls but we do support setting the
equivalent in netstack via stack.Options() method. But AF_UNIX sockets in gVisor
can be used without netstack, with hostinet or even without any networking stack
at all. Which means ideally these sysctls need to live as globals in gVisor.
But rather than make this a big change for now we hardcode the limits in the
AF_UNIX implementation itself (which in itself is better than where we were
before) where it SO_SNDBUF was hardcoded to 16KiB. Further we bump the initial
limit to a default value of 208 KiB to match linux from the paltry 16 KiB we use
today.
Updates #5132
PiperOrigin-RevId: 356665498
Diffstat (limited to 'test')
-rw-r--r-- | test/syscalls/linux/BUILD | 3 | ||||
-rw-r--r-- | test/syscalls/linux/socket_generic.cc | 2 | ||||
-rw-r--r-- | test/syscalls/linux/socket_unix_dgram.cc | 35 | ||||
-rw-r--r-- | test/syscalls/linux/socket_unix_seqpacket.cc | 35 | ||||
-rw-r--r-- | test/syscalls/linux/socket_unix_stream.cc | 80 |
5 files changed, 154 insertions, 1 deletions
diff --git a/test/syscalls/linux/BUILD b/test/syscalls/linux/BUILD index 499027e7c..42fc363a2 100644 --- a/test/syscalls/linux/BUILD +++ b/test/syscalls/linux/BUILD @@ -2346,6 +2346,7 @@ cc_library( deps = [ ":socket_test_util", ":unix_domain_socket_test_util", + "@com_google_absl//absl/time", gtest, "//test/util:test_util", ], @@ -2360,6 +2361,7 @@ cc_library( deps = [ ":socket_test_util", ":unix_domain_socket_test_util", + "@com_google_absl//absl/time", gtest, "//test/util:test_util", ], @@ -2678,6 +2680,7 @@ cc_binary( deps = [ ":socket_test_util", ":unix_domain_socket_test_util", + "@com_google_absl//absl/time", gtest, "//test/util:test_main", "//test/util:test_util", diff --git a/test/syscalls/linux/socket_generic.cc b/test/syscalls/linux/socket_generic.cc index de0b8bb11..f70047a09 100644 --- a/test/syscalls/linux/socket_generic.cc +++ b/test/syscalls/linux/socket_generic.cc @@ -379,7 +379,7 @@ TEST_P(AllSocketPairTest, RcvBufSucceeds) { EXPECT_GT(size, 0); } -TEST_P(AllSocketPairTest, SndBufSucceeds) { +TEST_P(AllSocketPairTest, GetSndBufSucceeds) { auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); int size = 0; socklen_t size_size = sizeof(size); diff --git a/test/syscalls/linux/socket_unix_dgram.cc b/test/syscalls/linux/socket_unix_dgram.cc index af0df4fb4..5b0844493 100644 --- a/test/syscalls/linux/socket_unix_dgram.cc +++ b/test/syscalls/linux/socket_unix_dgram.cc @@ -18,6 +18,8 @@ #include <sys/un.h> #include "gtest/gtest.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" #include "test/syscalls/linux/socket_test_util.h" #include "test/syscalls/linux/unix_domain_socket_test_util.h" #include "test/util/test_util.h" @@ -39,6 +41,39 @@ TEST_P(DgramUnixSocketPairTest, WriteOneSideClosed) { SyscallFailsWithErrno(ECONNREFUSED)); } +TEST_P(DgramUnixSocketPairTest, IncreasedSocketSendBufUnblocksWrites) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + int sock = sockets->first_fd(); + int buf_size = 0; + socklen_t buf_size_len = sizeof(buf_size); + ASSERT_THAT(getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, &buf_size_len), + SyscallSucceeds()); + int opts; + ASSERT_THAT(opts = fcntl(sock, F_GETFL), SyscallSucceeds()); + opts |= O_NONBLOCK; + ASSERT_THAT(fcntl(sock, F_SETFL, opts), SyscallSucceeds()); + + std::vector<char> buf(buf_size / 4); + // Write till the socket buffer is full. + while (RetryEINTR(send)(sock, buf.data(), buf.size(), 0) != -1) { + // Sleep to give linux a chance to move data from the send buffer to the + // receive buffer. + absl::SleepFor(absl::Milliseconds(10)); // 10ms. + } + // The last error should have been EWOULDBLOCK. + ASSERT_EQ(errno, EWOULDBLOCK); + + // Now increase the socket send buffer. + buf_size = buf_size * 2; + ASSERT_THAT( + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)), + SyscallSucceeds()); + + // The send should succeed again. + ASSERT_THAT(RetryEINTR(send)(sock, buf.data(), buf.size(), 0), + SyscallSucceeds()); +} + } // namespace } // namespace testing diff --git a/test/syscalls/linux/socket_unix_seqpacket.cc b/test/syscalls/linux/socket_unix_seqpacket.cc index 6d03df4d9..eb373373d 100644 --- a/test/syscalls/linux/socket_unix_seqpacket.cc +++ b/test/syscalls/linux/socket_unix_seqpacket.cc @@ -18,6 +18,8 @@ #include <sys/un.h> #include "gtest/gtest.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" #include "test/syscalls/linux/socket_test_util.h" #include "test/syscalls/linux/unix_domain_socket_test_util.h" #include "test/util/test_util.h" @@ -61,6 +63,39 @@ TEST_P(SeqpacketUnixSocketPairTest, Sendto) { SyscallSucceedsWithValue(3)); } +TEST_P(SeqpacketUnixSocketPairTest, IncreasedSocketSendBufUnblocksWrites) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + int sock = sockets->first_fd(); + int buf_size = 0; + socklen_t buf_size_len = sizeof(buf_size); + ASSERT_THAT(getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, &buf_size_len), + SyscallSucceeds()); + int opts; + ASSERT_THAT(opts = fcntl(sock, F_GETFL), SyscallSucceeds()); + opts |= O_NONBLOCK; + ASSERT_THAT(fcntl(sock, F_SETFL, opts), SyscallSucceeds()); + + std::vector<char> buf(buf_size / 4); + // Write till the socket buffer is full. + while (RetryEINTR(send)(sock, buf.data(), buf.size(), 0) != -1) { + // Sleep to give linux a chance to move data from the send buffer to the + // receive buffer. + absl::SleepFor(absl::Milliseconds(10)); // 10ms. + } + // The last error should have been EWOULDBLOCK. + ASSERT_EQ(errno, EWOULDBLOCK); + + // Now increase the socket send buffer. + buf_size = buf_size * 2; + ASSERT_THAT( + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)), + SyscallSucceeds()); + + // The send should succeed again. + ASSERT_THAT(RetryEINTR(send)(sock, buf.data(), buf.size(), 0), + SyscallSucceeds()); +} + } // namespace } // namespace testing diff --git a/test/syscalls/linux/socket_unix_stream.cc b/test/syscalls/linux/socket_unix_stream.cc index ad9c4bf37..3ff810914 100644 --- a/test/syscalls/linux/socket_unix_stream.cc +++ b/test/syscalls/linux/socket_unix_stream.cc @@ -17,6 +17,8 @@ #include <sys/un.h> #include "gtest/gtest.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" #include "test/syscalls/linux/socket_test_util.h" #include "test/syscalls/linux/unix_domain_socket_test_util.h" #include "test/util/test_util.h" @@ -134,6 +136,84 @@ TEST_P(StreamUnixSocketPairTest, GetSocketAcceptConn) { EXPECT_EQ(got, 0); } +TEST_P(StreamUnixSocketPairTest, SetSocketSendBuf) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + auto s = sockets->first_fd(); + int max = 0; + int min = 0; + { + // Discover maxmimum buffer size by setting to a really large value. + constexpr int kRcvBufSz = INT_MAX; + ASSERT_THAT( + setsockopt(s, SOL_SOCKET, SO_SNDBUF, &kRcvBufSz, sizeof(kRcvBufSz)), + SyscallSucceeds()); + + max = 0; + socklen_t max_len = sizeof(max); + ASSERT_THAT(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &max, &max_len), + SyscallSucceeds()); + } + + { + // Discover minimum buffer size by setting it to zero. + constexpr int kRcvBufSz = 0; + ASSERT_THAT( + setsockopt(s, SOL_SOCKET, SO_SNDBUF, &kRcvBufSz, sizeof(kRcvBufSz)), + SyscallSucceeds()); + + socklen_t min_len = sizeof(min); + ASSERT_THAT(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &min, &min_len), + SyscallSucceeds()); + } + + int quarter_sz = min + (max - min) / 4; + ASSERT_THAT( + setsockopt(s, SOL_SOCKET, SO_SNDBUF, &quarter_sz, sizeof(quarter_sz)), + SyscallSucceeds()); + + int val = 0; + socklen_t val_len = sizeof(val); + ASSERT_THAT(getsockopt(s, SOL_SOCKET, SO_SNDBUF, &val, &val_len), + SyscallSucceeds()); + + // Linux doubles the value set by SO_SNDBUF/SO_SNDBUF. + quarter_sz *= 2; + ASSERT_EQ(quarter_sz, val); +} + +TEST_P(StreamUnixSocketPairTest, IncreasedSocketSendBufUnblocksWrites) { + auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair()); + int sock = sockets->first_fd(); + int buf_size = 0; + socklen_t buf_size_len = sizeof(buf_size); + ASSERT_THAT(getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, &buf_size_len), + SyscallSucceeds()); + int opts; + ASSERT_THAT(opts = fcntl(sock, F_GETFL), SyscallSucceeds()); + opts |= O_NONBLOCK; + ASSERT_THAT(fcntl(sock, F_SETFL, opts), SyscallSucceeds()); + + std::vector<char> buf(buf_size / 4); + // Write till the socket buffer is full. + while (RetryEINTR(send)(sock, buf.data(), buf.size(), 0) != -1) { + // Sleep to give linux a chance to move data from the send buffer to the + // receive buffer. + absl::SleepFor(absl::Milliseconds(10)); // 10ms. + } + // The last error should have been EWOULDBLOCK. + ASSERT_EQ(errno, EWOULDBLOCK); + + // Now increase the socket send buffer. + buf_size = buf_size * 2; + ASSERT_THAT( + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &buf_size, sizeof(buf_size)), + SyscallSucceeds()); + + // The send should succeed again. + ASSERT_THAT(RetryEINTR(send)(sock, buf.data(), buf.size(), 0), + SyscallSucceeds()); +} + INSTANTIATE_TEST_SUITE_P( AllUnixDomainSockets, StreamUnixSocketPairTest, ::testing::ValuesIn(IncludeReversals(VecCat<SocketPairKind>( |