From 78df0b92a8aabcf2a1d25de550aaf95a98932242 Mon Sep 17 00:00:00 2001 From: Li Cao Date: Sat, 14 Sep 2024 17:09:23 +0800 Subject: [PATCH] [infra if] add platform infra if module --- src/ncp/posix/CMakeLists.txt | 2 + src/ncp/posix/infra_if.cpp | 158 +++++++++++++++++++++++++++++++++++ src/ncp/posix/infra_if.hpp | 83 ++++++++++++++++++ tests/gtest/CMakeLists.txt | 1 + tests/gtest/test_infraif.cpp | 88 +++++++++++++++++++ 5 files changed, 332 insertions(+) create mode 100644 src/ncp/posix/infra_if.cpp create mode 100644 src/ncp/posix/infra_if.hpp create mode 100644 tests/gtest/test_infraif.cpp diff --git a/src/ncp/posix/CMakeLists.txt b/src/ncp/posix/CMakeLists.txt index 1f03fd3c18c..7b8557bb1ce 100644 --- a/src/ncp/posix/CMakeLists.txt +++ b/src/ncp/posix/CMakeLists.txt @@ -27,6 +27,8 @@ # add_library(otbr-posix + infra_if.hpp + infra_if.cpp netif.cpp netif_linux.cpp netif_unix.cpp diff --git a/src/ncp/posix/infra_if.cpp b/src/ncp/posix/infra_if.cpp new file mode 100644 index 00000000000..6b1fc11b446 --- /dev/null +++ b/src/ncp/posix/infra_if.cpp @@ -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 +#ifdef __linux__ +#include +#include +#endif +#include +#include + +#include "utils/socket_utils.hpp" + +namespace otbr { + +otbrError InfraIf::Dependencies::SetInfraIf(uint32_t aInfraIfIndex, + bool aIsRunning, + const std::vector &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 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 &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(ifReq.ifr_flags); + + close(sock); + return flags; +} + +void InfraIf::GetAddresses(std::vector &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(addr->ifa_addr); + aAddrs.emplace_back(*reinterpret_cast(&ip6Addr->sin6_addr)); + } + + freeifaddrs(ifAddrs); +} + +bool InfraIf::HasLinkLocalAddress(const std::vector &aAddrs) +{ + bool hasLla = false; + + for (const Ip6Address &otAddr : aAddrs) + { + if (IN6_IS_ADDR_LINKLOCAL(reinterpret_cast(&otAddr))) + { + hasLla = true; + break; + } + } + + return hasLla; +} + +} // namespace otbr diff --git a/src/ncp/posix/infra_if.hpp b/src/ncp/posix/infra_if.hpp new file mode 100644 index 00000000000..263a88c663b --- /dev/null +++ b/src/ncp/posix/infra_if.hpp @@ -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 + +#include + +#include + +#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 &aIp6Addresses); + }; + + InfraIf(Dependencies &aDependencies); + + void Init(void); + void Deinit(void); + void SetInfraIf(const char *aIfName); + +private: + bool IsRunning(const std::vector &aAddrs) const; + uint32_t GetFlags(void) const; + void GetAddresses(std::vector &aAddrs); + static bool HasLinkLocalAddress(const std::vector &aAddrs); + + Dependencies &mDeps; + char mInfraIfName[IFNAMSIZ]; + uint32_t mInfraIfIndex; +}; + +} // namespace otbr + +#endif // OTBR_AGENT_POSIX_INFRA_IF_HPP_ diff --git a/tests/gtest/CMakeLists.txt b/tests/gtest/CMakeLists.txt index f9674ed6946..8710342d562 100644 --- a/tests/gtest/CMakeLists.txt +++ b/tests/gtest/CMakeLists.txt @@ -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 diff --git a/tests/gtest/test_infraif.cpp b/tests/gtest/test_infraif.cpp new file mode 100644 index 00000000000..c45aa0602c3 --- /dev/null +++ b/tests/gtest/test_infraif.cpp @@ -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 +#include + +#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 &aIp6Addresses) override + { + mInfraIfIndex = aInfraIfIndex; + mIsRunning = aIsRunning; + mIp6Addresses = aIp6Addresses; + return OTBR_ERROR_NONE; + } + + uint32_t mInfraIfIndex; + bool mIsRunning; + std::vector 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 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__