Skip to content

Commit

Permalink
[posix] add multicast address update in netif module (#2447)
Browse files Browse the repository at this point in the history
This commit addes multicast addresses update method of `Netif` module.

This commit contains a small unit test case to verify the
implementation.
  • Loading branch information
Irving-cl authored Aug 26, 2024
1 parent a8f89be commit 626b3f5
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 4 deletions.
61 changes: 61 additions & 0 deletions src/ncp/posix/netif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,65 @@ void Netif::UpdateIp6UnicastAddresses(const std::vector<Ip6AddressInfo> &aAddrIn
mIp6UnicastAddresses.assign(aAddrInfos.begin(), aAddrInfos.end());
}

otbrError Netif::UpdateIp6MulticastAddresses(const std::vector<Ip6Address> &aAddrs)
{
otbrError error = OTBR_ERROR_NONE;

// Remove stale addresses
for (const Ip6Address &address : mIp6MulticastAddresses)
{
if (std::find(aAddrs.begin(), aAddrs.end(), address) == aAddrs.end())
{
otbrLogInfo("Remove address: %s", Ip6Address(address).ToString().c_str());
SuccessOrExit(error = ProcessMulticastAddressChange(address, /* aIsAdded */ false));
}
}

// Add new addresses
for (const Ip6Address &address : aAddrs)
{
if (std::find(mIp6MulticastAddresses.begin(), mIp6MulticastAddresses.end(), address) ==
mIp6MulticastAddresses.end())
{
otbrLogInfo("Add address: %s", Ip6Address(address).ToString().c_str());
SuccessOrExit(error = ProcessMulticastAddressChange(address, /* aIsAdded */ true));
}
}

mIp6MulticastAddresses.assign(aAddrs.begin(), aAddrs.end());

exit:
if (error != OTBR_ERROR_NONE)
{
mIp6MulticastAddresses.clear();
}
return error;
}

otbrError Netif::ProcessMulticastAddressChange(const Ip6Address &aAddress, bool aIsAdded)
{
struct ipv6_mreq mreq;
otbrError error = OTBR_ERROR_NONE;
int err;

VerifyOrExit(mIpFd >= 0, error = OTBR_ERROR_INVALID_STATE);
memcpy(&mreq.ipv6mr_multiaddr, &aAddress, sizeof(mreq.ipv6mr_multiaddr));
mreq.ipv6mr_interface = mNetifIndex;

err = setsockopt(mIpFd, IPPROTO_IPV6, (aIsAdded ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP), &mreq, sizeof(mreq));

if (err != 0)
{
otbrLogWarning("%s failure (%d)", aIsAdded ? "IPV6_JOIN_GROUP" : "IPV6_LEAVE_GROUP", errno);
ExitNow(error = OTBR_ERROR_ERRNO);
}

otbrLogInfo("%s multicast address %s", aIsAdded ? "Added" : "Removed", Ip6Address(aAddress).ToString().c_str());

exit:
return error;
}

void Netif::Clear(void)
{
if (mTunFd != -1)
Expand All @@ -135,6 +194,8 @@ void Netif::Clear(void)
}

mNetifIndex = 0;
mIp6UnicastAddresses.clear();
mIp6MulticastAddresses.clear();
}

} // namespace otbr
11 changes: 7 additions & 4 deletions src/ncp/posix/netif.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class Netif
otbrError Init(const std::string &aInterfaceName);
void Deinit(void);

void UpdateIp6UnicastAddresses(const std::vector<Ip6AddressInfo> &aAddrInfos);
void UpdateIp6UnicastAddresses(const std::vector<Ip6AddressInfo> &aOtAddrInfos);
otbrError UpdateIp6MulticastAddresses(const std::vector<Ip6Address> &aAddrs);

private:
// TODO: Retrieve the Maximum Ip6 size from the coprocessor.
Expand All @@ -63,9 +64,10 @@ class Netif
otbrError CreateTunDevice(const std::string &aInterfaceName);
otbrError InitNetlink(void);

void PlatformSpecificInit(void);
void SetAddrGenModeToNone(void);
void ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded);
void PlatformSpecificInit(void);
void SetAddrGenModeToNone(void);
void ProcessUnicastAddressChange(const Ip6AddressInfo &aAddressInfo, bool aIsAdded);
otbrError ProcessMulticastAddressChange(const Ip6Address &aAddress, bool aIsAdded);

int mTunFd; ///< Used to exchange IPv6 packets.
int mIpFd; ///< Used to manage IPv6 stack on the network interface.
Expand All @@ -76,6 +78,7 @@ class Netif
std::string mNetifName;

std::vector<Ip6AddressInfo> mIp6UnicastAddresses;
std::vector<Ip6Address> mIp6MulticastAddresses;
};

} // namespace otbr
Expand Down
125 changes: 125 additions & 0 deletions tests/gtest/test_netif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,69 @@ std::vector<std::string> GetAllIp6Addrs(const char *aInterfaceName)
return ip6Addrs;
}

static int ParseHex(char *aStr, unsigned char *aAddr)
{
int len = 0;

while (*aStr)
{
int tmp;
if (aStr[1] == 0)
{
return -1;
}
if (sscanf(aStr, "%02x", &tmp) != 1)
{
return -1;
}
aAddr[len] = tmp;
len++;
aStr += 2;
}

return len;
}

std::vector<std::string> GetAllIp6MulAddrs(const char *aInterfaceName)
{
const char *kPathIgmp6 = "/proc/net/igmp6";
std::string line;
std::vector<std::string> ip6MulAddrs;

std::ifstream file(kPathIgmp6);
if (!file.is_open())
{
perror("Cannot open IGMP6 file");
exit(EXIT_FAILURE);
}

while (std::getline(file, line))
{
char interfaceName[256] = {0};
char hexa[256] = {0};
int index;
int users;
unsigned char addr[16];

sscanf(line.c_str(), "%d%s%s%d", &index, interfaceName, hexa, &users);
if (strcmp(interfaceName, aInterfaceName) == 0)
{
char addrStr[INET6_ADDRSTRLEN];
ParseHex(hexa, addr);
if (inet_ntop(AF_INET6, addr, addrStr, sizeof(addrStr)) == NULL)
{
perror("inet_ntop");
exit(EXIT_FAILURE);
}
ip6MulAddrs.emplace_back(addrStr);
}
}

file.close();

return ip6MulAddrs;
}

TEST(Netif, WpanInitWithFullInterfaceName)
{
const char *wpan = "wpan0";
Expand Down Expand Up @@ -297,4 +360,66 @@ TEST(Netif, WpanIfHasCorrectUnicastAddresses_AfterUpdatingUnicastAddresses)

netif.Deinit();
}

TEST(Netif, WpanIfHasCorrectMulticastAddresses_AfterUpdatingMulticastAddresses)
{
const char *wpan = "wpan0";
otbr::Netif netif;
EXPECT_EQ(netif.Init(wpan), OT_ERROR_NONE);

otbr::Ip6Address kDefaultMulAddr1 = {
{0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}};
const char *kDefaultMulAddr1Str = "ff01::1";
const char *kDefaultMulAddr2Str = "ff02::1";
const char *kDefaultMulAddr3Str = "ff02::2";

otbr::Ip6Address kMulAddr1 = {
{0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc}};
otbr::Ip6Address kMulAddr2 = {
{0xff, 0x32, 0x00, 0x40, 0xfd, 0x0d, 0x07, 0xfc, 0xa1, 0xb9, 0xf0, 0x50, 0x00, 0x00, 0x00, 0x01}};
const char *kMulAddr1Str = "ff03::fc";
const char *kMulAddr2Str = "ff32:40:fd0d:7fc:a1b9:f050:0:1";

otbr::Ip6Address testArray1[] = {
kMulAddr1,
};
std::vector<otbr::Ip6Address> testVec1(testArray1, testArray1 + sizeof(testArray1) / sizeof(otbr::Ip6Address));
netif.UpdateIp6MulticastAddresses(testVec1);
std::vector<std::string> wpanMulAddrs = GetAllIp6MulAddrs(wpan);
EXPECT_EQ(wpanMulAddrs.size(), 4);
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr1Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));

otbr::Ip6Address testArray2[] = {kMulAddr1, kMulAddr2};
std::vector<otbr::Ip6Address> testVec2(testArray2, testArray2 + sizeof(testArray2) / sizeof(otbr::Ip6Address));
netif.UpdateIp6MulticastAddresses(testVec2);
wpanMulAddrs = GetAllIp6MulAddrs(wpan);
EXPECT_EQ(wpanMulAddrs.size(), 5);
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr1Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kMulAddr2Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));

otbr::Ip6Address testArray3[] = {kDefaultMulAddr1};
std::vector<otbr::Ip6Address> testVec3(testArray3, testArray3 + sizeof(testArray3) / sizeof(otbr::Ip6Address));
netif.UpdateIp6MulticastAddresses(testVec3);
wpanMulAddrs = GetAllIp6MulAddrs(wpan);
EXPECT_EQ(wpanMulAddrs.size(), 3);
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));

std::vector<otbr::Ip6Address> empty;
netif.UpdateIp6MulticastAddresses(empty);
wpanMulAddrs = GetAllIp6MulAddrs(wpan);
EXPECT_EQ(wpanMulAddrs.size(), 3);
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr1Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr2Str));
EXPECT_THAT(wpanMulAddrs, ::testing::Contains(kDefaultMulAddr3Str));

netif.Deinit();
}
#endif // __linux__

0 comments on commit 626b3f5

Please sign in to comment.