gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/test/syscalls/linux/socket_netdevice.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 <linux/ethtool.h> 16 #include <linux/netlink.h> 17 #include <linux/rtnetlink.h> 18 #include <linux/sockios.h> 19 #include <sys/ioctl.h> 20 #include <sys/socket.h> 21 22 #include "gtest/gtest.h" 23 #include "absl/base/internal/endian.h" 24 #include "test/syscalls/linux/socket_netlink_util.h" 25 #include "test/util/file_descriptor.h" 26 #include "test/util/socket_util.h" 27 #include "test/util/test_util.h" 28 29 // Tests for netdevice queries. 30 31 namespace gvisor { 32 namespace testing { 33 34 namespace { 35 36 using ::testing::AnyOf; 37 using ::testing::Eq; 38 39 TEST(NetdeviceTest, Loopback) { 40 FileDescriptor sock = 41 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 42 43 // Prepare the request. 44 struct ifreq ifr; 45 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 46 47 // Check for a non-zero interface index. 48 ASSERT_THAT(ioctl(sock.get(), SIOCGIFINDEX, &ifr), SyscallSucceeds()); 49 EXPECT_NE(ifr.ifr_ifindex, 0); 50 51 // Check that the loopback is zero hardware address. 52 ASSERT_THAT(ioctl(sock.get(), SIOCGIFHWADDR, &ifr), SyscallSucceeds()); 53 EXPECT_EQ(ifr.ifr_hwaddr.sa_family, ARPHRD_LOOPBACK); 54 EXPECT_EQ(ifr.ifr_hwaddr.sa_data[0], 0); 55 EXPECT_EQ(ifr.ifr_hwaddr.sa_data[1], 0); 56 EXPECT_EQ(ifr.ifr_hwaddr.sa_data[2], 0); 57 EXPECT_EQ(ifr.ifr_hwaddr.sa_data[3], 0); 58 EXPECT_EQ(ifr.ifr_hwaddr.sa_data[4], 0); 59 EXPECT_EQ(ifr.ifr_hwaddr.sa_data[5], 0); 60 } 61 62 TEST(NetdeviceTest, Netmask) { 63 // We need an interface index to identify the loopback device. 64 FileDescriptor sock = 65 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 66 struct ifreq ifr; 67 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 68 ASSERT_THAT(ioctl(sock.get(), SIOCGIFINDEX, &ifr), SyscallSucceeds()); 69 EXPECT_NE(ifr.ifr_ifindex, 0); 70 71 // Use a netlink socket to get the netmask, which we'll then compare to the 72 // netmask obtained via ioctl. 73 FileDescriptor fd = 74 ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE)); 75 uint32_t port = ASSERT_NO_ERRNO_AND_VALUE(NetlinkPortID(fd.get())); 76 77 struct request { 78 struct nlmsghdr hdr; 79 struct rtgenmsg rgm; 80 }; 81 82 constexpr uint32_t kSeq = 12345; 83 84 struct request req; 85 req.hdr.nlmsg_len = sizeof(req); 86 req.hdr.nlmsg_type = RTM_GETADDR; 87 req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; 88 req.hdr.nlmsg_seq = kSeq; 89 req.rgm.rtgen_family = AF_UNSPEC; 90 91 // Iterate through messages until we find the one containing the prefix length 92 // (i.e. netmask) for the loopback device. 93 int prefixlen = -1; 94 ASSERT_NO_ERRNO(NetlinkRequestResponse( 95 fd, &req, sizeof(req), 96 [&](const struct nlmsghdr* hdr) { 97 EXPECT_THAT(hdr->nlmsg_type, AnyOf(Eq(RTM_NEWADDR), Eq(NLMSG_DONE))); 98 99 EXPECT_TRUE((hdr->nlmsg_flags & NLM_F_MULTI) == NLM_F_MULTI) 100 << std::hex << hdr->nlmsg_flags; 101 102 EXPECT_EQ(hdr->nlmsg_seq, kSeq); 103 EXPECT_EQ(hdr->nlmsg_pid, port); 104 105 if (hdr->nlmsg_type != RTM_NEWADDR) { 106 return; 107 } 108 109 // RTM_NEWADDR contains at least the header and ifaddrmsg. 110 EXPECT_GE(hdr->nlmsg_len, sizeof(*hdr) + sizeof(struct ifaddrmsg)); 111 112 struct ifaddrmsg* ifaddrmsg = 113 reinterpret_cast<struct ifaddrmsg*>(NLMSG_DATA(hdr)); 114 if (ifaddrmsg->ifa_index == static_cast<uint32_t>(ifr.ifr_ifindex) && 115 ifaddrmsg->ifa_family == AF_INET) { 116 prefixlen = ifaddrmsg->ifa_prefixlen; 117 } 118 }, 119 false)); 120 121 ASSERT_GE(prefixlen, 0); 122 123 // Netmask is stored big endian in struct sockaddr_in, so we do the same for 124 // comparison. 125 uint32_t mask = 0xffffffff << (32 - prefixlen); 126 mask = absl::gbswap_32(mask); 127 128 // Check that the loopback interface has the correct subnet mask. 129 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 130 ASSERT_THAT(ioctl(sock.get(), SIOCGIFNETMASK, &ifr), SyscallSucceeds()); 131 EXPECT_EQ(ifr.ifr_netmask.sa_family, AF_INET); 132 struct sockaddr_in* sin = 133 reinterpret_cast<struct sockaddr_in*>(&ifr.ifr_netmask); 134 EXPECT_EQ(sin->sin_addr.s_addr, mask); 135 } 136 137 TEST(NetdeviceTest, InterfaceName) { 138 FileDescriptor sock = 139 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 140 141 // Prepare the request. 142 struct ifreq ifr; 143 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 144 145 // Check for a non-zero interface index. 146 ASSERT_THAT(ioctl(sock.get(), SIOCGIFINDEX, &ifr), SyscallSucceeds()); 147 EXPECT_NE(ifr.ifr_ifindex, 0); 148 149 // Check that SIOCGIFNAME finds the loopback interface. 150 snprintf(ifr.ifr_name, IFNAMSIZ, "foo"); 151 ASSERT_THAT(ioctl(sock.get(), SIOCGIFNAME, &ifr), SyscallSucceeds()); 152 EXPECT_STREQ(ifr.ifr_name, "lo"); 153 } 154 155 TEST(NetdeviceTest, InterfaceFlags) { 156 FileDescriptor sock = 157 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 158 159 // Prepare the request. 160 struct ifreq ifr; 161 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 162 163 // Check that SIOCGIFFLAGS marks the interface with IFF_LOOPBACK, IFF_UP, and 164 // IFF_RUNNING. 165 ASSERT_THAT(ioctl(sock.get(), SIOCGIFFLAGS, &ifr), SyscallSucceeds()); 166 EXPECT_EQ(ifr.ifr_flags & IFF_UP, IFF_UP); 167 EXPECT_EQ(ifr.ifr_flags & IFF_RUNNING, IFF_RUNNING); 168 } 169 170 TEST(NetdeviceTest, InterfaceMTU) { 171 FileDescriptor sock = 172 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 173 174 // Prepare the request. 175 struct ifreq ifr = {}; 176 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 177 178 // Check that SIOCGIFMTU returns a nonzero MTU. 179 ASSERT_THAT(ioctl(sock.get(), SIOCGIFMTU, &ifr), SyscallSucceeds()); 180 EXPECT_GT(ifr.ifr_mtu, 0); 181 } 182 183 TEST(NetdeviceTest, InterfaceQLEN) { 184 FileDescriptor sock = 185 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_STREAM, 0)); 186 187 // Prepare the request. 188 struct ifreq ifr = {}; 189 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 190 191 // Check that SIOCGIFTXQLEN returns without error. 192 ASSERT_THAT(ioctl(sock.get(), SIOCGIFTXQLEN, &ifr), SyscallSucceeds()); 193 194 // Gvisor network doesn't implement queues and always returns 0. 195 // When exposing the host network, lo could have any queue length set. 196 if (IsRunningOnGvisor() && !IsRunningWithHostinet()) { 197 EXPECT_EQ(ifr.ifr_qlen, 0); 198 } 199 } 200 201 TEST(NetdeviceTest, EthtoolGetTSInfo) { 202 FileDescriptor sock = 203 ASSERT_NO_ERRNO_AND_VALUE(Socket(AF_INET, SOCK_DGRAM, 0)); 204 205 struct ethtool_ts_info tsi = {}; 206 tsi.cmd = ETHTOOL_GET_TS_INFO; // Get NIC's Timestamping capabilities. 207 208 // Prepare the request. 209 struct ifreq ifr = {}; 210 snprintf(ifr.ifr_name, IFNAMSIZ, "lo"); 211 ifr.ifr_data = (void*)&tsi; 212 213 // Check that SIOCGIFMTU returns a nonzero MTU. 214 if (IsRunningOnGvisor()) { 215 ASSERT_THAT(ioctl(sock.get(), SIOCETHTOOL, &ifr), 216 SyscallFailsWithErrno(EOPNOTSUPP)); 217 return; 218 } 219 ASSERT_THAT(ioctl(sock.get(), SIOCETHTOOL, &ifr), SyscallSucceeds()); 220 } 221 222 } // namespace 223 224 } // namespace testing 225 } // namespace gvisor