github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/syscalls/linux/proc_net.cc (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <arpa/inet.h> 16 #include <errno.h> 17 #include <netinet/in.h> 18 #include <poll.h> 19 #include <sys/socket.h> 20 #include <sys/syscall.h> 21 #include <sys/types.h> 22 23 #include <vector> 24 25 #include "gtest/gtest.h" 26 #include "absl/strings/numbers.h" 27 #include "absl/strings/str_cat.h" 28 #include "absl/strings/str_split.h" 29 #include "absl/strings/string_view.h" 30 #include "absl/time/clock.h" 31 #include "test/syscalls/linux/socket_test_util.h" 32 #include "test/util/capability_util.h" 33 #include "test/util/file_descriptor.h" 34 #include "test/util/fs_util.h" 35 #include "test/util/test_util.h" 36 37 namespace gvisor { 38 namespace testing { 39 namespace { 40 41 constexpr const char kProcNet[] = "/proc/net"; 42 constexpr const char kIpForward[] = "/proc/sys/net/ipv4/ip_forward"; 43 constexpr const char kRangeFile[] = "/proc/sys/net/ipv4/ip_local_port_range"; 44 45 TEST(ProcNetSymlinkTarget, FileMode) { 46 struct stat s; 47 ASSERT_THAT(stat(kProcNet, &s), SyscallSucceeds()); 48 EXPECT_EQ(s.st_mode & S_IFMT, S_IFDIR); 49 EXPECT_EQ(s.st_mode & 0777, 0555); 50 } 51 52 TEST(ProcNetSymlink, FileMode) { 53 struct stat s; 54 ASSERT_THAT(lstat(kProcNet, &s), SyscallSucceeds()); 55 EXPECT_EQ(s.st_mode & S_IFMT, S_IFLNK); 56 EXPECT_EQ(s.st_mode & 0777, 0777); 57 } 58 59 TEST(ProcNetSymlink, Contents) { 60 char buf[40] = {}; 61 int n = readlink(kProcNet, buf, sizeof(buf)); 62 ASSERT_THAT(n, SyscallSucceeds()); 63 64 buf[n] = 0; 65 EXPECT_STREQ(buf, "self/net"); 66 } 67 68 TEST(ProcNetIfInet6, Format) { 69 auto ifinet6 = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/if_inet6")); 70 EXPECT_THAT(ifinet6, 71 ::testing::MatchesRegex( 72 // Ex: "00000000000000000000000000000001 01 80 10 80 lo\n" 73 "^([a-f0-9]{32}( [a-f0-9]{2}){4} +[a-z][a-z0-9]*\n)+$")); 74 } 75 76 TEST(ProcSysNetIpv4Sack, Exists) { 77 EXPECT_THAT(open("/proc/sys/net/ipv4/tcp_sack", O_RDONLY), SyscallSucceeds()); 78 } 79 80 TEST(ProcSysNetIpv4Sack, CanReadAndWrite) { 81 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability((CAP_DAC_OVERRIDE)))); 82 83 auto const fd = 84 ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/sys/net/ipv4/tcp_sack", O_RDWR)); 85 86 char buf; 87 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(buf), 0), 88 SyscallSucceedsWithValue(sizeof(buf))); 89 90 EXPECT_TRUE(buf == '0' || buf == '1') << "unexpected tcp_sack: " << buf; 91 92 char to_write = (buf == '1') ? '0' : '1'; 93 EXPECT_THAT(PwriteFd(fd.get(), &to_write, sizeof(to_write), 0), 94 SyscallSucceedsWithValue(sizeof(to_write))); 95 96 buf = 0; 97 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(buf), 0), 98 SyscallSucceedsWithValue(sizeof(buf))); 99 EXPECT_EQ(buf, to_write); 100 } 101 102 // DeviceEntry is an entry in /proc/net/dev 103 struct DeviceEntry { 104 std::string name; 105 uint64_t stats[16]; 106 }; 107 108 PosixErrorOr<std::vector<DeviceEntry>> GetDeviceMetricsFromProc( 109 const std::string dev) { 110 std::vector<std::string> lines = absl::StrSplit(dev, '\n'); 111 std::vector<DeviceEntry> entries; 112 113 // /proc/net/dev prints 2 lines of headers followed by a line of metrics for 114 // each network interface. 115 for (unsigned i = 2; i < lines.size(); i++) { 116 // Ignore empty lines. 117 if (lines[i].empty()) { 118 continue; 119 } 120 121 std::vector<std::string> values = 122 absl::StrSplit(lines[i], ' ', absl::SkipWhitespace()); 123 124 // Interface name + 16 values. 125 if (values.size() != 17) { 126 return PosixError(EINVAL, "invalid line: " + lines[i]); 127 } 128 129 DeviceEntry entry; 130 entry.name = values[0]; 131 // Skip the interface name and read only the values. 132 for (unsigned j = 1; j < 17; j++) { 133 uint64_t num; 134 if (!absl::SimpleAtoi(values[j], &num)) { 135 return PosixError(EINVAL, "invalid value: " + values[j]); 136 } 137 entry.stats[j - 1] = num; 138 } 139 140 entries.push_back(entry); 141 } 142 143 return entries; 144 } 145 146 // TEST(ProcNetDev, Format) tests that /proc/net/dev is parsable and 147 // contains at least one entry. 148 TEST(ProcNetDev, Format) { 149 auto dev = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/dev")); 150 auto entries = ASSERT_NO_ERRNO_AND_VALUE(GetDeviceMetricsFromProc(dev)); 151 152 EXPECT_GT(entries.size(), 0); 153 } 154 155 PosixErrorOr<uint64_t> GetSNMPMetricFromProc(const std::string snmp, 156 const std::string& type, 157 const std::string& item) { 158 std::vector<std::string> snmp_vec = absl::StrSplit(snmp, '\n'); 159 160 // /proc/net/snmp prints a line of headers followed by a line of metrics. 161 // Only search the headers. 162 for (unsigned i = 0; i < snmp_vec.size(); i = i + 2) { 163 if (!absl::StartsWith(snmp_vec[i], type)) continue; 164 165 std::vector<std::string> fields = 166 absl::StrSplit(snmp_vec[i], ' ', absl::SkipWhitespace()); 167 168 EXPECT_TRUE((i + 1) < snmp_vec.size()); 169 std::vector<std::string> values = 170 absl::StrSplit(snmp_vec[i + 1], ' ', absl::SkipWhitespace()); 171 172 EXPECT_TRUE(!fields.empty() && fields.size() == values.size()); 173 174 // Metrics start at the first index. 175 for (unsigned j = 1; j < fields.size(); j++) { 176 if (fields[j] == item) { 177 uint64_t val; 178 if (!absl::SimpleAtoi(values[j], &val)) { 179 return PosixError(EINVAL, 180 absl::StrCat("field is not a number: ", values[j])); 181 } 182 183 return val; 184 } 185 } 186 } 187 // We should never get here. 188 return PosixError( 189 EINVAL, absl::StrCat("failed to find ", type, "/", item, " in:", snmp)); 190 } 191 192 TEST(ProcNetSnmp, TcpReset) { 193 // TODO(gvisor.dev/issue/866): epsocket metrics are not savable. 194 DisableSave ds; 195 196 uint64_t oldAttemptFails; 197 uint64_t oldActiveOpens; 198 uint64_t oldOutRsts; 199 auto snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 200 oldActiveOpens = ASSERT_NO_ERRNO_AND_VALUE( 201 GetSNMPMetricFromProc(snmp, "Tcp", "ActiveOpens")); 202 oldOutRsts = 203 ASSERT_NO_ERRNO_AND_VALUE(GetSNMPMetricFromProc(snmp, "Tcp", "OutRsts")); 204 oldAttemptFails = ASSERT_NO_ERRNO_AND_VALUE( 205 GetSNMPMetricFromProc(snmp, "Tcp", "AttemptFails")); 206 207 FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, 0)); 208 209 struct sockaddr_in sin = { 210 .sin_family = AF_INET, 211 .sin_port = htons(1234), 212 }; 213 214 ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &(sin.sin_addr)), 1); 215 ASSERT_THAT(connect(s.get(), (struct sockaddr*)&sin, sizeof(sin)), 216 SyscallFailsWithErrno(ECONNREFUSED)); 217 218 uint64_t newAttemptFails; 219 uint64_t newActiveOpens; 220 uint64_t newOutRsts; 221 snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 222 newActiveOpens = ASSERT_NO_ERRNO_AND_VALUE( 223 GetSNMPMetricFromProc(snmp, "Tcp", "ActiveOpens")); 224 newOutRsts = 225 ASSERT_NO_ERRNO_AND_VALUE(GetSNMPMetricFromProc(snmp, "Tcp", "OutRsts")); 226 newAttemptFails = ASSERT_NO_ERRNO_AND_VALUE( 227 GetSNMPMetricFromProc(snmp, "Tcp", "AttemptFails")); 228 229 EXPECT_EQ(oldActiveOpens, newActiveOpens - 1); 230 EXPECT_EQ(oldOutRsts, newOutRsts - 1); 231 EXPECT_EQ(oldAttemptFails, newAttemptFails - 1); 232 } 233 234 TEST(ProcNetSnmp, TcpEstab) { 235 // TODO(gvisor.dev/issue/866): epsocket metrics are not savable. 236 DisableSave ds; 237 238 uint64_t oldEstabResets; 239 uint64_t oldActiveOpens; 240 uint64_t oldPassiveOpens; 241 uint64_t oldCurrEstab; 242 auto snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 243 oldActiveOpens = ASSERT_NO_ERRNO_AND_VALUE( 244 GetSNMPMetricFromProc(snmp, "Tcp", "ActiveOpens")); 245 oldPassiveOpens = ASSERT_NO_ERRNO_AND_VALUE( 246 GetSNMPMetricFromProc(snmp, "Tcp", "PassiveOpens")); 247 oldCurrEstab = ASSERT_NO_ERRNO_AND_VALUE( 248 GetSNMPMetricFromProc(snmp, "Tcp", "CurrEstab")); 249 oldEstabResets = ASSERT_NO_ERRNO_AND_VALUE( 250 GetSNMPMetricFromProc(snmp, "Tcp", "EstabResets")); 251 252 FileDescriptor s_listen = 253 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, 0)); 254 struct sockaddr_in sin = { 255 .sin_family = AF_INET, 256 .sin_port = 0, 257 }; 258 259 ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &(sin.sin_addr)), 1); 260 ASSERT_THAT(bind(s_listen.get(), (struct sockaddr*)&sin, sizeof(sin)), 261 SyscallSucceeds()); 262 ASSERT_THAT(listen(s_listen.get(), 1), SyscallSucceeds()); 263 264 // Get the port bound by the listening socket. 265 socklen_t addrlen = sizeof(sin); 266 ASSERT_THAT(getsockname(s_listen.get(), AsSockAddr(&sin), &addrlen), 267 SyscallSucceeds()); 268 269 FileDescriptor s_connect = 270 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, 0)); 271 ASSERT_THAT(connect(s_connect.get(), (struct sockaddr*)&sin, sizeof(sin)), 272 SyscallSucceeds()); 273 274 auto s_accept = 275 ASSERT_NO_ERRNO_AND_VALUE(Accept(s_listen.get(), nullptr, nullptr)); 276 277 uint64_t newEstabResets; 278 uint64_t newActiveOpens; 279 uint64_t newPassiveOpens; 280 uint64_t newCurrEstab; 281 snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 282 newActiveOpens = ASSERT_NO_ERRNO_AND_VALUE( 283 GetSNMPMetricFromProc(snmp, "Tcp", "ActiveOpens")); 284 newPassiveOpens = ASSERT_NO_ERRNO_AND_VALUE( 285 GetSNMPMetricFromProc(snmp, "Tcp", "PassiveOpens")); 286 newCurrEstab = ASSERT_NO_ERRNO_AND_VALUE( 287 GetSNMPMetricFromProc(snmp, "Tcp", "CurrEstab")); 288 289 EXPECT_EQ(oldActiveOpens, newActiveOpens - 1); 290 EXPECT_EQ(oldPassiveOpens, newPassiveOpens - 1); 291 EXPECT_EQ(oldCurrEstab, newCurrEstab - 2); 292 293 // Send 1 byte from client to server. 294 ASSERT_THAT(send(s_connect.get(), "a", 1, 0), SyscallSucceedsWithValue(1)); 295 296 constexpr int kPollTimeoutMs = 20000; // Wait up to 20 seconds for the data. 297 298 // Wait until server-side fd sees the data on its side but don't read it. 299 struct pollfd poll_fd = {s_accept.get(), POLLIN, 0}; 300 ASSERT_THAT(RetryEINTR(poll)(&poll_fd, 1, kPollTimeoutMs), 301 SyscallSucceedsWithValue(1)); 302 303 // Now close server-side fd without reading the data which leads to a RST 304 // packet sent to client side. 305 s_accept.reset(-1); 306 307 // Wait until client-side fd sees RST packet. 308 struct pollfd poll_fd1 = {s_connect.get(), POLLIN, 0}; 309 ASSERT_THAT(RetryEINTR(poll)(&poll_fd1, 1, kPollTimeoutMs), 310 SyscallSucceedsWithValue(1)); 311 312 // Now close client-side fd. 313 s_connect.reset(-1); 314 315 // Wait until the process of the netstack. 316 absl::SleepFor(absl::Seconds(1)); 317 318 snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 319 newCurrEstab = ASSERT_NO_ERRNO_AND_VALUE( 320 GetSNMPMetricFromProc(snmp, "Tcp", "CurrEstab")); 321 newEstabResets = ASSERT_NO_ERRNO_AND_VALUE( 322 GetSNMPMetricFromProc(snmp, "Tcp", "EstabResets")); 323 324 EXPECT_EQ(oldCurrEstab, newCurrEstab); 325 EXPECT_EQ(oldEstabResets, newEstabResets - 2); 326 } 327 328 TEST(ProcNetSnmp, UdpNoPorts) { 329 // TODO(gvisor.dev/issue/866): epsocket metrics are not savable. 330 DisableSave ds; 331 332 uint64_t oldOutDatagrams; 333 uint64_t oldNoPorts; 334 auto snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 335 oldOutDatagrams = ASSERT_NO_ERRNO_AND_VALUE( 336 GetSNMPMetricFromProc(snmp, "Udp", "OutDatagrams")); 337 oldNoPorts = 338 ASSERT_NO_ERRNO_AND_VALUE(GetSNMPMetricFromProc(snmp, "Udp", "NoPorts")); 339 340 FileDescriptor s = ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 341 342 struct sockaddr_in sin = { 343 .sin_family = AF_INET, 344 .sin_port = htons(4444), 345 }; 346 ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &(sin.sin_addr)), 1); 347 ASSERT_THAT(sendto(s.get(), "a", 1, 0, (struct sockaddr*)&sin, sizeof(sin)), 348 SyscallSucceedsWithValue(1)); 349 350 uint64_t newOutDatagrams; 351 uint64_t newNoPorts; 352 snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 353 newOutDatagrams = ASSERT_NO_ERRNO_AND_VALUE( 354 GetSNMPMetricFromProc(snmp, "Udp", "OutDatagrams")); 355 newNoPorts = 356 ASSERT_NO_ERRNO_AND_VALUE(GetSNMPMetricFromProc(snmp, "Udp", "NoPorts")); 357 358 EXPECT_EQ(oldOutDatagrams, newOutDatagrams - 1); 359 EXPECT_EQ(oldNoPorts, newNoPorts - 1); 360 } 361 362 TEST(ProcNetSnmp, UdpIn) { 363 // TODO(gvisor.dev/issue/866): epsocket metrics are not savable. 364 const DisableSave ds; 365 366 uint64_t oldOutDatagrams; 367 uint64_t oldInDatagrams; 368 auto snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 369 oldOutDatagrams = ASSERT_NO_ERRNO_AND_VALUE( 370 GetSNMPMetricFromProc(snmp, "Udp", "OutDatagrams")); 371 oldInDatagrams = ASSERT_NO_ERRNO_AND_VALUE( 372 GetSNMPMetricFromProc(snmp, "Udp", "InDatagrams")); 373 374 std::cerr << "snmp: " << std::endl << snmp << std::endl; 375 FileDescriptor server = 376 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 377 struct sockaddr_in sin = { 378 .sin_family = AF_INET, 379 .sin_port = htons(0), 380 }; 381 ASSERT_EQ(inet_pton(AF_INET, "127.0.0.1", &(sin.sin_addr)), 1); 382 ASSERT_THAT(bind(server.get(), (struct sockaddr*)&sin, sizeof(sin)), 383 SyscallSucceeds()); 384 // Get the port bound by the server socket. 385 socklen_t addrlen = sizeof(sin); 386 ASSERT_THAT(getsockname(server.get(), AsSockAddr(&sin), &addrlen), 387 SyscallSucceeds()); 388 389 FileDescriptor client = 390 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 391 ASSERT_THAT( 392 sendto(client.get(), "a", 1, 0, (struct sockaddr*)&sin, sizeof(sin)), 393 SyscallSucceedsWithValue(1)); 394 395 char buf[128]; 396 ASSERT_THAT(recvfrom(server.get(), buf, sizeof(buf), 0, NULL, NULL), 397 SyscallSucceedsWithValue(1)); 398 399 uint64_t newOutDatagrams; 400 uint64_t newInDatagrams; 401 snmp = ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 402 std::cerr << "new snmp: " << std::endl << snmp << std::endl; 403 newOutDatagrams = ASSERT_NO_ERRNO_AND_VALUE( 404 GetSNMPMetricFromProc(snmp, "Udp", "OutDatagrams")); 405 newInDatagrams = ASSERT_NO_ERRNO_AND_VALUE( 406 GetSNMPMetricFromProc(snmp, "Udp", "InDatagrams")); 407 408 EXPECT_EQ(oldOutDatagrams, newOutDatagrams - 1); 409 EXPECT_EQ(oldInDatagrams, newInDatagrams - 1); 410 } 411 412 TEST(ProcNetSnmp, CheckNetStat) { 413 // TODO(b/155123175): SNMP and netstat don't work on gVisor. 414 SKIP_IF(IsRunningOnGvisor()); 415 416 std::string contents = 417 ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/netstat")); 418 419 int name_count = 0; 420 int value_count = 0; 421 std::vector<absl::string_view> lines = absl::StrSplit(contents, '\n'); 422 for (size_t i = 0; i + 1 < lines.size(); i += 2) { 423 std::vector<absl::string_view> names = 424 absl::StrSplit(lines[i], absl::ByAnyChar("\t ")); 425 std::vector<absl::string_view> values = 426 absl::StrSplit(lines[i + 1], absl::ByAnyChar("\t ")); 427 EXPECT_EQ(names.size(), values.size()) << " mismatch in lines '" << lines[i] 428 << "' and '" << lines[i + 1] << "'"; 429 for (size_t j = 0; j < names.size() && j < values.size(); ++j) { 430 if (names[j] == "TCPOrigDataSent" || names[j] == "TCPSynRetrans" || 431 names[j] == "TCPDSACKRecv" || names[j] == "TCPDSACKOfoRecv") { 432 ++name_count; 433 int64_t val; 434 if (absl::SimpleAtoi(values[j], &val)) { 435 ++value_count; 436 } 437 } 438 } 439 } 440 EXPECT_EQ(name_count, 4); 441 EXPECT_EQ(value_count, 4); 442 } 443 444 TEST(ProcNetSnmp, Stat) { 445 struct stat st = {}; 446 ASSERT_THAT(stat("/proc/net/snmp", &st), SyscallSucceeds()); 447 } 448 449 TEST(ProcNetSnmp, CheckSnmp) { 450 // TODO(b/155123175): SNMP and netstat don't work on gVisor. 451 SKIP_IF(IsRunningOnGvisor()); 452 453 std::string contents = 454 ASSERT_NO_ERRNO_AND_VALUE(GetContents("/proc/net/snmp")); 455 456 int name_count = 0; 457 int value_count = 0; 458 std::vector<absl::string_view> lines = absl::StrSplit(contents, '\n'); 459 for (size_t i = 0; i + 1 < lines.size(); i += 2) { 460 std::vector<absl::string_view> names = 461 absl::StrSplit(lines[i], absl::ByAnyChar("\t ")); 462 std::vector<absl::string_view> values = 463 absl::StrSplit(lines[i + 1], absl::ByAnyChar("\t ")); 464 EXPECT_EQ(names.size(), values.size()) << " mismatch in lines '" << lines[i] 465 << "' and '" << lines[i + 1] << "'"; 466 for (size_t j = 0; j < names.size() && j < values.size(); ++j) { 467 if (names[j] == "RetransSegs") { 468 ++name_count; 469 int64_t val; 470 if (absl::SimpleAtoi(values[j], &val)) { 471 ++value_count; 472 } 473 } 474 } 475 } 476 EXPECT_EQ(name_count, 1); 477 EXPECT_EQ(value_count, 1); 478 } 479 480 TEST(ProcSysNetIpv4Recovery, Exists) { 481 EXPECT_THAT(open("/proc/sys/net/ipv4/tcp_recovery", O_RDONLY), 482 SyscallSucceeds()); 483 } 484 485 TEST(ProcSysNetIpv4Recovery, CanReadAndWrite) { 486 // TODO(b/162988252): Enable save/restore for this test after the bug is 487 // fixed. 488 DisableSave ds; 489 490 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability((CAP_DAC_OVERRIDE)))); 491 492 auto const fd = ASSERT_NO_ERRNO_AND_VALUE( 493 Open("/proc/sys/net/ipv4/tcp_recovery", O_RDWR)); 494 495 char buf[10] = {'\0'}; 496 char to_write = '2'; 497 498 // Check initial value is set to 1. 499 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(buf), 0), 500 SyscallSucceedsWithValue(sizeof(to_write) + 1)); 501 if (IsRunningOnGvisor()) { 502 // TODO(gvisor.dev/issue/5243): TCPRACKLossDetection = 1 should be turned on 503 // by default. 504 EXPECT_EQ(strcmp(buf, "0\n"), 0); 505 } else { 506 EXPECT_EQ(strcmp(buf, "1\n"), 0); 507 } 508 509 // Set tcp_recovery to one of the allowed constants. 510 EXPECT_THAT(PwriteFd(fd.get(), &to_write, sizeof(to_write), 0), 511 SyscallSucceedsWithValue(sizeof(to_write))); 512 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(buf), 0), 513 SyscallSucceedsWithValue(sizeof(to_write) + 1)); 514 EXPECT_EQ(strcmp(buf, "2\n"), 0); 515 516 // Set tcp_recovery to any random value. 517 char kMessage[] = "100"; 518 EXPECT_THAT(PwriteFd(fd.get(), kMessage, strlen(kMessage), 0), 519 SyscallSucceedsWithValue(strlen(kMessage))); 520 EXPECT_THAT(PreadFd(fd.get(), buf, sizeof(kMessage), 0), 521 SyscallSucceedsWithValue(sizeof(kMessage))); 522 EXPECT_EQ(strcmp(buf, "100\n"), 0); 523 } 524 525 TEST(ProcSysNetIpv4IpForward, Exists) { 526 auto fd = ASSERT_NO_ERRNO_AND_VALUE(Open(kIpForward, O_RDONLY)); 527 } 528 529 TEST(ProcSysNetIpv4IpForward, DefaultValueEqZero) { 530 // Test is only valid in sandbox. Not hermetic in native tests 531 // running on a arbitrary machine. 532 SKIP_IF(!IsRunningOnGvisor()); 533 auto const fd = ASSERT_NO_ERRNO_AND_VALUE(Open(kIpForward, O_RDONLY)); 534 535 char buf = 101; 536 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(buf), 0), 537 SyscallSucceedsWithValue(sizeof(buf))); 538 539 EXPECT_EQ(buf, '0') << "unexpected ip_forward: " << buf; 540 } 541 542 TEST(ProcSysNetIpv4IpForward, CanReadAndWrite) { 543 SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability((CAP_DAC_OVERRIDE)))); 544 545 auto const fd = ASSERT_NO_ERRNO_AND_VALUE(Open(kIpForward, O_RDWR)); 546 547 char buf; 548 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(buf), 0), 549 SyscallSucceedsWithValue(sizeof(buf))); 550 551 EXPECT_TRUE(buf == '0' || buf == '1') << "unexpected ip_forward: " << buf; 552 553 // constexpr char to_write = '1'; 554 char to_write = (buf == '1') ? '0' : '1'; 555 EXPECT_THAT(PwriteFd(fd.get(), &to_write, sizeof(to_write), 0), 556 SyscallSucceedsWithValue(sizeof(to_write))); 557 558 buf = 0; 559 EXPECT_THAT(PreadFd(fd.get(), &buf, sizeof(buf), 0), 560 SyscallSucceedsWithValue(sizeof(buf))); 561 EXPECT_EQ(buf, to_write); 562 } 563 564 TEST(ProcSysNetPortRange, CanReadAndWrite) { 565 int min; 566 int max; 567 std::string rangefile = ASSERT_NO_ERRNO_AND_VALUE(GetContents(kRangeFile)); 568 ASSERT_EQ(rangefile.back(), '\n'); 569 rangefile.pop_back(); 570 std::vector<std::string> range = 571 absl::StrSplit(rangefile, absl::ByAnyChar("\t ")); 572 ASSERT_GT(range.size(), 1); 573 ASSERT_TRUE(absl::SimpleAtoi(range.front(), &min)); 574 ASSERT_TRUE(absl::SimpleAtoi(range.back(), &max)); 575 EXPECT_LE(min, max); 576 577 // If the file isn't writable, there's nothing else to do here. 578 if (access(kRangeFile, W_OK)) { 579 return; 580 } 581 582 constexpr int kSize = 77; 583 FileDescriptor fd = 584 ASSERT_NO_ERRNO_AND_VALUE(Open(kRangeFile, O_WRONLY | O_TRUNC, 0)); 585 max = min + kSize; 586 const std::string small_range = absl::StrFormat("%d %d", min, max); 587 ASSERT_THAT(write(fd.get(), small_range.c_str(), small_range.size()), 588 SyscallSucceedsWithValue(small_range.size())); 589 590 rangefile = ASSERT_NO_ERRNO_AND_VALUE(GetContents(kRangeFile)); 591 ASSERT_EQ(rangefile.back(), '\n'); 592 rangefile.pop_back(); 593 range = absl::StrSplit(rangefile, absl::ByAnyChar("\t ")); 594 ASSERT_GT(range.size(), 1); 595 ASSERT_TRUE(absl::SimpleAtoi(range.front(), &min)); 596 ASSERT_TRUE(absl::SimpleAtoi(range.back(), &max)); 597 EXPECT_EQ(min + kSize, max); 598 } 599 600 } // namespace 601 } // namespace testing 602 } // namespace gvisor