Skip to content

Commit

Permalink
[infra if] add platform infra if module
Browse files Browse the repository at this point in the history
  • Loading branch information
Irving-cl committed Sep 20, 2024
1 parent b9210e7 commit 78df0b9
Show file tree
Hide file tree
Showing 5 changed files with 332 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/ncp/posix/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#

add_library(otbr-posix
infra_if.hpp
infra_if.cpp
netif.cpp
netif_linux.cpp
netif_unix.cpp
Expand Down
158 changes: 158 additions & 0 deletions src/ncp/posix/infra_if.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#define OTBR_LOG_TAG "INFRAIF"

#include "infra_if.hpp"

#include <ifaddrs.h>
#ifdef __linux__
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#endif
#include <netinet/icmp6.h>
#include <sys/ioctl.h>

#include "utils/socket_utils.hpp"

namespace otbr {

otbrError InfraIf::Dependencies::SetInfraIf(uint32_t aInfraIfIndex,
bool aIsRunning,
const std::vector<Ip6Address> &aIp6Addresses)
{
OTBR_UNUSED_VARIABLE(aInfraIfIndex);
OTBR_UNUSED_VARIABLE(aIsRunning);
OTBR_UNUSED_VARIABLE(aIp6Addresses);
return OTBR_ERROR_NONE;
}

InfraIf::InfraIf(Dependencies &aDependencies)
: mDeps(aDependencies)
, mInfraIfIndex(0)
{
}

void InfraIf::Init(void)
{
}

void InfraIf::Deinit(void)
{
mInfraIfIndex = 0;
}

void InfraIf::SetInfraIf(const char *aIfName)
{
std::vector<Ip6Address> addresses;

VerifyOrDie(aIfName != nullptr && strlen(aIfName) > 0, "Invalid infra interface name");
VerifyOrDie(strnlen(aIfName, sizeof(mInfraIfName)) < sizeof(mInfraIfName), "infra interface name is too long!");
strcpy(mInfraIfName, aIfName);

mInfraIfIndex = if_nametoindex(aIfName);
VerifyOrDie(mInfraIfIndex != 0, "Failed to get the index for infra interface");

GetAddresses(addresses);

SuccessOrDie(mDeps.SetInfraIf(mInfraIfIndex, IsRunning(addresses), addresses), "Failed to set infra-if!");
}

bool InfraIf::IsRunning(const std::vector<Ip6Address> &aAddrs) const
{
return mInfraIfIndex ? ((GetFlags() & IFF_RUNNING) && HasLinkLocalAddress(aAddrs)) : false;
}

uint32_t InfraIf::GetFlags(void) const
{
int sock;
struct ifreq ifReq;
uint32_t flags = 0;

sock = SocketWithCloseExec(AF_INET6, SOCK_DGRAM, IPPROTO_IP, kSocketBlock);
VerifyOrDie(sock != -1, otbrErrorString(OTBR_ERROR_ERRNO));

memset(&ifReq, 0, sizeof(ifReq));
static_assert(sizeof(ifReq.ifr_name) >= sizeof(mInfraIfName), "mInfraIfName is not of appropriate size.");
strcpy(ifReq.ifr_name, mInfraIfName);

if (ioctl(sock, SIOCGIFFLAGS, &ifReq) == -1)
{
otbrLogCrit("The infra link %s may be lost. Exiting.", mInfraIfName);
DieNow(otbrErrorString(OTBR_ERROR_ERRNO));
}
flags = static_cast<uint32_t>(ifReq.ifr_flags);

close(sock);
return flags;
}

void InfraIf::GetAddresses(std::vector<Ip6Address> &aAddrs)
{
struct ifaddrs *ifAddrs = nullptr;

if (getifaddrs(&ifAddrs) < 0)
{
otbrLogCrit("failed to get netif addresses: %s", strerror(errno));
DieNow(otbrErrorString(OTBR_ERROR_ERRNO));
}

for (struct ifaddrs *addr = ifAddrs; addr != nullptr; addr = addr->ifa_next)
{
struct sockaddr_in6 *ip6Addr;

if (strncmp(addr->ifa_name, mInfraIfName, sizeof(mInfraIfName)) != 0 || addr->ifa_addr == nullptr ||
addr->ifa_addr->sa_family != AF_INET6)
{
continue;
}

ip6Addr = reinterpret_cast<sockaddr_in6 *>(addr->ifa_addr);
aAddrs.emplace_back(*reinterpret_cast<otIp6Address *>(&ip6Addr->sin6_addr));
}

freeifaddrs(ifAddrs);
}

bool InfraIf::HasLinkLocalAddress(const std::vector<Ip6Address> &aAddrs)
{
bool hasLla = false;

for (const Ip6Address &otAddr : aAddrs)
{
if (IN6_IS_ADDR_LINKLOCAL(reinterpret_cast<const in6_addr *>(&otAddr)))
{
hasLla = true;
break;
}
}

return hasLla;
}

} // namespace otbr
83 changes: 83 additions & 0 deletions src/ncp/posix/infra_if.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

/**
* @file
* This file includes definitions of the Infrastructure network interface of otbr-agent.
*/

#ifndef OTBR_AGENT_POSIX_INFRA_IF_HPP_
#define OTBR_AGENT_POSIX_INFRA_IF_HPP_

#include <net/if.h>

#include <vector>

#include <openthread/ip6.h>

#include "common/types.hpp"

namespace otbr {

/**
* Host infrastructure network interface module.
*
* The infrastructure network interface MUST be explicitly set by `SetInfraIf` before the InfraIf module can work.
*
*/
class InfraIf
{
public:
class Dependencies
{
public:
virtual otbrError SetInfraIf(uint32_t aInfraIfIndex,
bool aIsRunning,
const std::vector<Ip6Address> &aIp6Addresses);
};

InfraIf(Dependencies &aDependencies);

void Init(void);
void Deinit(void);
void SetInfraIf(const char *aIfName);

private:
bool IsRunning(const std::vector<Ip6Address> &aAddrs) const;
uint32_t GetFlags(void) const;
void GetAddresses(std::vector<Ip6Address> &aAddrs);
static bool HasLinkLocalAddress(const std::vector<Ip6Address> &aAddrs);

Dependencies &mDeps;
char mInfraIfName[IFNAMSIZ];
uint32_t mInfraIfIndex;
};

} // namespace otbr

#endif // OTBR_AGENT_POSIX_INFRA_IF_HPP_
1 change: 1 addition & 0 deletions tests/gtest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ if(OTBR_MDNS)
endif()

add_executable(otbr-posix-gtest-unit
test_infraif.cpp
test_netif.cpp
)
target_link_libraries(otbr-posix-gtest-unit
Expand Down
88 changes: 88 additions & 0 deletions tests/gtest/test_infraif.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2024, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "ncp/posix/infra_if.hpp"
#include "ncp/posix/netif.hpp"

// Only Test on linux platform for now.
#ifdef __linux__

class InfraIfDependencyTest : public otbr::InfraIf::Dependencies
{
public:
InfraIfDependencyTest(void)
: mInfraIfIndex(0)
, mIsRunning(false)
{
}

otbrError SetInfraIf(uint32_t aInfraIfIndex,
bool aIsRunning,
const std::vector<otbr::Ip6Address> &aIp6Addresses) override
{
mInfraIfIndex = aInfraIfIndex;
mIsRunning = aIsRunning;
mIp6Addresses = aIp6Addresses;
return OTBR_ERROR_NONE;
}

uint32_t mInfraIfIndex;
bool mIsRunning;
std::vector<otbr::Ip6Address> mIp6Addresses;
};

TEST(InfraIf, DepsSetInfraIfInvokedCorrectly_AfterSpecifyingInfraIf)
{
const std::string fakeInfraIf = "wlx123";

///< Utilize the Netif module to create a network interface as the fake infrastructure interface.
otbr::Netif::Dependencies defaultNetifDep;
otbr::Netif netif(defaultNetifDep);
EXPECT_EQ(netif.Init(fakeInfraIf), OTBR_ERROR_NONE);

const otIp6Address kTestAddr = {
{0xfd, 0x35, 0x7a, 0x7d, 0x0f, 0x16, 0xe7, 0xe3, 0x73, 0xf3, 0x09, 0x00, 0x8e, 0xbe, 0x1b, 0x65}};
std::vector<otbr::Ip6AddressInfo> addrs = {
{kTestAddr, 64, 0, 1, 0},
};
netif.UpdateIp6UnicastAddresses(addrs);

InfraIfDependencyTest testInfraIfDep;
otbr::InfraIf infraIf(testInfraIfDep);
infraIf.SetInfraIf(fakeInfraIf.c_str());

EXPECT_NE(testInfraIfDep.mInfraIfIndex, 0);
EXPECT_EQ(testInfraIfDep.mIsRunning, false);
EXPECT_EQ(testInfraIfDep.mIp6Addresses.size(), 1);
EXPECT_THAT(testInfraIfDep.mIp6Addresses, ::testing::Contains(otbr::Ip6Address(kTestAddr)));
}

#endif // __linux__

0 comments on commit 78df0b9

Please sign in to comment.