From 9106817c624cb514d5f7190e5e7e8ac572221ae6 Mon Sep 17 00:00:00 2001 From: whd <7058128+superwhd@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:33:52 +0800 Subject: [PATCH] [posix] add `otSysSetInfraNetif` API (#9528) This commit adds a new API `otSysSetInfraNetif` to support specifying the infrastructure network interface for the platform. This can be useful in following cases: - The infra link cannot be determined at the start up of `otbr-agent`. We can call this API to specify the infra link without specifying it in the command line arguments. - Let Thread Border Router switch to another infra link without restarting the whole OpenThread stack. --- src/core/border_router/infra_if.cpp | 1 - src/lib/platform/exit_code.h | 6 +++ .../include/openthread/openthread-system.h | 12 +++++ src/posix/platform/infra_if.cpp | 54 +++++++++++-------- src/posix/platform/infra_if.hpp | 23 +++++++- src/posix/platform/system.cpp | 21 ++++++-- 6 files changed, 88 insertions(+), 29 deletions(-) diff --git a/src/core/border_router/infra_if.cpp b/src/core/border_router/infra_if.cpp index 53e4fc2a698..011400c4d84 100644 --- a/src/core/border_router/infra_if.cpp +++ b/src/core/border_router/infra_if.cpp @@ -60,7 +60,6 @@ Error InfraIf::Init(uint32_t aIfIndex) Error error = kErrorNone; VerifyOrExit(!mInitialized, error = kErrorInvalidState); - VerifyOrExit(aIfIndex > 0, error = kErrorInvalidArgs); mIfIndex = aIfIndex; mInitialized = true; diff --git a/src/lib/platform/exit_code.h b/src/lib/platform/exit_code.h index c809eb1d150..4aef8bdd277 100644 --- a/src/lib/platform/exit_code.h +++ b/src/lib/platform/exit_code.h @@ -82,6 +82,12 @@ enum * No response from radio spinel. */ OT_EXIT_RADIO_SPINEL_NO_RESPONSE = 6, + + /** + * Invalid state. + */ + OT_EXIT_INVALID_STATE = 7, + }; /** diff --git a/src/posix/platform/include/openthread/openthread-system.h b/src/posix/platform/include/openthread/openthread-system.h index 7fe2e0ea0d9..820cf2b1f74 100644 --- a/src/posix/platform/include/openthread/openthread-system.h +++ b/src/posix/platform/include/openthread/openthread-system.h @@ -226,6 +226,18 @@ typedef struct otSysInfraNetIfAddressCounters */ void otSysCountInfraNetifAddresses(otSysInfraNetIfAddressCounters *aAddressCounters); +/** + * Sets the infrastructure network interface and the ICMPv6 socket. + * + * This function specifies the network interface name and the ICMPv6 socket on that interface. After calling this + * function, the caller can call otBorderRoutingInit() to let Border Routing work on that interface. + * + * @param[in] aInfraNetifName The name of the infrastructure network interface. + * @param[in] aIcmp6Socket A SOCK_RAW socket running on the infrastructure network interface. + * + */ +void otSysSetInfraNetif(const char *aInfraNetifName, int aIcmp6Socket); + #ifdef __cplusplus } // end of extern "C" #endif diff --git a/src/posix/platform/infra_if.cpp b/src/posix/platform/infra_if.cpp index 505d025704a..e86fdafed65 100644 --- a/src/posix/platform/infra_if.cpp +++ b/src/posix/platform/infra_if.cpp @@ -123,9 +123,8 @@ void otSysCountInfraNetifAddresses(otSysInfraNetIfAddressCounters *aAddressCount namespace ot { namespace Posix { -namespace { -int CreateIcmp6Socket(void) +int InfraNetif::CreateIcmp6Socket(const char *aInfraIfName) { int sock; int rval; @@ -168,6 +167,13 @@ int CreateIcmp6Socket(void) rval = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &kHopLimit, sizeof(kHopLimit)); VerifyOrDie(rval == 0, OT_EXIT_ERROR_ERRNO); +#ifdef __linux__ + rval = setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, aInfraIfName, strlen(aInfraIfName)); +#else // __NetBSD__ || __FreeBSD__ || __APPLE__ + rval = setsockopt(mInfraIfIcmp6Socket, IPPROTO_IPV6, IPV6_BOUND_IF, &mInfraIfIndex, sizeof(mInfraIfIndex)); +#endif // __linux__ + VerifyOrDie(rval == 0, OT_EXIT_ERROR_ERRNO); + return sock; } @@ -200,8 +206,6 @@ int CreateNetLinkSocket(void) return sock; } -} // namespace - otError InfraNetif::SendIcmp6Nd(uint32_t aInfraIfIndex, const otIp6Address &aDestAddress, const uint8_t *aBuffer, @@ -276,7 +280,10 @@ otError InfraNetif::SendIcmp6Nd(uint32_t aInfraIfIndex, return error; } -bool InfraNetif::IsRunning(void) const { return (GetFlags() & IFF_RUNNING) && HasLinkLocalAddress(); } +bool InfraNetif::IsRunning(void) const +{ + return mInfraIfIndex ? ((GetFlags() & IFF_RUNNING) && HasLinkLocalAddress()) : false; +} uint32_t InfraNetif::GetFlags(void) const { @@ -368,10 +375,18 @@ bool InfraNetif::HasLinkLocalAddress(void) const return hasLla; } -void InfraNetif::Init(const char *aIfName) +void InfraNetif::Init(void) { mNetLinkSocket = CreateNetLinkSocket(); } + +void InfraNetif::SetInfraNetif(const char *aIfName, int aIcmp6Socket) { - ssize_t rval; - uint32_t ifIndex = 0; + uint32_t ifIndex = 0; + otBorderRoutingState state = otBorderRoutingGetState(gInstance); + + OT_ASSERT(gInstance != nullptr); + + VerifyOrDie(mNetLinkSocket != -1, OT_EXIT_INVALID_STATE); + VerifyOrDie(state == OT_BORDER_ROUTING_STATE_UNINITIALIZED || state == OT_BORDER_ROUTING_STATE_DISABLED, + OT_EXIT_INVALID_STATE); if (aIfName == nullptr || aIfName[0] == '\0') { @@ -389,17 +404,14 @@ void InfraNetif::Init(const char *aIfName) otLogCritPlat("Failed to get the index for infra interface %s", aIfName); DieNow(OT_EXIT_INVALID_ARGUMENTS); } - mInfraIfIndex = ifIndex; - mInfraIfIcmp6Socket = CreateIcmp6Socket(); -#ifdef __linux__ - rval = setsockopt(mInfraIfIcmp6Socket, SOL_SOCKET, SO_BINDTODEVICE, mInfraIfName, strlen(mInfraIfName)); -#else // __NetBSD__ || __FreeBSD__ || __APPLE__ - rval = setsockopt(mInfraIfIcmp6Socket, IPPROTO_IPV6, IPV6_BOUND_IF, &mInfraIfIndex, sizeof(mInfraIfIndex)); -#endif // __linux__ - VerifyOrDie(rval == 0, OT_EXIT_ERROR_ERRNO); + mInfraIfIndex = ifIndex; - mNetLinkSocket = CreateNetLinkSocket(); + if (mInfraIfIcmp6Socket != -1) + { + close(mInfraIfIcmp6Socket); + } + mInfraIfIcmp6Socket = aIcmp6Socket; exit: return; @@ -408,7 +420,7 @@ void InfraNetif::Init(const char *aIfName) void InfraNetif::SetUp(void) { OT_ASSERT(gInstance != nullptr); - VerifyOrExit(mInfraIfIndex != 0); + VerifyOrExit(mNetLinkSocket != -1); SuccessOrDie(otBorderRoutingInit(gInstance, mInfraIfIndex, platformInfraIfIsRunning())); SuccessOrDie(otBorderRoutingSetEnabled(gInstance, /* aEnabled */ true)); @@ -419,12 +431,8 @@ void InfraNetif::SetUp(void) void InfraNetif::TearDown(void) { - VerifyOrExit(mInfraIfIndex != 0); - + IgnoreError(otBorderRoutingSetEnabled(gInstance, false)); Mainloop::Manager::Get().Remove(*this); - -exit: - return; } void InfraNetif::Deinit(void) diff --git a/src/posix/platform/infra_if.hpp b/src/posix/platform/infra_if.hpp index b0be452f640..b468e10a1ae 100644 --- a/src/posix/platform/infra_if.hpp +++ b/src/posix/platform/infra_if.hpp @@ -71,12 +71,21 @@ class InfraNetif : public Mainloop::Source, private NonCopyable /** * Initializes the infrastructure network interface. * + * To specify the infrastructure network interface, you need to call SetInfraNetif() after Init(). + * * @note This method is called before OpenThread instance is created. * - * @param[in] aIfName A pointer to infrastructure network interface name. + */ + void Init(void); + + /** + * Sets the infrastructure network interface. + * + * @param[in] aIfName A pointer to infrastructure network interface name. + * @param[in] aIcmp6Socket A SOCK_RAW socket for sending/receiving ICMPv6 messages. * */ - void Init(const char *aIfName); + void SetInfraNetif(const char *aIfName, int aIcmp6Socket); /** * Sets up the infrastructure network interface. @@ -175,6 +184,16 @@ class InfraNetif : public Mainloop::Source, private NonCopyable */ static InfraNetif &Get(void); + /** + * Creates a socket for sending/receiving ICMPv6 messages. + * + * @param[in] aInfraIfName The infrastructure network interface name. + * + * @returns The file descriptor of the socket. + * + */ + static int CreateIcmp6Socket(const char *aInfraIfName); + private: static const char kWellKnownIpv4OnlyName[]; // "ipv4only.arpa" static const otIp4Address kWellKnownIpv4OnlyAddress1; // 192.0.0.170 diff --git a/src/posix/platform/system.cpp b/src/posix/platform/system.cpp index c52dea1255d..a154ff829f0 100644 --- a/src/posix/platform/system.cpp +++ b/src/posix/platform/system.cpp @@ -121,6 +121,13 @@ static const char *getTrelRadioUrl(otPlatformConfig *aPlatformConfig) } #endif +#if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE +void otSysSetInfraNetif(const char *aInfraNetifName, int aIcmp6Socket) +{ + ot::Posix::InfraNetif::Get().SetInfraNetif(aInfraNetifName, aIcmp6Socket); +} +#endif + void platformInit(otPlatformConfig *aPlatformConfig) { #if OPENTHREAD_POSIX_CONFIG_BACKTRACE_ENABLE @@ -143,7 +150,8 @@ void platformInit(otPlatformConfig *aPlatformConfig) #endif #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE - ot::Posix::InfraNetif::Get().Init(aPlatformConfig->mBackboneInterfaceName); + ot::Posix::InfraNetif::Get().Init(); + #endif gNetifName[0] = '\0'; @@ -164,8 +172,10 @@ void platformInit(otPlatformConfig *aPlatformConfig) return; } -void platformSetUp(void) +void platformSetUp(otPlatformConfig *aPlatformConfig) { + OT_UNUSED_VARIABLE(aPlatformConfig); + VerifyOrExit(!gDryRun); #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE @@ -173,6 +183,11 @@ void platformSetUp(void) #endif #if OPENTHREAD_POSIX_CONFIG_INFRA_IF_ENABLE + if (aPlatformConfig->mBackboneInterfaceName != nullptr && strlen(aPlatformConfig->mBackboneInterfaceName) > 0) + { + otSysSetInfraNetif(aPlatformConfig->mBackboneInterfaceName, + ot::Posix::InfraNetif::CreateIcmp6Socket(aPlatformConfig->mBackboneInterfaceName)); + } ot::Posix::InfraNetif::Get().SetUp(); #endif @@ -206,7 +221,7 @@ otInstance *otSysInit(otPlatformConfig *aPlatformConfig) gInstance = otInstanceInitSingle(); OT_ASSERT(gInstance != nullptr); - platformSetUp(); + platformSetUp(aPlatformConfig); return gInstance; }