gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/ping_socket.cc (about) 1 // Copyright 2020 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 <errno.h> 16 #include <netinet/icmp6.h> 17 #include <netinet/in.h> 18 #include <netinet/ip.h> 19 #include <netinet/ip_icmp.h> 20 #include <sys/socket.h> 21 #include <sys/types.h> 22 #include <unistd.h> 23 24 #include <cctype> 25 #include <cstring> 26 #include <vector> 27 28 #include "gtest/gtest.h" 29 #include "absl/algorithm/container.h" 30 #include "absl/strings/str_join.h" 31 #include "absl/types/optional.h" 32 #include "test/syscalls/linux/ip_socket_test_util.h" 33 #include "test/util/file_descriptor.h" 34 #include "test/util/socket_util.h" 35 #include "test/util/test_util.h" 36 37 // Note: These tests require /proc/sys/net/ipv4/ping_group_range to be 38 // configured to allow the tester to create ping sockets (see icmp(7)). 39 40 namespace gvisor { 41 namespace testing { 42 namespace { 43 44 // Test ICMP port exhaustion returns EAGAIN. 45 // 46 // We disable both random/cooperative S/R for this test as it makes way too many 47 // syscalls. 48 TEST(PingSocket, ICMPPortExhaustion) { 49 DisableSave ds; 50 51 { 52 auto s = Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 53 if (!s.ok()) { 54 ASSERT_EQ(s.error().errno_value(), EACCES); 55 GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow " 56 "creation of ICMP or ICMPv6 sockets"; 57 } 58 } 59 60 const struct sockaddr_in addr = { 61 .sin_family = AF_INET, 62 .sin_addr = 63 { 64 .s_addr = htonl(INADDR_LOOPBACK), 65 }, 66 }; 67 68 std::vector<FileDescriptor> sockets; 69 constexpr int kSockets = 65536; 70 for (int i = 0; i < kSockets; i++) { 71 auto s = 72 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP)); 73 int ret = connect(s.get(), reinterpret_cast<const struct sockaddr*>(&addr), 74 sizeof(addr)); 75 if (ret == 0) { 76 sockets.push_back(std::move(s)); 77 continue; 78 } 79 ASSERT_THAT(ret, SyscallFailsWithErrno(EAGAIN)); 80 break; 81 } 82 } 83 84 TEST(PingSocket, PayloadTooLarge) { 85 PosixErrorOr<FileDescriptor> result = 86 Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 87 if (!result.ok()) { 88 int errno_value = result.error().errno_value(); 89 ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); 90 GTEST_SKIP() << "ping socket not supported"; 91 } 92 FileDescriptor& ping = result.ValueOrDie(); 93 94 constexpr icmphdr kSendIcmp = { 95 .type = ICMP_ECHO, 96 }; 97 constexpr size_t kGiantSize = 1 << 21; // 2MB. 98 const sockaddr_in kAddr = { 99 .sin_family = AF_INET, 100 .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)}, 101 }; 102 ASSERT_THAT(sendto(ping.get(), &kSendIcmp, kGiantSize, 0, 103 reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)), 104 SyscallFailsWithErrno(EMSGSIZE)); 105 } 106 107 TEST(PingSocket, ReceiveTOS) { 108 PosixErrorOr<FileDescriptor> result = 109 Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 110 if (!result.ok()) { 111 int errno_value = result.error().errno_value(); 112 ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); 113 GTEST_SKIP() << "ping socket not supported"; 114 } 115 FileDescriptor& ping = result.ValueOrDie(); 116 117 const sockaddr_in kAddr = { 118 .sin_family = AF_INET, 119 .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)}, 120 }; 121 ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr), 122 sizeof(kAddr)), 123 SyscallSucceeds()); 124 125 constexpr int kArbitraryTOS = 42; 126 ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IP, IP_TOS, &kArbitraryTOS, 127 sizeof(kArbitraryTOS)), 128 SyscallSucceeds()); 129 130 constexpr icmphdr kSendIcmp = { 131 .type = ICMP_ECHO, 132 }; 133 ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0, 134 reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)), 135 SyscallSucceedsWithValue(sizeof(kSendIcmp))); 136 137 // Register to receive TOS. 138 ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IP, IP_RECVTOS, &kSockOptOn, 139 sizeof(kSockOptOn)), 140 SyscallSucceeds()); 141 142 icmphdr recv_buf; 143 size_t recv_buf_len = sizeof(recv_buf); 144 uint8_t received_tos; 145 ASSERT_NO_FATAL_FAILURE(RecvTOS(ping.get(), 146 reinterpret_cast<char*>(&recv_buf), 147 &recv_buf_len, &received_tos)); 148 ASSERT_EQ(recv_buf_len, sizeof(kSendIcmp)); 149 150 EXPECT_EQ(recv_buf.type, ICMP_ECHOREPLY); 151 EXPECT_EQ(recv_buf.code, 0); 152 153 EXPECT_EQ(received_tos, kArbitraryTOS); 154 } 155 156 TEST(PingSocket, ReceiveTClass) { 157 PosixErrorOr<FileDescriptor> result = 158 Socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); 159 if (!result.ok()) { 160 int errno_value = result.error().errno_value(); 161 ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); 162 GTEST_SKIP() << "ping socket not supported"; 163 } 164 FileDescriptor& ping = result.ValueOrDie(); 165 166 const sockaddr_in6 kAddr = { 167 .sin6_family = AF_INET6, 168 .sin6_addr = in6addr_loopback, 169 }; 170 ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr), 171 sizeof(kAddr)), 172 SyscallSucceeds()); 173 174 constexpr int kArbitraryTClass = 42; 175 ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_TCLASS, 176 &kArbitraryTClass, sizeof(kArbitraryTClass)), 177 SyscallSucceeds()); 178 179 constexpr icmp6_hdr kSendIcmp = { 180 .icmp6_type = ICMP6_ECHO_REQUEST, 181 }; 182 ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0, 183 reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)), 184 SyscallSucceedsWithValue(sizeof(kSendIcmp))); 185 186 // Register to receive TCLASS. 187 ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_RECVTCLASS, &kSockOptOn, 188 sizeof(kSockOptOn)), 189 SyscallSucceeds()); 190 191 struct { 192 icmp6_hdr icmpv6; 193 194 // Add an extra byte to confirm we did not read unexpected bytes. 195 char unused; 196 } ABSL_ATTRIBUTE_PACKED recv_buf; 197 size_t recv_buf_len = sizeof(recv_buf); 198 int received_tclass; 199 ASSERT_NO_FATAL_FAILURE(RecvTClass(ping.get(), 200 reinterpret_cast<char*>(&recv_buf), 201 &recv_buf_len, &received_tclass)); 202 ASSERT_EQ(recv_buf_len, sizeof(kSendIcmp)); 203 204 EXPECT_EQ(recv_buf.icmpv6.icmp6_type, ICMP6_ECHO_REPLY); 205 EXPECT_EQ(recv_buf.icmpv6.icmp6_code, 0); 206 207 EXPECT_EQ(received_tclass, kArbitraryTClass); 208 } 209 210 TEST(PingSocket, ReceiveTTL) { 211 PosixErrorOr<FileDescriptor> result = 212 Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 213 if (!result.ok()) { 214 int errno_value = result.error().errno_value(); 215 ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); 216 GTEST_SKIP() << "ping socket not supported"; 217 } 218 FileDescriptor& ping = result.ValueOrDie(); 219 220 const sockaddr_in kAddr = { 221 .sin_family = AF_INET, 222 .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)}, 223 }; 224 ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr), 225 sizeof(kAddr)), 226 SyscallSucceeds()); 227 228 constexpr icmphdr kSendIcmp = { 229 .type = ICMP_ECHO, 230 }; 231 ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0, 232 reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)), 233 SyscallSucceedsWithValue(sizeof(kSendIcmp))); 234 235 // Register to receive TTL. 236 constexpr int kOne = 1; 237 ASSERT_THAT( 238 setsockopt(ping.get(), IPPROTO_IP, IP_RECVTTL, &kOne, sizeof(kOne)), 239 SyscallSucceeds()); 240 241 icmphdr recv_icmp; 242 size_t recv_len = sizeof(recv_icmp); 243 int received_ttl; 244 ASSERT_NO_FATAL_FAILURE(RecvTTL(ping.get(), 245 reinterpret_cast<char*>(&recv_icmp), 246 &recv_len, &received_ttl)); 247 ASSERT_EQ(recv_len, sizeof(kSendIcmp)); 248 249 EXPECT_EQ(recv_icmp.type, ICMP_ECHOREPLY); 250 EXPECT_EQ(recv_icmp.code, 0); 251 252 constexpr int kDefaultTTL = 64; 253 EXPECT_EQ(received_ttl, kDefaultTTL); 254 } 255 256 TEST(PingSocket, ReceiveHopLimit) { 257 PosixErrorOr<FileDescriptor> result = 258 Socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); 259 if (!result.ok()) { 260 int errno_value = result.error().errno_value(); 261 ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); 262 GTEST_SKIP() << "ping socket not supported"; 263 } 264 FileDescriptor& ping = result.ValueOrDie(); 265 266 const sockaddr_in6 kAddr = { 267 .sin6_family = AF_INET6, 268 .sin6_addr = in6addr_loopback, 269 }; 270 ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr), 271 sizeof(kAddr)), 272 SyscallSucceeds()); 273 274 constexpr icmp6_hdr kSendIcmp = { 275 .icmp6_type = ICMP6_ECHO_REQUEST, 276 }; 277 ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0, 278 reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)), 279 SyscallSucceedsWithValue(sizeof(kSendIcmp))); 280 281 // Register to receive HOPLIMIT. 282 constexpr int kOne = 1; 283 ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &kOne, 284 sizeof(kOne)), 285 SyscallSucceeds()); 286 287 icmp6_hdr recv_icmpv6; 288 size_t recv_len = sizeof(recv_icmpv6); 289 int received_hoplimit; 290 ASSERT_NO_FATAL_FAILURE(RecvHopLimit(ping.get(), 291 reinterpret_cast<char*>(&recv_icmpv6), 292 &recv_len, &received_hoplimit)); 293 ASSERT_EQ(recv_len, sizeof(kSendIcmp)); 294 295 EXPECT_EQ(recv_icmpv6.icmp6_type, ICMP6_ECHO_REPLY); 296 EXPECT_EQ(recv_icmpv6.icmp6_code, 0); 297 298 constexpr int kDefaultHopLimit = 64; 299 EXPECT_EQ(received_hoplimit, kDefaultHopLimit); 300 } 301 302 TEST(PingSocket, ReceiveIPPacketInfo) { 303 PosixErrorOr<FileDescriptor> result = 304 Socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP); 305 if (!result.ok()) { 306 int errno_value = result.error().errno_value(); 307 ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); 308 GTEST_SKIP() << "ping socket not supported"; 309 } 310 FileDescriptor& ping = result.ValueOrDie(); 311 312 const sockaddr_in kAddr = { 313 .sin_family = AF_INET, 314 .sin_addr = {.s_addr = htonl(INADDR_LOOPBACK)}, 315 }; 316 ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr), 317 sizeof(kAddr)), 318 SyscallSucceeds()); 319 320 constexpr icmphdr kSendIcmp = { 321 .type = ICMP_ECHO, 322 }; 323 ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0, 324 reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)), 325 SyscallSucceedsWithValue(sizeof(kSendIcmp))); 326 327 // Register to receive PKTINFO. 328 ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IP, IP_PKTINFO, &kSockOptOn, 329 sizeof(kSockOptOn)), 330 SyscallSucceeds()); 331 332 struct { 333 icmphdr icmp; 334 335 // Add an extra byte to confirm we did not read unexpected bytes. 336 char unused; 337 } ABSL_ATTRIBUTE_PACKED recv_buf; 338 size_t recv_buf_len = sizeof(recv_buf); 339 in_pktinfo received_pktinfo; 340 ASSERT_NO_FATAL_FAILURE(RecvPktInfo(ping.get(), 341 reinterpret_cast<char*>(&recv_buf), 342 &recv_buf_len, &received_pktinfo)); 343 ASSERT_EQ(recv_buf_len, sizeof(icmphdr)); 344 345 EXPECT_EQ(recv_buf.icmp.type, ICMP_ECHOREPLY); 346 EXPECT_EQ(recv_buf.icmp.code, 0); 347 348 EXPECT_EQ(received_pktinfo.ipi_ifindex, 349 ASSERT_NO_ERRNO_AND_VALUE(GetLoopbackIndex())); 350 EXPECT_EQ(ntohl(received_pktinfo.ipi_spec_dst.s_addr), INADDR_ANY); 351 EXPECT_EQ(ntohl(received_pktinfo.ipi_addr.s_addr), INADDR_LOOPBACK); 352 } 353 354 TEST(PingSocket, ReceiveIPv6PktInfo) { 355 PosixErrorOr<FileDescriptor> result = 356 Socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); 357 if (!result.ok()) { 358 int errno_value = result.error().errno_value(); 359 ASSERT_EQ(errno_value, EACCES) << strerror(errno_value); 360 GTEST_SKIP() << "ping socket not supported"; 361 } 362 FileDescriptor& ping = result.ValueOrDie(); 363 364 const sockaddr_in6 kAddr = { 365 .sin6_family = AF_INET6, 366 .sin6_addr = in6addr_loopback, 367 }; 368 ASSERT_THAT(bind(ping.get(), reinterpret_cast<const sockaddr*>(&kAddr), 369 sizeof(kAddr)), 370 SyscallSucceeds()); 371 372 constexpr icmp6_hdr kSendIcmp = { 373 .icmp6_type = ICMP6_ECHO_REQUEST, 374 }; 375 ASSERT_THAT(sendto(ping.get(), &kSendIcmp, sizeof(kSendIcmp), 0, 376 reinterpret_cast<const sockaddr*>(&kAddr), sizeof(kAddr)), 377 SyscallSucceedsWithValue(sizeof(kSendIcmp))); 378 379 // Register to receive PKTINFO. 380 ASSERT_THAT(setsockopt(ping.get(), IPPROTO_IPV6, IPV6_RECVPKTINFO, 381 &kSockOptOn, sizeof(kSockOptOn)), 382 SyscallSucceeds()); 383 384 struct { 385 icmp6_hdr icmpv6; 386 387 // Add an extra byte to confirm we did not read unexpected bytes. 388 char unused; 389 } ABSL_ATTRIBUTE_PACKED recv_buf; 390 size_t recv_buf_len = sizeof(recv_buf); 391 in6_pktinfo received_pktinfo; 392 ASSERT_NO_FATAL_FAILURE(RecvIPv6PktInfo(ping.get(), 393 reinterpret_cast<char*>(&recv_buf), 394 &recv_buf_len, &received_pktinfo)); 395 ASSERT_EQ(recv_buf_len, sizeof(kSendIcmp)); 396 397 EXPECT_EQ(recv_buf.icmpv6.icmp6_type, ICMP6_ECHO_REPLY); 398 EXPECT_EQ(recv_buf.icmpv6.icmp6_code, 0); 399 400 EXPECT_EQ(received_pktinfo.ipi6_ifindex, 401 ASSERT_NO_ERRNO_AND_VALUE(GetLoopbackIndex())); 402 ASSERT_EQ(memcmp(&received_pktinfo.ipi6_addr, &in6addr_loopback, 403 sizeof(in6addr_loopback)), 404 0); 405 } 406 407 struct BindTestCase { 408 TestAddress bind_to; 409 int want = 0; 410 absl::optional<int> want_gvisor; 411 }; 412 413 // Test fixture for socket binding. 414 class Fixture 415 : public ::testing::TestWithParam<std::tuple<SocketKind, BindTestCase>> {}; 416 417 TEST_P(Fixture, Bind) { 418 auto [socket_factory, test_case] = GetParam(); 419 auto socket = socket_factory.Create(); 420 if (!socket.ok()) { 421 ASSERT_EQ(socket.error().errno_value(), EACCES); 422 GTEST_SKIP() << "TODO(gvisor.dev/issue/6126): Buildkite does not allow " 423 "creation of ICMP or ICMPv6 sockets"; 424 } 425 auto socket_fd = std::move(socket).ValueOrDie(); 426 427 const int want = test_case.want_gvisor.has_value() && IsRunningOnGvisor() 428 ? *test_case.want_gvisor 429 : test_case.want; 430 if (want == 0) { 431 EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr), 432 test_case.bind_to.addr_len), 433 SyscallSucceeds()); 434 } else { 435 EXPECT_THAT(bind(socket_fd->get(), AsSockAddr(&test_case.bind_to.addr), 436 test_case.bind_to.addr_len), 437 SyscallFailsWithErrno(want)); 438 } 439 } 440 441 std::vector<std::tuple<SocketKind, BindTestCase>> ICMPTestCases() { 442 return ApplyVec<std::tuple<SocketKind, BindTestCase>>( 443 [](const BindTestCase& test_case) { 444 return std::make_tuple(ICMPUnboundSocket(0), test_case); 445 }, 446 std::vector<BindTestCase>{ 447 { 448 .bind_to = V4Any(), 449 .want = 0, 450 .want_gvisor = 0, 451 }, 452 { 453 .bind_to = V4Broadcast(), 454 .want = EADDRNOTAVAIL, 455 }, 456 { 457 .bind_to = V4Loopback(), 458 .want = 0, 459 }, 460 { 461 .bind_to = V4LoopbackSubnetBroadcast(), 462 .want = EADDRNOTAVAIL, 463 }, 464 { 465 .bind_to = V4Multicast(), 466 .want = EADDRNOTAVAIL, 467 }, 468 { 469 .bind_to = V4MulticastAllHosts(), 470 .want = EADDRNOTAVAIL, 471 }, 472 { 473 .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"), 474 .want = EADDRNOTAVAIL, 475 }, 476 { 477 .bind_to = V6Any(), 478 .want = EAFNOSUPPORT, 479 }, 480 { 481 .bind_to = V6Loopback(), 482 .want = EAFNOSUPPORT, 483 }, 484 { 485 .bind_to = V6Multicast(), 486 .want = EAFNOSUPPORT, 487 }, 488 { 489 .bind_to = V6MulticastInterfaceLocalAllNodes(), 490 .want = EAFNOSUPPORT, 491 }, 492 { 493 .bind_to = V6MulticastLinkLocalAllNodes(), 494 .want = EAFNOSUPPORT, 495 }, 496 { 497 .bind_to = V6MulticastLinkLocalAllRouters(), 498 .want = EAFNOSUPPORT, 499 }, 500 { 501 .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"), 502 .want = EAFNOSUPPORT, 503 }, 504 }); 505 } 506 507 std::vector<std::tuple<SocketKind, BindTestCase>> ICMPv6TestCases() { 508 return ApplyVec<std::tuple<SocketKind, BindTestCase>>( 509 [](const BindTestCase& test_case) { 510 return std::make_tuple(ICMPv6UnboundSocket(0), test_case); 511 }, 512 std::vector<BindTestCase>{ 513 { 514 .bind_to = V4Any(), 515 .want = EINVAL, 516 }, 517 { 518 .bind_to = V4Broadcast(), 519 .want = EINVAL, 520 }, 521 { 522 .bind_to = V4Loopback(), 523 .want = EINVAL, 524 }, 525 { 526 .bind_to = V4LoopbackSubnetBroadcast(), 527 .want = EINVAL, 528 }, 529 { 530 .bind_to = V4Multicast(), 531 .want = EINVAL, 532 }, 533 { 534 .bind_to = V4MulticastAllHosts(), 535 .want = EINVAL, 536 }, 537 { 538 .bind_to = V4AddrStr("IPv4UnknownUnicast", "192.168.1.1"), 539 .want = EINVAL, 540 }, 541 { 542 .bind_to = V6Any(), 543 .want = 0, 544 }, 545 { 546 .bind_to = V6Loopback(), 547 .want = 0, 548 }, 549 // TODO(gvisor.dev/issue/6021): Remove want_gvisor from all the 550 // multicast test cases below once ICMPv6 sockets return EINVAL when 551 // binding to IPv6 multicast addresses. 552 { 553 .bind_to = V6Multicast(), 554 .want = EINVAL, 555 .want_gvisor = EADDRNOTAVAIL, 556 }, 557 { 558 .bind_to = V6MulticastInterfaceLocalAllNodes(), 559 .want = EINVAL, 560 .want_gvisor = EADDRNOTAVAIL, 561 }, 562 { 563 .bind_to = V6MulticastLinkLocalAllNodes(), 564 .want = EINVAL, 565 .want_gvisor = EADDRNOTAVAIL, 566 }, 567 { 568 .bind_to = V6MulticastLinkLocalAllRouters(), 569 .want = EINVAL, 570 .want_gvisor = EADDRNOTAVAIL, 571 }, 572 { 573 .bind_to = V6AddrStr("IPv6UnknownUnicast", "fc00::1"), 574 .want = EADDRNOTAVAIL, 575 }, 576 }); 577 } 578 579 std::vector<std::tuple<SocketKind, BindTestCase>> AllTestCases() { 580 return VecCat<std::tuple<SocketKind, BindTestCase>>(ICMPTestCases(), 581 ICMPv6TestCases()); 582 } 583 584 std::string TestDescription( 585 const ::testing::TestParamInfo<Fixture::ParamType>& info) { 586 auto [socket_factory, test_case] = info.param; 587 std::string name = absl::StrJoin( 588 {socket_factory.description, test_case.bind_to.description}, "_"); 589 absl::c_replace_if( 590 name, [](char c) { return !std::isalnum(c); }, '_'); 591 return name; 592 } 593 594 INSTANTIATE_TEST_SUITE_P(PingSockets, Fixture, 595 ::testing::ValuesIn(AllTestCases()), TestDescription); 596 597 } // namespace 598 } // namespace testing 599 } // namespace gvisor