[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
This commit is contained in:
Song GUO
2022-12-16 02:53:08 -08:00
committed by GitHub
parent 0f3de13ca8
commit 117c8519ec
5 changed files with 111 additions and 25 deletions
+2 -1
View File
@@ -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
};
/**
+1
View File
@@ -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
};
/**
+44 -8
View File
@@ -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<uint8_t *>(&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<Notifier>().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;
+15 -2
View File
@@ -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<Translator, &Translator::HandleMappingExpirerTimer>;
bool mEnabled;
void UpdateState(void);
bool mEnabled;
State mState;
uint64_t mNextMappingId;
+49 -14
View File
@@ -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 <size_t N> 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<nlmsghdr *>(&req), sizeof(req), RTA_DST, data, sizeof(data));
AddRtAttr(reinterpret_cast<nlmsghdr *>(&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