@@ -1796,6 +1796,16 @@ TEST(NetlinkRouteTest, VethAdd) {
17961796 SKIP_IF (!ASSERT_NO_ERRNO_AND_VALUE (HaveCapability (CAP_NET_ADMIN)));
17971797 SKIP_IF (IsRunningWithHostinet ());
17981798
1799+ // Running the test in an ephemeral netns allows it to not interfere with
1800+ // other tests that also want to create veth pairs with the same names.
1801+ const FileDescriptor curr_nsfd =
1802+ ASSERT_NO_ERRNO_AND_VALUE (Open (" /proc/thread-self/ns/net" , O_RDONLY));
1803+ Cleanup restore_netns = Cleanup ([&] {
1804+ ASSERT_THAT (setns (curr_nsfd.get (), CLONE_NEWNET),
1805+ SyscallSucceedsWithValue (0 ));
1806+ });
1807+ ASSERT_THAT (unshare (CLONE_NEWNET), SyscallSucceedsWithValue (0 ));
1808+
17991809 FileDescriptor fd =
18001810 ASSERT_NO_ERRNO_AND_VALUE (NetlinkBoundSocket (NETLINK_ROUTE));
18011811 VethRequest req = GetVethRequest (kSeq , " veth1" , " veth2" );
@@ -1823,6 +1833,86 @@ TEST(NetlinkRouteTest, LookupAllAddrOrder) {
18231833 }
18241834}
18251835
1836+ struct NetNSRequest {
1837+ struct nlmsghdr hdr;
1838+ struct ifinfomsg ifm;
1839+ char buf[1024 ];
1840+ };
1841+
1842+ struct NetNSRequest GetNetNSRequest (uint32_t seq, int if_index, int ns_fd) {
1843+ struct NetNSRequest req = {};
1844+
1845+ req.hdr .nlmsg_len = NLMSG_LENGTH (sizeof (struct ifinfomsg ));
1846+ req.hdr .nlmsg_type = RTM_NEWLINK;
1847+ req.hdr .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1848+ req.hdr .nlmsg_seq = seq;
1849+ req.ifm .ifi_family = AF_UNSPEC;
1850+ req.ifm .ifi_index = if_index;
1851+ addattr (&req.hdr , sizeof (req), IFLA_NET_NS_FD, &ns_fd, sizeof (ns_fd));
1852+
1853+ return req;
1854+ }
1855+
1856+ // Guard against b/456552490, a bug where gvisor'd try to modify the given
1857+ // attributes in the wrong stack when the request also directs it to change the
1858+ // netns.
1859+ TEST (NetlinkRouteTest, ChangeNetnsAndOtherAttrsTogether) {
1860+ SKIP_IF (!ASSERT_NO_ERRNO_AND_VALUE (HaveCapability (CAP_NET_ADMIN)));
1861+ SKIP_IF (IsRunningWithHostinet ());
1862+ // TODO(gvisor.dev/issue/4595): enable cooperative save tests.
1863+ const DisableSave ds;
1864+
1865+ // Running the test in an ephemeral netns allows it to not interfere with
1866+ // other tests that also want to create veth pairs with the same names.
1867+ const FileDescriptor curr_nsfd =
1868+ ASSERT_NO_ERRNO_AND_VALUE (Open (" /proc/thread-self/ns/net" , O_RDONLY));
1869+ Cleanup restore_netns = Cleanup ([&] {
1870+ ASSERT_THAT (setns (curr_nsfd.get (), CLONE_NEWNET),
1871+ SyscallSucceedsWithValue (0 ));
1872+ });
1873+ ASSERT_THAT (unshare (CLONE_NEWNET), SyscallSucceedsWithValue (0 ));
1874+
1875+ FileDescriptor nlsk =
1876+ ASSERT_NO_ERRNO_AND_VALUE (NetlinkBoundSocket (NETLINK_ROUTE));
1877+ VethRequest req = GetVethRequest (kSeq , " veth1" , " veth2" );
1878+ EXPECT_NO_ERRNO (
1879+ NetlinkRequestAckOrError (nlsk, kSeq , &req, req.hdr .nlmsg_len ));
1880+ int inner_veth_idx = if_nametoindex (" veth2" );
1881+ ASSERT_NE (inner_veth_idx, 0 );
1882+
1883+ // Enter a new network namespace and move veth2 into it.
1884+ ASSERT_THAT (unshare (CLONE_NEWNET), SyscallSucceedsWithValue (0 ));
1885+ const FileDescriptor inner_nsfd =
1886+ ASSERT_NO_ERRNO_AND_VALUE (Open (" /proc/thread-self/ns/net" , O_RDONLY));
1887+ NetNSRequest set_netns_req =
1888+ GetNetNSRequest (kSeq , inner_veth_idx, inner_nsfd.get ());
1889+ // Request a name change along with the netns change.
1890+ std::string new_name = " veth2_new" ;
1891+ addattr (&set_netns_req.hdr , sizeof (set_netns_req), IFLA_IFNAME,
1892+ new_name.c_str (), new_name.size ());
1893+ EXPECT_NO_ERRNO (NetlinkRequestAckOrError (nlsk, kSeq , &set_netns_req,
1894+ set_netns_req.hdr .nlmsg_len ));
1895+
1896+ // Verify that an interface with the new name exists in the inner netns.
1897+ bool found_name_inner = false ;
1898+ std::vector<Link> links = ASSERT_NO_ERRNO_AND_VALUE (DumpLinks ());
1899+ for (const Link& link : links) {
1900+ if (link.name == new_name) {
1901+ found_name_inner = true ;
1902+ break ;
1903+ }
1904+ }
1905+ EXPECT_TRUE (found_name_inner)
1906+ << " Did not find interface with name " << new_name;
1907+
1908+ // And verify also that the outer netns does not have the new name.
1909+ links = ASSERT_NO_ERRNO_AND_VALUE (DumpLinks (nlsk));
1910+ for (const Link& link : links) {
1911+ ASSERT_NE (link.name , new_name)
1912+ << " Found interface with name " << new_name << " in outer netns" ;
1913+ }
1914+ }
1915+
18261916struct NameRequest {
18271917 struct nlmsghdr hdr;
18281918 struct ifinfomsg ifm;
@@ -1965,27 +2055,23 @@ TEST(NetlinkRouteTest, LinkMulticastGroupBasic) {
19652055 }
19662056}
19672057
1968- struct VethRequest GetSetNetNSRequest (uint32_t seq, int if_index, int ns_fd) {
1969- struct VethRequest req = {};
1970-
1971- req.hdr .nlmsg_len = NLMSG_LENGTH (sizeof (struct ifinfomsg ));
1972- req.hdr .nlmsg_type = RTM_NEWLINK;
1973- req.hdr .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1974- req.hdr .nlmsg_seq = seq;
1975- req.ifm .ifi_family = AF_UNSPEC;
1976- req.ifm .ifi_index = if_index;
1977- addattr (&req.hdr , sizeof (req), IFLA_NET_NS_FD, &ns_fd, sizeof (ns_fd));
1978-
1979- return req;
1980- }
1981-
19822058// To verify the namespaced nature of the netlink multicast groups.
19832059TEST (NetlinkRouteTest, LinkMulticastGroupNamespaced) {
19842060 SKIP_IF (!ASSERT_NO_ERRNO_AND_VALUE (HaveCapability (CAP_NET_ADMIN)));
19852061 SKIP_IF (IsRunningWithHostinet ());
19862062 // TODO(gvisor.dev/issue/4595): enable cooperative save tests.
19872063 const DisableSave ds;
19882064
2065+ // Running the test in an ephemeral netns allows it to not interfere with
2066+ // other tests that also want to create veth pairs with the same names.
2067+ const FileDescriptor curr_nsfd =
2068+ ASSERT_NO_ERRNO_AND_VALUE (Open (" /proc/thread-self/ns/net" , O_RDONLY));
2069+ Cleanup restore_netns = Cleanup ([&] {
2070+ ASSERT_THAT (setns (curr_nsfd.get (), CLONE_NEWNET),
2071+ SyscallSucceedsWithValue (0 ));
2072+ });
2073+ ASSERT_THAT (unshare (CLONE_NEWNET), SyscallSucceedsWithValue (0 ));
2074+
19892075 FileDescriptor control_nlsk =
19902076 ASSERT_NO_ERRNO_AND_VALUE (NetlinkBoundSocket (NETLINK_ROUTE));
19912077 VethRequest req = GetVethRequest (kSeq , " veth1" , " veth2" );
@@ -1998,16 +2084,9 @@ TEST(NetlinkRouteTest, LinkMulticastGroupNamespaced) {
19982084 struct sockaddr_nl mcast_addr = {};
19992085 mcast_addr.nl_family = AF_NETLINK;
20002086 mcast_addr.nl_groups = RTMGRP_LINK;
2001- FileDescriptor root_nlsk =
2087+ FileDescriptor outer_nlsk =
20022088 ASSERT_NO_ERRNO_AND_VALUE (NetlinkBoundSocket (NETLINK_ROUTE, &mcast_addr));
20032089
2004- const FileDescriptor root_nsfd =
2005- ASSERT_NO_ERRNO_AND_VALUE (Open (" /proc/thread-self/ns/net" , O_RDONLY));
2006- Cleanup restore_netns = Cleanup ([&] {
2007- ASSERT_THAT (setns (root_nsfd.get (), CLONE_NEWNET),
2008- SyscallSucceedsWithValue (0 ));
2009- });
2010-
20112090 // Enter a new network namespace.
20122091 ASSERT_THAT (unshare (CLONE_NEWNET), SyscallSucceedsWithValue (0 ));
20132092 FileDescriptor inner_nlsk =
@@ -2016,24 +2095,24 @@ TEST(NetlinkRouteTest, LinkMulticastGroupNamespaced) {
20162095 // And move veth2 into it.
20172096 const FileDescriptor inner_nsfd =
20182097 ASSERT_NO_ERRNO_AND_VALUE (Open (" /proc/thread-self/ns/net" , O_RDONLY));
2019- VethRequest set_netns_req =
2020- GetSetNetNSRequest (kSeq , inner_veth_idx, inner_nsfd.get ());
2098+ NetNSRequest set_netns_req =
2099+ GetNetNSRequest (kSeq , inner_veth_idx, inner_nsfd.get ());
20212100 EXPECT_NO_ERRNO (NetlinkRequestAckOrError (control_nlsk, kSeq , &set_netns_req,
20222101 set_netns_req.hdr .nlmsg_len ));
20232102
20242103 constexpr int kPollTimeoutMs = 1000 ;
20252104 bool got_msg = false ;
2026- // We expect an RTM_DELINK message for veth2 in the root netns socket.
2105+ // We expect an RTM_DELINK message for veth2 in the outer netns socket.
20272106 // But an RTM_NEWLINK is also expected for veth1 because its peer was moved.
20282107 // Hence the two attempts. N.B. gVisor does not send the RTM_NEWLINK because
20292108 // IFLA_LINK_NETNSID is not yet supported.
20302109 for (int i = 0 ; i < 2 ; ++i) {
2031- struct pollfd pfd = {.fd = root_nlsk .get (), .events = POLLIN};
2110+ struct pollfd pfd = {.fd = outer_nlsk .get (), .events = POLLIN};
20322111 ASSERT_EQ (RetryEINTR (poll)(&pfd, 1 , kPollTimeoutMs ), 1 )
20332112 << " root_nlsk: Did not get veth2 DELLINK" ;
20342113
20352114 ASSERT_NO_ERRNO (NetlinkResponse (
2036- root_nlsk ,
2115+ outer_nlsk ,
20372116 [&](const struct nlmsghdr * hdr) {
20382117 const struct ifinfomsg * msg =
20392118 reinterpret_cast <const struct ifinfomsg *>(NLMSG_DATA (hdr));
@@ -2044,7 +2123,7 @@ TEST(NetlinkRouteTest, LinkMulticastGroupNamespaced) {
20442123 /* expect_nlmsgerr=*/ false ));
20452124 if (got_msg) break ;
20462125 }
2047- EXPECT_TRUE (got_msg) << " root_nlsk : Did not get veth2 DELLINK" ;
2126+ EXPECT_TRUE (got_msg) << " outer_nlsk : Did not get veth2 DELLINK" ;
20482127
20492128 // We expect an RTM_NEWLINK message for veth2 in the inner netns socket.
20502129 {
0 commit comments