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