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