// Copyright 2020 The gVisor Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "test/syscalls/linux/socket_netlink_route_util.h" #include #include #include #include "test/syscalls/linux/socket_netlink_util.h" namespace gvisor { namespace testing { namespace { constexpr uint32_t kSeq = 12345; } // namespace PosixError DumpLinks( const FileDescriptor& fd, uint32_t seq, const std::function& fn) { struct request { struct nlmsghdr hdr; struct ifinfomsg ifm; }; struct request req = {}; req.hdr.nlmsg_len = sizeof(req); req.hdr.nlmsg_type = RTM_GETLINK; req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; req.hdr.nlmsg_seq = seq; req.ifm.ifi_family = AF_UNSPEC; return NetlinkRequestResponse(fd, &req, sizeof(req), fn, false); } PosixErrorOr> DumpLinks() { ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, NetlinkBoundSocket(NETLINK_ROUTE)); std::vector links; RETURN_IF_ERRNO(DumpLinks(fd, kSeq, [&](const struct nlmsghdr* hdr) { if (hdr->nlmsg_type != RTM_NEWLINK || hdr->nlmsg_len < NLMSG_SPACE(sizeof(struct ifinfomsg))) { return; } const struct ifinfomsg* msg = reinterpret_cast(NLMSG_DATA(hdr)); const auto* rta = FindRtAttr(hdr, msg, IFLA_IFNAME); if (rta == nullptr) { // Ignore links that do not have a name. return; } links.emplace_back(); links.back().index = msg->ifi_index; links.back().type = msg->ifi_type; links.back().name = std::string(reinterpret_cast(RTA_DATA(rta))); })); return links; } PosixErrorOr LoopbackLink() { ASSIGN_OR_RETURN_ERRNO(auto links, DumpLinks()); for (const auto& link : links) { if (link.type == ARPHRD_LOOPBACK) { return link; } } return PosixError(ENOENT, "loopback link not found"); } PosixError LinkAddLocalAddr(int index, int family, int prefixlen, const void* addr, int addrlen) { ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, NetlinkBoundSocket(NETLINK_ROUTE)); struct request { struct nlmsghdr hdr; struct ifaddrmsg ifaddr; char attrbuf[512]; }; struct request req = {}; req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifaddr)); req.hdr.nlmsg_type = RTM_NEWADDR; req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.hdr.nlmsg_seq = kSeq; req.ifaddr.ifa_index = index; req.ifaddr.ifa_family = family; req.ifaddr.ifa_prefixlen = prefixlen; struct rtattr* rta = reinterpret_cast( reinterpret_cast(&req) + NLMSG_ALIGN(req.hdr.nlmsg_len)); rta->rta_type = IFA_LOCAL; rta->rta_len = RTA_LENGTH(addrlen); req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(addrlen); memcpy(RTA_DATA(rta), addr, addrlen); return NetlinkRequestAckOrError(fd, kSeq, &req, req.hdr.nlmsg_len); } PosixError LinkChangeFlags(int index, unsigned int flags, unsigned int change) { ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, NetlinkBoundSocket(NETLINK_ROUTE)); struct request { struct nlmsghdr hdr; struct ifinfomsg ifinfo; char pad[NLMSG_ALIGNTO]; }; struct request req = {}; req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifinfo)); req.hdr.nlmsg_type = RTM_NEWLINK; req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.hdr.nlmsg_seq = kSeq; req.ifinfo.ifi_index = index; req.ifinfo.ifi_flags = flags; req.ifinfo.ifi_change = change; return NetlinkRequestAckOrError(fd, kSeq, &req, req.hdr.nlmsg_len); } PosixError LinkSetMacAddr(int index, const void* addr, int addrlen) { ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, NetlinkBoundSocket(NETLINK_ROUTE)); struct request { struct nlmsghdr hdr; struct ifinfomsg ifinfo; char attrbuf[512]; }; struct request req = {}; req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(req.ifinfo)); req.hdr.nlmsg_type = RTM_NEWLINK; req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; req.hdr.nlmsg_seq = kSeq; req.ifinfo.ifi_index = index; struct rtattr* rta = reinterpret_cast( reinterpret_cast(&req) + NLMSG_ALIGN(req.hdr.nlmsg_len)); rta->rta_type = IFLA_ADDRESS; rta->rta_len = RTA_LENGTH(addrlen); req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(addrlen); memcpy(RTA_DATA(rta), addr, addrlen); return NetlinkRequestAckOrError(fd, kSeq, &req, req.hdr.nlmsg_len); } } // namespace testing } // namespace gvisor