mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add test coverage for RTM_NEWROUTE & RTM_DELROUTE
PiperOrigin-RevId: 554612706
This commit is contained in:
@@ -151,6 +151,8 @@ cc_library(
|
||||
hdrs = ["socket_netlink_route_util.h"],
|
||||
deps = [
|
||||
":socket_netlink_util",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:posix_error",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -3371,6 +3373,8 @@ cc_binary(
|
||||
"//test/util:capability_util",
|
||||
"//test/util:cleanup",
|
||||
"//test/util:file_descriptor",
|
||||
"//test/util:posix_error",
|
||||
"//test/util:save_util",
|
||||
"//test/util:socket_util",
|
||||
"@com_google_absl//absl/strings:str_format",
|
||||
gtest,
|
||||
|
||||
@@ -22,16 +22,21 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "test/syscalls/linux/socket_netlink_route_util.h"
|
||||
#include "test/syscalls/linux/socket_netlink_util.h"
|
||||
#include "test/util/capability_util.h"
|
||||
#include "test/util/cleanup.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/linux_capability_util.h"
|
||||
#include "test/util/posix_error.h"
|
||||
#include "test/util/save_util.h"
|
||||
#include "test/util/socket_util.h"
|
||||
#include "test/util/test_util.h"
|
||||
|
||||
@@ -823,6 +828,63 @@ TEST(NetlinkRouteTest, GetRouteRequest) {
|
||||
EXPECT_TRUE(rtDstFound);
|
||||
}
|
||||
|
||||
// NetlinkRouteTest with a single parameter that must be AF_INET or AF_INET6.
|
||||
using NetlinkRouteIpInvariantTest = ::testing::TestWithParam<int>;
|
||||
|
||||
TEST_P(NetlinkRouteIpInvariantTest, AddAndRemoveRoute) {
|
||||
// Gvisor does not support `RTM_NEWROUTE` or `RTM_DELROUTE`.
|
||||
SKIP_IF(IsRunningOnGvisor());
|
||||
// CAP_NET_ADMIN is required to modify the routing table.
|
||||
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
|
||||
|
||||
// Based on the test parameter, build an IPv4 or IPv6 destination subnet.
|
||||
int family = GetParam();
|
||||
struct in_addr dst_v4;
|
||||
struct in6_addr dst_v6;
|
||||
void* dst = nullptr;
|
||||
int dst_len;
|
||||
int prefixlen;
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
ASSERT_EQ(inet_pton(family, "192.0.2.0", &dst_v4), 1);
|
||||
prefixlen = 24;
|
||||
dst = &dst_v4;
|
||||
dst_len = sizeof(dst_v4);
|
||||
break;
|
||||
case AF_INET6:
|
||||
ASSERT_EQ(inet_pton(family, "2001:db8::", &dst_v6), 1);
|
||||
prefixlen = 64;
|
||||
dst = &dst_v6;
|
||||
dst_len = sizeof(dst_v6);
|
||||
break;
|
||||
default:
|
||||
FAIL() << "address family must be AF_INET or AF_INET6";
|
||||
}
|
||||
|
||||
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
|
||||
|
||||
// Create should succeed, as no such route in kernel.
|
||||
ASSERT_NO_ERRNO(
|
||||
AddUnicastRoute(loopback_link.index, family, prefixlen, dst, dst_len));
|
||||
|
||||
// Second create should fail, as we already created the route above.
|
||||
EXPECT_THAT(
|
||||
AddUnicastRoute(loopback_link.index, family, prefixlen, dst, dst_len),
|
||||
PosixErrorIs(EEXIST, _));
|
||||
|
||||
// First delete should succeed, as route exists.
|
||||
EXPECT_NO_ERRNO(
|
||||
DelUnicastRoute(loopback_link.index, family, prefixlen, dst, dst_len));
|
||||
|
||||
// Second delete should fail, as route no longer exists.
|
||||
EXPECT_THAT(
|
||||
DelUnicastRoute(loopback_link.index, family, prefixlen, dst, dst_len),
|
||||
PosixErrorIs(ESRCH, _));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AddAndRemoveRoute, NetlinkRouteIpInvariantTest,
|
||||
::testing::Values(AF_INET, AF_INET6));
|
||||
|
||||
// RecvmsgTrunc tests the recvmsg MSG_TRUNC flag with zero length output
|
||||
// buffer. MSG_TRUNC with a zero length buffer should consume subsequent
|
||||
// messages off the socket.
|
||||
|
||||
@@ -18,39 +18,46 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
#include "test/syscalls/linux/socket_netlink_util.h"
|
||||
#include "test/util/file_descriptor.h"
|
||||
#include "test/util/posix_error.h"
|
||||
|
||||
namespace gvisor {
|
||||
namespace testing {
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kSeq = 12345;
|
||||
constexpr uint32_t kMetric = 999;
|
||||
|
||||
// Types of address modifications that may be performed on an interface.
|
||||
enum class LinkAddrModification {
|
||||
// Types of modifications that may be performed to a Netlink resource.
|
||||
enum class NetlinkModification {
|
||||
kAdd,
|
||||
kAddExclusive,
|
||||
kReplace,
|
||||
kDelete,
|
||||
};
|
||||
|
||||
// Populates |hdr| with appripriate values for the modification type.
|
||||
PosixError PopulateNlmsghdr(LinkAddrModification modification,
|
||||
struct nlmsghdr* hdr) {
|
||||
// Populates |hdr| with appropriate values for the modification type.
|
||||
PosixError PopulateLinkAddrNlmsghdr(NetlinkModification modification,
|
||||
struct nlmsghdr* hdr) {
|
||||
switch (modification) {
|
||||
case LinkAddrModification::kAdd:
|
||||
case NetlinkModification::kAdd:
|
||||
hdr->nlmsg_type = RTM_NEWADDR;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
return NoError();
|
||||
case LinkAddrModification::kAddExclusive:
|
||||
case NetlinkModification::kAddExclusive:
|
||||
hdr->nlmsg_type = RTM_NEWADDR;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_ACK;
|
||||
return NoError();
|
||||
case LinkAddrModification::kReplace:
|
||||
case NetlinkModification::kReplace:
|
||||
hdr->nlmsg_type = RTM_NEWADDR;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_ACK;
|
||||
return NoError();
|
||||
case LinkAddrModification::kDelete:
|
||||
case NetlinkModification::kDelete:
|
||||
hdr->nlmsg_type = RTM_DELADDR;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
return NoError();
|
||||
@@ -59,10 +66,35 @@ PosixError PopulateNlmsghdr(LinkAddrModification modification,
|
||||
return PosixError(EINVAL);
|
||||
}
|
||||
|
||||
// Populates |hdr| with appropriate values for the modification type.
|
||||
PosixError PopulateRouteNlmsghdr(NetlinkModification modification,
|
||||
struct nlmsghdr* hdr) {
|
||||
switch (modification) {
|
||||
case NetlinkModification::kAdd:
|
||||
hdr->nlmsg_type = RTM_NEWROUTE;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
|
||||
return NoError();
|
||||
case NetlinkModification::kAddExclusive:
|
||||
hdr->nlmsg_type = RTM_NEWROUTE;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_ACK;
|
||||
return NoError();
|
||||
case NetlinkModification::kReplace:
|
||||
hdr->nlmsg_type = RTM_NEWROUTE;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_ACK;
|
||||
return NoError();
|
||||
case NetlinkModification::kDelete:
|
||||
hdr->nlmsg_type = RTM_DELROUTE;
|
||||
hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
return NoError();
|
||||
}
|
||||
|
||||
return PosixError(EINVAL);
|
||||
}
|
||||
|
||||
// Adds or removes the specified address from the specified interface.
|
||||
PosixError LinkModifyLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen,
|
||||
LinkAddrModification modification) {
|
||||
NetlinkModification modification) {
|
||||
ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
struct request {
|
||||
@@ -72,7 +104,7 @@ PosixError LinkModifyLocalAddr(int index, int family, int prefixlen,
|
||||
};
|
||||
|
||||
struct request req = {};
|
||||
PosixError err = PopulateNlmsghdr(modification, &req.hdr);
|
||||
PosixError err = PopulateLinkAddrNlmsghdr(modification, &req.hdr);
|
||||
if (!err.ok()) {
|
||||
return err;
|
||||
}
|
||||
@@ -92,6 +124,55 @@ PosixError LinkModifyLocalAddr(int index, int family, int prefixlen,
|
||||
return NetlinkRequestAckOrError(fd, kSeq, &req, req.hdr.nlmsg_len);
|
||||
}
|
||||
|
||||
// Adds or removes the specified route.
|
||||
PosixError ModifyUnicastRoute(int interface, int family, int prefixlen,
|
||||
const void* dst, int dstlen,
|
||||
NetlinkModification modification) {
|
||||
ASSIGN_OR_RETURN_ERRNO(FileDescriptor fd, NetlinkBoundSocket(NETLINK_ROUTE));
|
||||
|
||||
struct request {
|
||||
struct nlmsghdr hdr;
|
||||
struct rtmsg route;
|
||||
char attrbuf[512];
|
||||
};
|
||||
|
||||
struct request req = {};
|
||||
PosixError err = PopulateRouteNlmsghdr(modification, &req.hdr);
|
||||
if (!err.ok()) {
|
||||
return err;
|
||||
}
|
||||
req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(req.route));
|
||||
req.hdr.nlmsg_seq = kSeq;
|
||||
req.route.rtm_dst_len = prefixlen;
|
||||
req.route.rtm_family = family;
|
||||
req.route.rtm_type = RTN_UNICAST;
|
||||
|
||||
struct rtattr* rta_oif = reinterpret_cast<struct rtattr*>(
|
||||
reinterpret_cast<int8_t*>(&req) + NLMSG_ALIGN(req.hdr.nlmsg_len));
|
||||
rta_oif->rta_type = RTA_OIF;
|
||||
rta_oif->rta_len = RTA_LENGTH(sizeof(interface));
|
||||
req.hdr.nlmsg_len =
|
||||
NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(sizeof(interface));
|
||||
memcpy(RTA_DATA(rta_oif), &interface, sizeof(interface));
|
||||
|
||||
struct rtattr* rta_priority = reinterpret_cast<struct rtattr*>(
|
||||
reinterpret_cast<int8_t*>(&req) + NLMSG_ALIGN(req.hdr.nlmsg_len));
|
||||
rta_priority->rta_type = RTA_PRIORITY;
|
||||
rta_priority->rta_len = RTA_LENGTH(sizeof(kMetric));
|
||||
req.hdr.nlmsg_len =
|
||||
NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(sizeof(kMetric));
|
||||
memcpy(RTA_DATA(rta_priority), &kMetric, sizeof(kMetric));
|
||||
|
||||
struct rtattr* rta_dst = reinterpret_cast<struct rtattr*>(
|
||||
reinterpret_cast<int8_t*>(&req) + NLMSG_ALIGN(req.hdr.nlmsg_len));
|
||||
rta_dst->rta_type = RTA_DST;
|
||||
rta_dst->rta_len = RTA_LENGTH(dstlen);
|
||||
req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_LENGTH(dstlen);
|
||||
memcpy(RTA_DATA(rta_dst), dst, dstlen);
|
||||
|
||||
return NetlinkRequestAckOrError(fd, kSeq, &req, req.hdr.nlmsg_len);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
PosixError DumpLinks(
|
||||
@@ -151,25 +232,25 @@ PosixErrorOr<Link> LoopbackLink() {
|
||||
PosixError LinkAddLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
LinkAddrModification::kAdd);
|
||||
NetlinkModification::kAdd);
|
||||
}
|
||||
|
||||
PosixError LinkAddExclusiveLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
LinkAddrModification::kAddExclusive);
|
||||
NetlinkModification::kAddExclusive);
|
||||
}
|
||||
|
||||
PosixError LinkReplaceLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
LinkAddrModification::kReplace);
|
||||
NetlinkModification::kReplace);
|
||||
}
|
||||
|
||||
PosixError LinkDelLocalAddr(int index, int family, int prefixlen,
|
||||
const void* addr, int addrlen) {
|
||||
return LinkModifyLocalAddr(index, family, prefixlen, addr, addrlen,
|
||||
LinkAddrModification::kDelete);
|
||||
NetlinkModification::kDelete);
|
||||
}
|
||||
|
||||
PosixError LinkChangeFlags(int index, unsigned int flags, unsigned int change) {
|
||||
@@ -219,5 +300,17 @@ PosixError LinkSetMacAddr(int index, const void* addr, int addrlen) {
|
||||
return NetlinkRequestAckOrError(fd, kSeq, &req, req.hdr.nlmsg_len);
|
||||
}
|
||||
|
||||
PosixError AddUnicastRoute(int interface, int family, int prefixlen,
|
||||
const void* dst, int dstlen) {
|
||||
return ModifyUnicastRoute(interface, family, prefixlen, dst, dstlen,
|
||||
NetlinkModification::kAdd);
|
||||
}
|
||||
|
||||
PosixError DelUnicastRoute(int interface, int family, int prefixlen,
|
||||
const void* dst, int dstlen) {
|
||||
return ModifyUnicastRoute(interface, family, prefixlen, dst, dstlen,
|
||||
NetlinkModification::kDelete);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
@@ -62,6 +62,14 @@ PosixError LinkChangeFlags(int index, unsigned int flags, unsigned int change);
|
||||
// LinkSetMacAddr sets IFLA_ADDRESS attribute of the interface.
|
||||
PosixError LinkSetMacAddr(int index, const void* addr, int addrlen);
|
||||
|
||||
// AddRoute adds a route to the given dst subnet via the given interface.
|
||||
PosixError AddUnicastRoute(int interface, int family, int prefixlen,
|
||||
const void* dst, int dstlen);
|
||||
|
||||
// DelRoute removes a route to the given dst subnet via the given interface.
|
||||
PosixError DelUnicastRoute(int interface, int family, int prefixlen,
|
||||
const void* dst, int dstlen);
|
||||
|
||||
} // namespace testing
|
||||
} // namespace gvisor
|
||||
|
||||
|
||||
Reference in New Issue
Block a user