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