Fix the MAC address parse in IFLA_ADDRESS and add the tests.

PiperOrigin-RevId: 650333797
This commit is contained in:
Jing Chen
2024-07-08 12:19:08 -07:00
committed by gVisor bot
parent 3e875a5dad
commit 096478a2ff
7 changed files with 106 additions and 8 deletions
+2 -2
View File
@@ -206,10 +206,10 @@ func (s *Stack) setLink(ctx context.Context, id tcpip.NICID, linkAttrs map[uint1
}
}
case linux.IFLA_ADDRESS:
addr, err := tcpip.ParseMACAddress(v.String())
if err != nil {
if len(v) != tcpip.LinkAddressSize {
return syserr.ErrInvalidArgument
}
addr := tcpip.LinkAddress(v)
if err := s.Stack.SetNICAddress(id, addr); err != nil {
return syserr.TranslateNetstackError(err)
}
+11 -3
View File
@@ -38,6 +38,8 @@ type endpoint struct {
// +checklocks:mu
dispatcher stack.NetworkDispatcher
// +checklocks:mu
addr tcpip.LinkAddress
// +checklocks:mu
mtu uint32
}
@@ -91,12 +93,18 @@ func (*endpoint) MaxHeaderLength() uint16 {
}
// LinkAddress returns the link address of this endpoint.
func (*endpoint) LinkAddress() tcpip.LinkAddress {
return ""
func (e *endpoint) LinkAddress() tcpip.LinkAddress {
e.mu.RLock()
defer e.mu.RUnlock()
return e.addr
}
// SetLinkAddress implements stack.LinkEndpoint.SetLinkAddress.
func (*endpoint) SetLinkAddress(tcpip.LinkAddress) {}
func (e *endpoint) SetLinkAddress(addr tcpip.LinkAddress) {
e.mu.Lock()
defer e.mu.Unlock()
e.addr = addr
}
// Wait implements stack.LinkEndpoint.Wait.
func (*endpoint) Wait() {}
+7 -2
View File
@@ -55,6 +55,11 @@ const (
ipv6ProtocolNumber = 0x86dd
)
const (
// LinkAddressSize is the size of a MAC address.
LinkAddressSize = 6
)
// Errors related to Subnet
var (
errSubnetLengthMismatch = errors.New("subnet length of address and mask differ")
@@ -2705,7 +2710,7 @@ func ParseMACAddress(s string) (LinkAddress, error) {
parts := strings.FieldsFunc(s, func(c rune) bool {
return c == ':' || c == '-'
})
if len(parts) != 6 {
if len(parts) != LinkAddressSize {
return "", fmt.Errorf("inconsistent parts: %s", s)
}
addr := make([]byte, 0, len(parts))
@@ -2721,7 +2726,7 @@ func ParseMACAddress(s string) (LinkAddress, error) {
// GetRandMacAddr returns a mac address that can be used for local virtual devices.
func GetRandMacAddr() LinkAddress {
mac := make(net.HardwareAddr, 6)
mac := make(net.HardwareAddr, LinkAddressSize)
rand.Read(mac) // Fill with random data.
mac[0] &^= 0x1 // Clear multicast bit.
mac[0] |= 0x2 // Set local assignment bit (IEEE802).
+11
View File
@@ -38,3 +38,14 @@ if ! wait_for ! ip link show test_veth02; then
fail "test_veth02 hasn't been destroyed"
exit 1
fi
# Change the hardware address of a new veth device.
ip link add name test_veth01 type veth peer name test_veth02
ip link set dev test_veth01 address 1a:2a:3a:4a:5a:6a
ip link show test_veth01 | grep "1a:2a:3a:4a:5a:6a"
ip link del name test_veth01
# Check that test_veth02 has been destroyed.
if ! wait_for ! ip link show test_veth02; then
fail "test_veth02 hasn't been destroyed"
exit 1
fi
+69 -1
View File
@@ -172,9 +172,14 @@ void CheckLinkMsg(const struct nlmsghdr* hdr, const Link& link) {
EXPECT_NE(nullptr, rta_mtu) << "IFLA_MTU not found in message.";
if (rta_mtu != nullptr) {
const auto mtu = *(uint32_t*)(RTA_DATA(rta_mtu));
std::cout << "mtu: " << mtu << "link.mtu " << link.mtu << std::endl;
EXPECT_EQ(mtu, link.mtu);
}
const struct rtattr* rta_address = FindRtAttr(hdr, msg, IFLA_ADDRESS);
EXPECT_NE(nullptr, rta_address) << "IFLA_ADDRESS not found in message.";
if (rta_address != nullptr) {
std::string address(reinterpret_cast<const char*>(RTA_DATA(rta_address)));
EXPECT_EQ(address, link.address);
}
}
TEST(NetlinkRouteTest, GetLinkByIndex) {
@@ -327,6 +332,69 @@ TEST_P(NetlinkSetLinkTest, ChangeMTU) {
EXPECT_TRUE(found) << "Netlink response does not contain any links.";
}
TEST_P(NetlinkSetLinkTest, ChangeMACAddress) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
SKIP_IF(!IsRunningOnGvisor());
SKIP_IF(IsRunningWithHostinet());
Link loopback_link = ASSERT_NO_ERRNO_AND_VALUE(LoopbackLink());
FileDescriptor fd =
ASSERT_NO_ERRNO_AND_VALUE(NetlinkBoundSocket(NETLINK_ROUTE));
struct request {
struct nlmsghdr hdr;
struct ifinfomsg ifm;
struct rtattr rtattr;
char address[1024];
};
const int address_size = 6;
const char address[address_size + 1] = {static_cast<char>(0xa1),
static_cast<char>(0xa2),
static_cast<char>(0xa3),
static_cast<char>(0xa4),
static_cast<char>(0xa5),
static_cast<char>(0xa6),
'\0'};
// Change the link MAC address.
struct request req = {};
req.hdr.nlmsg_type = GetParam();
req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
req.hdr.nlmsg_seq = kSeq;
req.ifm.ifi_family = AF_UNSPEC;
req.ifm.ifi_index = loopback_link.index;
req.rtattr.rta_type = IFLA_ADDRESS;
req.rtattr.rta_len = RTA_LENGTH(address_size);
strncpy(req.address, address, sizeof(req.address));
req.hdr.nlmsg_len =
NLMSG_LENGTH(sizeof(req.ifm)) + NLMSG_ALIGN(req.rtattr.rta_len);
EXPECT_NO_ERRNO(NetlinkRequestAckOrError(fd, kSeq, &req, sizeof(req)));
loopback_link.address = std::string(address);
// Search the link by its index.
struct searchrequest {
struct nlmsghdr hdr;
struct ifinfomsg ifm;
} search = {};
search.hdr.nlmsg_len = sizeof(search);
search.hdr.nlmsg_type = RTM_GETLINK;
search.hdr.nlmsg_flags = NLM_F_REQUEST;
search.hdr.nlmsg_seq = kSeq;
search.ifm.ifi_family = AF_UNSPEC;
search.ifm.ifi_index = loopback_link.index;
bool found = false;
ASSERT_NO_ERRNO(NetlinkRequestResponse(
fd, &search, sizeof(search),
[&](const struct nlmsghdr* hdr) {
CheckLinkMsg(hdr, loopback_link);
found = true;
},
false));
EXPECT_TRUE(found) << "Netlink response does not contain any links.";
}
TEST(NetlinkRouteTest, LinkUp) {
SKIP_IF(!ASSERT_NO_ERRNO_AND_VALUE(HaveCapability(CAP_NET_ADMIN)));
SKIP_IF(IsRunningWithHostinet());
@@ -285,6 +285,11 @@ PosixErrorOr<std::vector<Link>> DumpLinks() {
links.back().mtu = rta_mtu == nullptr
? 0
: *reinterpret_cast<uint32_t*>(RTA_DATA(rta_mtu));
const auto* rta_address = FindRtAttr(hdr, msg, IFLA_ADDRESS);
links.back().address =
rta_address == nullptr
? ""
: std::string(reinterpret_cast<const char*>(RTA_DATA(rta_address)));
}));
return links;
}
@@ -30,6 +30,7 @@ struct Link {
int16_t type;
std::string name;
uint32_t mtu;
std::string address;
};
PosixError DumpLinks(const FileDescriptor& fd, uint32_t seq,