From 117c8519eceb430ba0bec503c6b0fc17418dfa8f Mon Sep 17 00:00:00 2001 From: Song GUO Date: Fri, 16 Dec 2022 18:53:08 +0800 Subject: [PATCH] [posix] add / delete route to NAT64 CIDR according to NAT64 translator state (#8505) Adds a callback for platform getting adding / removing the NAT64 route when NAT64 translator is enabled / disabled. The cases of adding / removing routes to NAT64 CIDR: - NAT64 inactive -> active: - interface down: noop - interface up: add route - NAT64 active -> inactive: - interface down: noop - interface up: delete route - interface down -> up: - NAT64 enabled: add route - NAT64 disabled: noop - interface up -> down: - Noop, kernel will delete all routes on the interface --- include/openthread/instance.h | 3 +- src/core/common/notifier.hpp | 1 + src/core/net/nat64_translator.cpp | 52 +++++++++++++++++++++---- src/core/net/nat64_translator.hpp | 17 ++++++++- src/posix/platform/netif.cpp | 63 ++++++++++++++++++++++++------- 5 files changed, 111 insertions(+), 25 deletions(-) diff --git a/include/openthread/instance.h b/include/openthread/instance.h index aac927475..f77dbf204 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (268) +#define OPENTHREAD_API_VERSION (269) /** * @addtogroup api-instance @@ -196,6 +196,7 @@ enum OT_CHANGED_JOINER_STATE = 1 << 27, ///< Joiner state changed OT_CHANGED_ACTIVE_DATASET = 1 << 28, ///< Active Operational Dataset changed OT_CHANGED_PENDING_DATASET = 1 << 29, ///< Pending Operational Dataset changed + OT_CHANGED_NAT64_TRANSLATOR_STATE = 1 << 30, ///< The state of NAT64 translator changed }; /** diff --git a/src/core/common/notifier.hpp b/src/core/common/notifier.hpp index 01cd83f31..b3e4b56b4 100644 --- a/src/core/common/notifier.hpp +++ b/src/core/common/notifier.hpp @@ -95,6 +95,7 @@ enum Event : uint32_t kEventJoinerStateChanged = OT_CHANGED_JOINER_STATE, ///< Joiner state changed kEventActiveDatasetChanged = OT_CHANGED_ACTIVE_DATASET, ///< Active Dataset changed kEventPendingDatasetChanged = OT_CHANGED_PENDING_DATASET, ///< Pending Dataset changed + kEventNat64TranslatorStateChanged = OT_CHANGED_NAT64_TRANSLATOR_STATE, ///< Nat64Translator state changed }; /** diff --git a/src/core/net/nat64_translator.cpp b/src/core/net/nat64_translator.cpp index a72d89dc8..d21ba15e1 100644 --- a/src/core/net/nat64_translator.cpp +++ b/src/core/net/nat64_translator.cpp @@ -48,9 +48,26 @@ namespace Nat64 { RegisterLogModule("Nat64"); +const char *StateToString(State aState) +{ + static const char *const kStateString[] = { + "Disabled", + "NotRunning", + "Idle", + "Active", + }; + + static_assert(0 == kStateDisabled, "kStateDisabled value is incorrect"); + static_assert(1 == kStateNotRunning, "kStateNotRunning value is incorrect"); + static_assert(2 == kStateIdle, "kStateIdle value is incorrect"); + static_assert(3 == kStateActive, "kStateActive value is incorrect"); + + return kStateString[aState]; +} + Translator::Translator(Instance &aInstance) : InstanceLocator(aInstance) - , mEnabled(false) + , mState(State::kStateDisabled) , mMappingExpirerTimer(aInstance) { Random::NonCrypto::FillBuffer(reinterpret_cast(&mNextMappingId), sizeof(mNextMappingId)); @@ -490,6 +507,8 @@ Error Translator::SetIp4Cidr(const Ip4::Cidr &aCidr) numberOfHosts); mIp4Cidr = aCidr; + UpdateState(); + exit: return err; } @@ -501,6 +520,8 @@ void Translator::SetNat64Prefix(const Ip6::Prefix &aNat64Prefix) LogInfo("IPv6 Prefix for NAT64 updated to %s", aNat64Prefix.ToString().AsCString()); mNat64Prefix = aNat64Prefix; } + + UpdateState(); } void Translator::HandleMappingExpirerTimer(void) @@ -596,16 +617,31 @@ void Translator::ProtocolCounters::Count4To6Packet(uint8_t aProtocol, uint64_t a mTotal.m4To6Bytes += aPacketSize; } -State Translator::GetState(void) const +void Translator::UpdateState(void) { - State ret = kStateDisabled; + State newState; - VerifyOrExit(mEnabled); - VerifyOrExit(mIp4Cidr.mLength > 0 && mNat64Prefix.IsValidNat64(), ret = kStateNotRunning); - ret = kStateActive; + if (mEnabled) + { + if (mIp4Cidr.mLength > 0 && mNat64Prefix.IsValidNat64()) + { + newState = kStateActive; + } + else + { + newState = kStateNotRunning; + } + } + else + { + newState = kStateDisabled; + } + + SuccessOrExit(Get().Update(mState, newState, kEventNat64TranslatorStateChanged)); + LogInfo("NAT64 translator is now %s", StateToString(mState)); exit: - return ret; + return; } void Translator::SetEnabled(bool aEnabled) @@ -618,7 +654,7 @@ void Translator::SetEnabled(bool aEnabled) ReleaseMappings(mActiveAddressMappings); } - LogInfo("NAT64 translator %s", aEnabled ? "enabled" : "disabled"); + UpdateState(); exit: return; diff --git a/src/core/net/nat64_translator.hpp b/src/core/net/nat64_translator.hpp index 3eea9938b..689731fe3 100644 --- a/src/core/net/nat64_translator.hpp +++ b/src/core/net/nat64_translator.hpp @@ -56,6 +56,16 @@ enum State : uint8_t kStateActive = OT_NAT64_STATE_ACTIVE, ///< The component is running. }; +/** + * This function converts a `State` into a string. + * + * @param[in] aState A state. + * + * @returns A string representation of @p aState. + * + */ +const char *StateToString(State aState); + #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE /** @@ -166,7 +176,7 @@ public: * @retval kNat64StateActive The translator is translating packets. * */ - State GetState(void) const; + State GetState(void) const { return mState; } /** * This method translates an IPv4 datagram to an IPv6 datagram and sends it via Thread interface. @@ -364,7 +374,10 @@ private: using MappingTimer = TimerMilliIn; - bool mEnabled; + void UpdateState(void); + + bool mEnabled; + State mState; uint64_t mNextMappingId; diff --git a/src/posix/platform/netif.cpp b/src/posix/platform/netif.cpp index 56f12062a..5b23f617d 100644 --- a/src/posix/platform/netif.cpp +++ b/src/posix/platform/netif.cpp @@ -618,8 +618,7 @@ exit: return error; } -#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE || OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE -static otError DeleteRoute(const otIp6Prefix &aPrefix) +template otError DeleteRoute(const uint8_t (&aAddress)[N], uint8_t aPrefixLen) { constexpr unsigned int kBufSize = 512; struct @@ -628,10 +627,10 @@ static otError DeleteRoute(const otIp6Prefix &aPrefix) struct rtmsg msg; char buf[kBufSize]; } req{}; - unsigned char data[sizeof(in6_addr)]; - char addrBuf[OT_IP6_ADDRESS_STRING_SIZE]; - unsigned int netifIdx = otSysGetThreadNetifIndex(); - otError error = OT_ERROR_NONE; + unsigned int netifIdx = otSysGetThreadNetifIndex(); + otError error = OT_ERROR_NONE; + + static_assert(N == sizeof(in6_addr) || N == sizeof(in_addr), "aAddress should be 4 octets or 16 octets"); VerifyOrExit(netifIdx > 0, error = OT_ERROR_INVALID_STATE); VerifyOrExit(sNetlinkFd >= 0, error = OT_ERROR_INVALID_STATE); @@ -643,9 +642,9 @@ static otError DeleteRoute(const otIp6Prefix &aPrefix) req.header.nlmsg_pid = 0; req.header.nlmsg_seq = ++sNetlinkSequence; - req.msg.rtm_family = AF_INET6; + req.msg.rtm_family = (N == sizeof(in6_addr) ? AF_INET6 : AF_INET); req.msg.rtm_src_len = 0; - req.msg.rtm_dst_len = aPrefix.mLength; + req.msg.rtm_dst_len = aPrefixLen; req.msg.rtm_tos = 0; req.msg.rtm_scope = RT_SCOPE_UNIVERSE; req.msg.rtm_type = RTN_UNICAST; @@ -653,9 +652,7 @@ static otError DeleteRoute(const otIp6Prefix &aPrefix) req.msg.rtm_protocol = RTPROT_BOOT; req.msg.rtm_flags = 0; - otIp6AddressToString(&aPrefix.mPrefix, addrBuf, OT_IP6_ADDRESS_STRING_SIZE); - inet_pton(AF_INET6, addrBuf, data); - AddRtAttr(reinterpret_cast(&req), sizeof(req), RTA_DST, data, sizeof(data)); + AddRtAttr(reinterpret_cast(&req), sizeof(req), RTA_DST, &aAddress, sizeof(aAddress)); AddRtAttrUint32(&req.header, sizeof(req), RTA_OIF, netifIdx); if (send(sNetlinkFd, &req, sizeof(req), 0) < 0) @@ -668,10 +665,16 @@ exit: return error; } +#if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE || OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE static otError AddRoute(const otIp6Prefix &aPrefix, uint32_t aPriority) { return AddRoute(aPrefix.mPrefix.mFields.m8, aPrefix.mLength, aPriority); } + +static otError DeleteRoute(const otIp6Prefix &aPrefix) +{ + return DeleteRoute(aPrefix.mPrefix.mFields.m8, aPrefix.mLength); +} #endif // OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE || OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE #if OPENTHREAD_POSIX_CONFIG_INSTALL_OMR_ROUTES_ENABLE @@ -855,9 +858,14 @@ exit: #endif // OPENTHREAD_POSIX_CONFIG_INSTALL_EXTERNAL_ROUTES_ENABLE #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE -static otError AddIp4Route(const otIp4Cidr &aCidr, uint32_t aPriority) +static otError AddIp4Route(const otIp4Cidr &aIp4Cidr, uint32_t aPriority) { - return AddRoute(aCidr.mAddress.mFields.m8, aCidr.mLength, aPriority); + return AddRoute(aIp4Cidr.mAddress.mFields.m8, aIp4Cidr.mLength, aPriority); +} + +static otError DeleteIp4Route(const otIp4Cidr &aIp4Cidr) +{ + return DeleteRoute(aIp4Cidr.mAddress.mFields.m8, aIp4Cidr.mLength); } #endif #endif // defined(__linux__) @@ -874,6 +882,28 @@ static void processAddressChange(const otIp6AddressInfo *aAddressInfo, bool aIsA } } +#if defined(__linux__) && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE +void processNat64StateChange(otNat64State aNewState) +{ + // If the interface is not up and we are enabling NAT64, the route will be added when we bring up the route. + // Also, the route will be deleted by the kernel when we shutting down the interface. + // We should try to add route first, since otNat64SetEnabled never fails. + if (otIp6IsEnabled(gInstance)) + { + if (aNewState == OT_NAT64_STATE_ACTIVE) + { + AddIp4Route(gNat64Cidr, kNat64RoutePriority); + otLogInfoPlat("[netif] Adding route for NAT64"); + } + else + { + DeleteIp4Route(gNat64Cidr); + otLogInfoPlat("[netif] Deleting route for NAT64"); + } + } +} +#endif // defined(__linux__) && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE + void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags) { if (OT_CHANGED_THREAD_NETIF_STATE & aFlags) @@ -892,6 +922,12 @@ void platformNetifStateChange(otInstance *aInstance, otChangedFlags aFlags) ot::Posix::UpdateIpSets(aInstance); #endif } +#if defined(__linux__) && OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE + if (OT_CHANGED_NAT64_TRANSLATOR_STATE & aFlags) + { + processNat64StateChange(otNat64GetTranslatorState(aInstance)); + } +#endif } static void processReceive(otMessage *aMessage, void *aContext) @@ -1161,7 +1197,6 @@ static void processNetifLinkEvent(otInstance *aInstance, struct nlmsghdr *aNetli if (isUp && gNat64Cidr.mLength > 0) { SuccessOrExit(error = otNat64SetIp4Cidr(gInstance, &gNat64Cidr)); - AddIp4Route(gNat64Cidr, kNat64RoutePriority); otLogInfoPlat("[netif] Succeeded to enable NAT64"); } #endif