[nat64] add runtime switch for NAT64 prefix publisher and translator (#8194)

This commit is contained in:
Song GUO
2022-10-18 14:42:25 -07:00
committed by GitHub
parent 77fd973a76
commit aae250af89
13 changed files with 541 additions and 29 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs. * @note This number versions both OpenThread platform and user APIs.
* *
*/ */
#define OPENTHREAD_API_VERSION (251) #define OPENTHREAD_API_VERSION (252)
/** /**
* @addtogroup api-instance * @addtogroup api-instance
+67
View File
@@ -226,6 +226,73 @@ otError otNat64GetNextAddressMapping(otInstance * aInstance,
otNat64AddressMappingIterator *aIterator, otNat64AddressMappingIterator *aIterator,
otNat64AddressMapping * aMapping); otNat64AddressMapping * aMapping);
/**
* States of NAT64.
*
*/
typedef enum
{
OT_NAT64_STATE_DISABLED = 0, ///< NAT64 is disabled.
OT_NAT64_STATE_NOT_RUNNING, ///< NAT64 is enabled, but one or more dependencies of NAT64 are not running.
OT_NAT64_STATE_IDLE, ///< NAT64 is enabled, but this BR is not an active NAT64 BR.
OT_NAT64_STATE_ACTIVE, ///< The BR is publishing a NAT64 prefix and/or translating packets.
} otNat64State;
/**
* Gets the state of NAT64 translator.
*
* Available when `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_NAT64_STATE_DISABLED NAT64 translator is disabled.
* @retval OT_NAT64_STATE_NOT_RUNNING NAT64 translator is enabled, but the translator is not configured with a valid
* NAT64 prefix and a CIDR.
* @retval OT_NAT64_STATE_ACTIVE NAT64 translator is enabled, and is translating packets.
*
*/
otNat64State otNat64GetTranslatorState(otInstance *aInstance);
/**
* Gets the state of NAT64 prefix manager.
*
* Available when `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_NAT64_STATE_DISABLED NAT64 prefix manager is disabled.
* @retval OT_NAT64_STATE_NOT_RUNNING NAT64 prefix manager is enabled, but is not running (because the routing manager
* is not running).
* @retval OT_NAT64_STATE_IDLE NAT64 prefix manager is enabled, but is not publishing a NAT64 prefix. Usually
* when there is another border router publishing a NAT64 prefix with higher
* priority.
* @retval OT_NAT64_STATE_ACTIVE NAT64 prefix manager is enabled, and is publishing NAT64 prefix to the Thread
* network.
*
*/
otNat64State otNat64GetPrefixManagerState(otInstance *aInstance);
/**
* Enable or disable NAT64 functions.
*
* Note: This includes the NAT64 Translator (when `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled) and the NAT64
* Prefix Manager (when `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is enabled).
*
* When `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled, setting disabled to true resets the
* mapping table in the translator.
*
* Available when `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` or `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is
* enabled.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aEnabled A boolean to enable/disable the NAT64 functions
*
* @sa otNat64GetTranslatorState
* @sa otNat64GetPrefixManagerState
*
*/
void otNat64SetEnabled(otInstance *aInstance, bool aEnable);
/** /**
* Allocate a new message buffer for sending an IPv4 message to the NAT64 translator. * Allocate a new message buffer for sending an IPv4 message to the NAT64 translator.
* *
+65 -3
View File
@@ -1855,7 +1855,7 @@ Done
Gets the IPv4 configured CIDR in the NAT64 translator. Gets the IPv4 configured CIDR in the NAT64 translator.
This command is only available when device enables NAT64 translator. `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is required.
```bash ```bash
> nat64 cidr > nat64 cidr
@@ -1863,11 +1863,73 @@ This command is only available when device enables NAT64 translator.
Done Done
``` ```
### nat64 disable
Disable NAT64 functions, including the translator and the prefix publishing.
This command will reset the mapping table in the translator (if NAT64 translator is enabled in the build).
`OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` or `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` are required.
```bash
> nat64 disable
Done
```
### nat64 enable
Enable NAT64 functions, including the translator and the prefix publishing.
This command can be called anytime.
`OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` or `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` are required.
```bash
> nat64 enable
Done
```
### nat64 state
Gets the state of NAT64 functions.
Possible results for prefix manager are (`OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is required):
- `Disabled`: NAT64 prefix manager is disabled.
- `NotRunning`: NAT64 prefix manager is enabled, but is not running, probably bacause the routing manager is disabled.
- `Idle`: NAT64 prefix manager is enabled and is running, but is not publishing a NAT64 prefix. Usually when there is another border router publishing a NAT64 prefix with higher priority.
- `Active`: NAT64 prefix manager is enabled, running and publishing a NAT64 prefix.
Possible results for NAT64 translator are (`OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is required):
- `Disabled`: NAT64 translator is disabled.
- `NotRunning`: NAT64 translator is enabled, but is not translating packets, probably bacause it is not configued with a NAT64 prefix or a CIDR for NAT64.
- `Active`: NAT64 translator is enabled and is translating packets.
`OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` or `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` are required.
```bash
> nat64 state
PrefixManager: NotRunning
Translator: NotRunning
Done
> nat64 state
PrefixManager: Idle
Translator: NotRunning
Done
> nat64 state
PrefixManager: Active
Translator: Active
Done
```
### nat64 mappings ### nat64 mappings
Get the NAT64 translator mappings. Get the NAT64 translator mappings.
This command is only available when device enables NAT64 translator. `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is required.
```bash ```bash
> nat64 mappings > nat64 mappings
@@ -1885,7 +1947,7 @@ This command is only available when device enables NAT64 translator.
Get the NAT64 translator packet and error counters. Get the NAT64 translator packet and error counters.
This command is only available when device enables NAT64 translator. `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is required.
```bash ```bash
> nat64 counters > nat64 counters
+74 -4
View File
@@ -84,7 +84,7 @@
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE #if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
#include <openthread/trel.h> #include <openthread/trel.h>
#endif #endif
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
#include <openthread/nat64.h> #include <openthread/nat64.h>
#endif #endif
@@ -735,15 +735,84 @@ exit:
} }
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE #endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[]) template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[])
{ {
otError error = OT_ERROR_NONE; otError error = OT_ERROR_NONE;
bool enable;
if (aArgs[0].IsEmpty()) if (aArgs[0].IsEmpty())
{ {
ExitNow(error = OT_ERROR_INVALID_COMMAND); ExitNow(error = OT_ERROR_INVALID_COMMAND);
} }
/**
* @cli nat64 (enable,disable)
* @code
* nat64 enable
* Done
* @endcode
* @code
* nat64 disable
* Done
* @endcode
* @cparam nat64 @ca{enable|disable}
* @par api_copy
* #otNat64SetEnabled
*
*/
if (ParseEnableOrDisable(aArgs[0], enable) == OT_ERROR_NONE)
{
otNat64SetEnabled(GetInstancePtr(), enable);
}
/**
* @cli nat64 state
* @code
* nat64 state
* PrefixManager: Active
* Translator: Active
* Done
* @endcode
* @par
* Gets the state of NAT64 functions.
* @par
* `PrefixManager` state is available when `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is enabled.
* `Translator` state is available when `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled.
* @par
* When `OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE` is enabled, `PrefixManager` returns one of the following
* states:
* - `Disabled`: NAT64 prefix manager is disabled.
* - `NotRunning`: NAT64 prefix manager is enabled, but is not running. This could mean that the routing manager is
* disabled.
* - `Idle`: NAT64 prefix manager is enabled and is running, but is not publishing a NAT64 prefix. This can happen
* when there is another border router publishing a NAT64 prefix with a higher priority.
* - `Active`: NAT64 prefix manager is enabled, running, and publishing a NAT64 prefix.
* @par
* When `OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is enabled, `Translator` returns one of the following states:
* - `Disabled`: NAT64 translator is disabled.
* - `NotRunning`: NAT64 translator is enabled, but is not translating packets. This could mean that the Translator
* is not configured with a NAT64 prefix or a CIDR for NAT64.
* - `Active`: NAT64 translator is enabled and is translating packets.
* @sa otNat64GetPrefixManagerState
* @sa otNat64GetTranslatorState
*
*/
else if (aArgs[0] == "state")
{
static const char *const kNat64State[] = {"Disabled", "NotRunning", "Idle", "Active"};
static_assert(0 == OT_NAT64_STATE_DISABLED, "OT_NAT64_STATE_DISABLED value is incorrect");
static_assert(1 == OT_NAT64_STATE_NOT_RUNNING, "OT_NAT64_STATE_NOT_RUNNING value is incorrect");
static_assert(2 == OT_NAT64_STATE_IDLE, "OT_NAT64_STATE_IDLE value is incorrect");
static_assert(3 == OT_NAT64_STATE_ACTIVE, "OT_NAT64_STATE_ACTIVE value is incorrect");
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
OutputLine("PrefixManager: %s", kNat64State[otNat64GetPrefixManagerState(GetInstancePtr())]);
#endif
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
OutputLine("Translator: %s", kNat64State[otNat64GetTranslatorState(GetInstancePtr())]);
#endif
}
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
/** /**
* @cli nat64 cidr * @cli nat64 cidr
* @code * @code
@@ -932,6 +1001,7 @@ template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[])
errorCounters.mCount6To4[i]); errorCounters.mCount6To4[i]);
} }
} }
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
else else
{ {
ExitNow(error = OT_ERROR_INVALID_COMMAND); ExitNow(error = OT_ERROR_INVALID_COMMAND);
@@ -940,7 +1010,7 @@ template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[])
exit: exit:
return error; return error;
} }
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
#if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
template <> otError Interpreter::Process<Cmd("bbr")>(Arg aArgs[]) template <> otError Interpreter::Process<Cmd("bbr")>(Arg aArgs[])
@@ -7091,7 +7161,7 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
#endif #endif
CmdEntry("mode"), CmdEntry("mode"),
CmdEntry("multiradio"), CmdEntry("multiradio"),
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
CmdEntry("nat64"), CmdEntry("nat64"),
#endif #endif
#if OPENTHREAD_FTD #if OPENTHREAD_FTD
+30
View File
@@ -46,6 +46,12 @@
using namespace ot; using namespace ot;
// Note: We support the following scenrios:
// - Using OpenThread's routing manager, while using external NAT64 translator (like tayga).
// - Using OpenThread's NAT64 translator, while using external routing manager.
// So OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE translator and OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE are two
// separate build flags and they are not depending on each other.
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
otError otNat64SetIp4Cidr(otInstance *aInstance, const otIp4Cidr *aCidr) otError otNat64SetIp4Cidr(otInstance *aInstance, const otIp4Cidr *aCidr)
{ {
@@ -98,8 +104,32 @@ otError otNat64GetCidr(otInstance *aInstance, otIp4Cidr *aCidr)
{ {
return AsCoreType(aInstance).Get<Nat64::Translator>().GetIp4Cidr(AsCoreType(aCidr)); return AsCoreType(aInstance).Get<Nat64::Translator>().GetIp4Cidr(AsCoreType(aCidr));
} }
otNat64State otNat64GetTranslatorState(otInstance *aInstance)
{
return MapEnum(AsCoreType(aInstance).Get<Nat64::Translator>().GetState());
}
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE #endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
otNat64State otNat64GetPrefixManagerState(otInstance *aInstance)
{
return MapEnum(AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetNat64PrefixManagerState());
}
#endif
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
void otNat64SetEnabled(otInstance *aInstance, bool aEnabled)
{
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().SetNat64PrefixManagerEnabled(aEnabled);
#endif
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
AsCoreType(aInstance).Get<Nat64::Translator>().SetEnabled(aEnabled);
#endif
}
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
bool otIp4IsAddressEqual(const otIp4Address *aFirst, const otIp4Address *aSecond) bool otIp4IsAddressEqual(const otIp4Address *aFirst, const otIp4Address *aSecond)
{ {
return AsCoreType(aFirst) == AsCoreType(aSecond); return AsCoreType(aFirst) == AsCoreType(aSecond);
@@ -170,6 +170,12 @@ exit:
} }
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
void RoutingManager::SetNat64PrefixManagerEnabled(bool aEnabled)
{
// PrefixManager will start itself if routing manager is running.
mNat64PrefixManager.SetEnabled(aEnabled);
}
Error RoutingManager::GetNat64Prefix(Ip6::Prefix &aPrefix) Error RoutingManager::GetNat64Prefix(Ip6::Prefix &aPrefix)
{ {
Error error = kErrorNone; Error error = kErrorNone;
@@ -2328,6 +2334,7 @@ void RoutingManager::OnMeshPrefixArray::MarkAsDeleted(const OnMeshPrefix &aPrefi
RoutingManager::Nat64PrefixManager::Nat64PrefixManager(Instance &aInstance) RoutingManager::Nat64PrefixManager::Nat64PrefixManager(Instance &aInstance)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mEnabled(false)
, mTimer(aInstance) , mTimer(aInstance)
{ {
mInfraIfPrefix.Clear(); mInfraIfPrefix.Clear();
@@ -2335,13 +2342,41 @@ RoutingManager::Nat64PrefixManager::Nat64PrefixManager(Instance &aInstance)
mPublishedPrefix.Clear(); mPublishedPrefix.Clear();
} }
void RoutingManager::Nat64PrefixManager::SetEnabled(bool aEnabled)
{
VerifyOrExit(mEnabled != aEnabled);
mEnabled = aEnabled;
if (aEnabled)
{
if (Get<RoutingManager>().IsRunning())
{
Start();
}
}
else
{
Stop();
}
exit:
return;
}
void RoutingManager::Nat64PrefixManager::Start(void) void RoutingManager::Nat64PrefixManager::Start(void)
{ {
VerifyOrExit(mEnabled);
LogInfo("Starting Nat64PrefixManager");
mTimer.Start(0); mTimer.Start(0);
exit:
return;
} }
void RoutingManager::Nat64PrefixManager::Stop(void) void RoutingManager::Nat64PrefixManager::Stop(void)
{ {
LogInfo("Stopping Nat64PrefixManager");
if (mPublishedPrefix.IsValidNat64()) if (mPublishedPrefix.IsValidNat64())
{ {
Get<RoutingManager>().UnpublishExternalRoute(mPublishedPrefix); Get<RoutingManager>().UnpublishExternalRoute(mPublishedPrefix);
@@ -2350,6 +2385,10 @@ void RoutingManager::Nat64PrefixManager::Stop(void)
mPublishedPrefix.Clear(); mPublishedPrefix.Clear();
mInfraIfPrefix.Clear(); mInfraIfPrefix.Clear();
mTimer.Stop(); mTimer.Stop();
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
Get<Nat64::Translator>().SetNat64Prefix(mPublishedPrefix);
#endif
} }
void RoutingManager::Nat64PrefixManager::GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix) void RoutingManager::Nat64PrefixManager::GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix)
@@ -2387,6 +2426,8 @@ void RoutingManager::Nat64PrefixManager::Evaluate(void)
NetworkData::ExternalRouteConfig netdataPrefixConfig; NetworkData::ExternalRouteConfig netdataPrefixConfig;
bool shouldPublish; bool shouldPublish;
VerifyOrExit(mEnabled);
LogInfo("Evaluating NAT64 prefix"); LogInfo("Evaluating NAT64 prefix");
prefix = GetFavoredPrefix(preference); prefix = GetFavoredPrefix(preference);
@@ -2430,6 +2471,9 @@ void RoutingManager::Nat64PrefixManager::Evaluate(void)
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE #if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
Get<Nat64::Translator>().SetNat64Prefix(mPublishedPrefix); Get<Nat64::Translator>().SetNat64Prefix(mPublishedPrefix);
#endif #endif
exit:
return;
} }
bool RoutingManager::Nat64PrefixManager::ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const bool RoutingManager::Nat64PrefixManager::ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const
@@ -2449,6 +2493,8 @@ exit:
void RoutingManager::Nat64PrefixManager::HandleTimer(void) void RoutingManager::Nat64PrefixManager::HandleTimer(void)
{ {
OT_ASSERT(mEnabled);
Discover(); Discover();
mTimer.Start(TimeMilli::SecToMsec(kDefaultNat64PrefixLifetime)); mTimer.Start(TimeMilli::SecToMsec(kDefaultNat64PrefixLifetime));
@@ -2481,6 +2527,19 @@ void RoutingManager::Nat64PrefixManager::HandleDiscoverDone(const Ip6::Prefix &a
} }
} }
Nat64::State RoutingManager::Nat64PrefixManager::GetState(void) const
{
Nat64::State state = Nat64::kStateDisabled;
VerifyOrExit(mEnabled);
VerifyOrExit(Get<RoutingManager>().IsRunning(), state = Nat64::kStateNotRunning);
VerifyOrExit(mPublishedPrefix.IsValidNat64(), state = Nat64::kStateIdle);
state = Nat64::kStateActive;
exit:
return state;
}
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE #endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
+41 -2
View File
@@ -218,6 +218,27 @@ public:
Error GetOnLinkPrefix(Ip6::Prefix &aPrefix); Error GetOnLinkPrefix(Ip6::Prefix &aPrefix);
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE #if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
/**
* Gets the state of NAT64 prefix publishing.
*
* @retval kStateDisabled NAT64 is disabled.
* @retval kStateNotRunning NAT64 is enabled, but is not running since routing manager is not running.
* @retval kStateIdle NAT64 is enabled, but the border router is not publishing a NAT64 prefix. Usually
* when there is another border router publishing a NAT64 prefix with higher
* priority.
* @retval kStateActive The Border router is publishing a NAT64 prefix.
*
*/
Nat64::State GetNat64PrefixManagerState(void) const { return mNat64PrefixManager.GetState(); }
/**
* Enable or disable NAT64 orefix publishing.
*
* @param[in] aEnabled A boolean to enable/disable NAT64 prefix publishing.
*
*/
void SetNat64PrefixManagerEnabled(bool aEnabled);
/** /**
* This method returns the local NAT64 prefix. * This method returns the local NAT64 prefix.
* *
@@ -334,6 +355,15 @@ public:
void HandleSrpServerAutoEnableMode(void); void HandleSrpServerAutoEnableMode(void);
#endif #endif
/**
* Gets the state of RoutingManager.
*
* @retval TRUE The RoutingManager is currently running.
* @retval FALSE The RoutingManager is not running.
*
*/
bool IsRunning(void) const { return mIsRunning; }
private: private:
static constexpr uint8_t kMaxOnMeshPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_ON_MESH_PREFIXES; static constexpr uint8_t kMaxOnMeshPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_ON_MESH_PREFIXES;
@@ -666,11 +696,18 @@ private:
// interface prefix, maintaining the discovered prefix // interface prefix, maintaining the discovered prefix
// lifetime, and selection of the NAT64 prefix to publish in // lifetime, and selection of the NAT64 prefix to publish in
// Network Data. // Network Data.
//
// Calling methods except GeneratrLocalPrefix and SetEnabled
// when disabled becomes no-op.
explicit Nat64PrefixManager(Instance &aInstance); explicit Nat64PrefixManager(Instance &aInstance);
void Start(void); void SetEnabled(bool aEnabled);
void Stop(void); Nat64::State GetState(void) const;
void Start(void);
void Stop(void);
void GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix); void GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix);
const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; } const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const; const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const;
@@ -684,6 +721,8 @@ private:
using Nat64Timer = TimerMilliIn<RoutingManager, &RoutingManager::HandleNat64PrefixManagerTimer>; using Nat64Timer = TimerMilliIn<RoutingManager, &RoutingManager::HandleNat64PrefixManagerTimer>;
bool mEnabled;
Ip6::Prefix mInfraIfPrefix; // The latest NAT64 prefix discovered on the infrastructure interface. Ip6::Prefix mInfraIfPrefix; // The latest NAT64 prefix discovered on the infrastructure interface.
Ip6::Prefix mLocalPrefix; // The local prefix (from BR ULA prefix). Ip6::Prefix mLocalPrefix; // The local prefix (from BR ULA prefix).
Ip6::Prefix mPublishedPrefix; // The prefix to publish in Net Data (empty or local or from infra-if). Ip6::Prefix mPublishedPrefix; // The prefix to publish in Net Data (empty or local or from infra-if).
+42 -8
View File
@@ -50,6 +50,7 @@ RegisterLogModule("Nat64");
Translator::Translator(Instance &aInstance) Translator::Translator(Instance &aInstance)
: InstanceLocator(aInstance) : InstanceLocator(aInstance)
, mEnabled(false)
, mMappingExpirerTimer(aInstance) , mMappingExpirerTimer(aInstance)
{ {
Random::NonCrypto::FillBuffer(reinterpret_cast<uint8_t *>(&mNextMappingId), sizeof(mNextMappingId)); Random::NonCrypto::FillBuffer(reinterpret_cast<uint8_t *>(&mNextMappingId), sizeof(mNextMappingId));
@@ -308,23 +309,28 @@ void Translator::ReleaseMapping(AddressMapping &aMapping)
LogInfo("mapping removed: %s", aMapping.ToString().AsCString()); LogInfo("mapping removed: %s", aMapping.ToString().AsCString());
} }
uint16_t Translator::ReleaseExpiredMappings(void) uint16_t Translator::ReleaseMappings(LinkedList<AddressMapping> &aMappings)
{ {
uint16_t numRemoved = 0; uint16_t numRemoved = 0;
TimeMilli now = TimerMilli::GetNow();
LinkedList<AddressMapping> idleMappings;
mActiveAddressMappings.RemoveAllMatching(now, idleMappings); for (AddressMapping *mapping = aMappings.Pop(); mapping != nullptr; mapping = aMappings.Pop())
for (AddressMapping *idleMapping = idleMappings.Pop(); idleMapping != nullptr; idleMapping = idleMappings.Pop())
{ {
numRemoved++; numRemoved++;
ReleaseMapping(*idleMapping); ReleaseMapping(*mapping);
} }
return numRemoved; return numRemoved;
} }
uint16_t Translator::ReleaseExpiredMappings(void)
{
LinkedList<AddressMapping> idleMappings;
mActiveAddressMappings.RemoveAllMatching(TimerMilli::GetNow(), idleMappings);
return ReleaseMappings(idleMappings);
}
Translator::AddressMapping *Translator::AllocateMapping(const Ip6::Address &aIp6Addr) Translator::AddressMapping *Translator::AllocateMapping(const Ip6::Address &aIp6Addr)
{ {
AddressMapping *mapping = nullptr; AddressMapping *mapping = nullptr;
@@ -590,6 +596,34 @@ void Translator::ProtocolCounters::Count4To6Packet(uint8_t aProtocol, uint64_t a
mTotal.m4To6Bytes += aPacketSize; mTotal.m4To6Bytes += aPacketSize;
} }
State Translator::GetState(void) const
{
State ret = kStateDisabled;
VerifyOrExit(mEnabled);
VerifyOrExit(mIp4Cidr.mLength > 0 && mNat64Prefix.IsValidNat64(), ret = kStateNotRunning);
ret = kStateActive;
exit:
return ret;
}
void Translator::SetEnabled(bool aEnabled)
{
VerifyOrExit(mEnabled != aEnabled);
mEnabled = aEnabled;
if (!aEnabled)
{
ReleaseMappings(mActiveAddressMappings);
}
LogInfo("NAT64 translator %s", aEnabled ? "enabled" : "disabled");
exit:
return;
}
} // namespace Nat64 } // namespace Nat64
} // namespace ot } // namespace ot
+37 -4
View File
@@ -37,8 +37,6 @@
#include "openthread-core-config.h" #include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
#include "common/array.hpp" #include "common/array.hpp"
#include "common/linked_list.hpp" #include "common/linked_list.hpp"
#include "common/locator.hpp" #include "common/locator.hpp"
@@ -50,6 +48,16 @@
namespace ot { namespace ot {
namespace Nat64 { namespace Nat64 {
enum State : uint8_t
{
kStateDisabled = OT_NAT64_STATE_DISABLED, ///< The component is disabled.
kStateNotRunning = OT_NAT64_STATE_NOT_RUNNING, ///< The component is enabled, but is not running.
kStateIdle = OT_NAT64_STATE_IDLE, ///< NAT64 is enabled, but this BR is not an active NAT64 BR.
kStateActive = OT_NAT64_STATE_ACTIVE, ///< The component is running.
};
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
/** /**
* This class implements the NAT64 translator. * This class implements the NAT64 translator.
* *
@@ -140,6 +148,26 @@ public:
*/ */
explicit Translator(Instance &aInstance); explicit Translator(Instance &aInstance);
/**
* Set the state of NAT64 translator.
*
* Note: Disabling the translator will invalidate all address mappings.
*
* @param[in] aEnabled A boolean to enable/disable NAT64 translator.
*
*/
void SetEnabled(bool aEnabled);
/**
* Gets the state of NAT64 translator.
*
* @retval kNat64StateDisabled The translator is disabled.
* @retval kNat64StateIdle The translator is not configured with a valid NAT64 prefix and a CIDR.
* @retval kNat64StateActive The translator is translating packets.
*
*/
State GetState(void) const;
/** /**
* This method translates an IPv4 datagram to an IPv6 datagram and sends it via Thread interface. * This method translates an IPv4 datagram to an IPv6 datagram and sends it via Thread interface.
* *
@@ -325,6 +353,7 @@ private:
Error TranslateIcmp4(Message &aMessage); Error TranslateIcmp4(Message &aMessage);
Error TranslateIcmp6(Message &aMessage); Error TranslateIcmp6(Message &aMessage);
uint16_t ReleaseMappings(LinkedList<AddressMapping> &aMappings);
void ReleaseMapping(AddressMapping &aMapping); void ReleaseMapping(AddressMapping &aMapping);
uint16_t ReleaseExpiredMappings(void); uint16_t ReleaseExpiredMappings(void);
AddressMapping *AllocateMapping(const Ip6::Address &aIp6Addr); AddressMapping *AllocateMapping(const Ip6::Address &aIp6Addr);
@@ -335,6 +364,8 @@ private:
using MappingTimer = TimerMilliIn<Translator, &Translator::HandleMappingExpirerTimer>; using MappingTimer = TimerMilliIn<Translator, &Translator::HandleMappingExpirerTimer>;
bool mEnabled;
uint64_t mNextMappingId; uint64_t mNextMappingId;
Array<Ip4::Address, kAddressMappingPoolSize> mIp4AddressPool; Array<Ip4::Address, kAddressMappingPoolSize> mIp4AddressPool;
@@ -349,14 +380,16 @@ private:
ProtocolCounters mCounters; ProtocolCounters mCounters;
ErrorCounters mErrorCounters; ErrorCounters mErrorCounters;
}; };
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
} // namespace Nat64 } // namespace Nat64
DefineMapEnum(otNat64State, Nat64::State);
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
DefineCoreType(otNat64ProtocolCounters, Nat64::Translator::ProtocolCounters); DefineCoreType(otNat64ProtocolCounters, Nat64::Translator::ProtocolCounters);
DefineCoreType(otNat64ErrorCounters, Nat64::Translator::ErrorCounters); DefineCoreType(otNat64ErrorCounters, Nat64::Translator::ErrorCounters);
#endif
} // namespace ot } // namespace ot
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
#endif // NAT64_TRANSLATOR_HPP_ #endif // NAT64_TRANSLATOR_HPP_
@@ -26,10 +26,12 @@
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE. # POSSIBILITY OF SUCH DAMAGE.
# #
from typing import Mapping
import unittest import unittest
import config import config
import thread_cert import thread_cert
import enum
# Test description: # Test description:
# This test verifies that a single NAT64 prefix is advertised when there are # This test verifies that a single NAT64 prefix is advertised when there are
@@ -53,6 +55,11 @@ HOST = 4
NAT64_PREFIX_REFRESH_DELAY = 305 NAT64_PREFIX_REFRESH_DELAY = 305
NAT64_STATE_DISABLED = 'Disabled'
NAT64_STATE_NOT_RUNNING = 'NotRunning'
NAT64_STATE_IDLE = 'Idle'
NAT64_STATE_ACTIVE = 'Active'
class Nat64MultiBorderRouter(thread_cert.TestCase): class Nat64MultiBorderRouter(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False USE_MESSAGE_FACTORY = False
@@ -81,6 +88,19 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
}, },
} }
def assertDictIncludes(self, actual: Mapping[str, str], expected: Mapping[str, str]):
""" Asserts the `actual` dict includes the `expected` dict.
Args:
actual: A dict for checking.
expected: The expected items that the actual dict should contains.
"""
for k, v in expected.items():
if k not in actual:
raise AssertionError(f"key {k} is not found in first dict")
if v != actual[k]:
raise AssertionError(f"{repr(actual[k])} != {repr(v)} for key {k}")
def test(self): def test(self):
br1 = self.nodes[BR1] br1 = self.nodes[BR1]
router = self.nodes[ROUTER] router = self.nodes[ROUTER]
@@ -91,6 +111,7 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
self.simulator.go(5) self.simulator.go(5)
br1.start() br1.start()
br1.enable_nat64()
self.simulator.go(config.LEADER_STARTUP_DELAY) self.simulator.go(config.LEADER_STARTUP_DELAY)
br1.bash("service bind9 stop") br1.bash("service bind9 stop")
self.simulator.go(NAT64_PREFIX_REFRESH_DELAY) self.simulator.go(NAT64_PREFIX_REFRESH_DELAY)
@@ -105,6 +126,7 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
# it will add the infrastructure nat64 prefix to Network Data. # it will add the infrastructure nat64 prefix to Network Data.
# #
br2.start() br2.start()
br2.enable_nat64()
self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY) self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY)
self.assertEqual('router', br2.get_state()) self.assertEqual('router', br2.get_state())
@@ -117,17 +139,33 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
nat64_prefix = br1.get_netdata_nat64_prefix()[0] nat64_prefix = br1.get_netdata_nat64_prefix()[0]
self.assertEqual(nat64_prefix, br2_infra_nat64_prefix) self.assertEqual(nat64_prefix, br2_infra_nat64_prefix)
self.assertNotEqual(nat64_prefix, br1_local_nat64_prefix) self.assertNotEqual(nat64_prefix, br1_local_nat64_prefix)
self.assertDictIncludes(br1.get_nat64_state(), {
'PrefixManager': NAT64_STATE_IDLE,
'Translator': NAT64_STATE_NOT_RUNNING
})
self.assertDictIncludes(br2.get_nat64_state(), {
'PrefixManager': NAT64_STATE_ACTIVE,
'Translator': NAT64_STATE_ACTIVE
})
# #
# Case 2. Disable border routing on BR2. # Case 2. Disable NAT64 on BR2.
# BR1 will add its local nat64 prefix. # BR1 will add its local nat64 prefix.
# #
br2.disable_br() br2.disable_nat64()
self.simulator.go(10) self.simulator.go(10)
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1) self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
nat64_prefix = br1.get_netdata_nat64_prefix()[0] nat64_prefix = br1.get_netdata_nat64_prefix()[0]
self.assertEqual(nat64_prefix, br1_local_nat64_prefix) self.assertEqual(nat64_prefix, br1_local_nat64_prefix)
self.assertDictIncludes(br1.get_nat64_state(), {
'PrefixManager': NAT64_STATE_ACTIVE,
'Translator': NAT64_STATE_ACTIVE
})
self.assertDictIncludes(br2.get_nat64_state(), {
'PrefixManager': NAT64_STATE_DISABLED,
'Translator': NAT64_STATE_DISABLED
})
# #
# Case 3. Re-enables BR2 with a local prefix and it will not add # Case 3. Re-enables BR2 with a local prefix and it will not add
@@ -135,7 +173,7 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
# #
br2.bash("service bind9 stop") br2.bash("service bind9 stop")
self.simulator.go(5) self.simulator.go(5)
br2.enable_br() br2.enable_nat64()
self.simulator.go(10) self.simulator.go(10)
self.assertNotEqual(br2_infra_nat64_prefix, br2.get_br_favored_nat64_prefix()) self.assertNotEqual(br2_infra_nat64_prefix, br2.get_br_favored_nat64_prefix())
@@ -145,30 +183,92 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
nat64_prefix = br1.get_netdata_nat64_prefix()[0] nat64_prefix = br1.get_netdata_nat64_prefix()[0]
self.assertEqual(nat64_prefix, br1_local_nat64_prefix) self.assertEqual(nat64_prefix, br1_local_nat64_prefix)
self.assertNotEqual(nat64_prefix, br2_local_nat64_prefix) self.assertNotEqual(nat64_prefix, br2_local_nat64_prefix)
self.assertDictIncludes(br1.get_nat64_state(), {
'PrefixManager': NAT64_STATE_ACTIVE,
'Translator': NAT64_STATE_ACTIVE
})
self.assertDictIncludes(br2.get_nat64_state(), {
'PrefixManager': NAT64_STATE_IDLE,
'Translator': NAT64_STATE_NOT_RUNNING
})
# #
# Case 4. Disable border routing on BR1. # Case 4. Disable NAT64 on BR1.
# BR1 withdraws its local prefix and BR2 advertises its local prefix. # BR1 withdraws its local prefix and BR2 advertises its local prefix.
# #
br1.disable_br() br1.disable_nat64()
self.simulator.go(10) self.simulator.go(10)
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1) self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
nat64_prefix = br1.get_netdata_nat64_prefix()[0] nat64_prefix = br1.get_netdata_nat64_prefix()[0]
self.assertEqual(br2_local_nat64_prefix, nat64_prefix) self.assertEqual(br2_local_nat64_prefix, nat64_prefix)
self.assertNotEqual(br1_local_nat64_prefix, nat64_prefix) self.assertNotEqual(br1_local_nat64_prefix, nat64_prefix)
self.assertDictIncludes(br1.get_nat64_state(), {
'PrefixManager': NAT64_STATE_DISABLED,
'Translator': NAT64_STATE_DISABLED
})
self.assertDictIncludes(br2.get_nat64_state(), {
'PrefixManager': NAT64_STATE_ACTIVE,
'Translator': NAT64_STATE_ACTIVE
})
# #
# Case 5. Re-enable border routing on BR1. # Case 5. Re-enable NAT64 on BR1.
# NAT64 prefix in Network Data is still BR2's local prefix. # NAT64 prefix in Network Data is still BR2's local prefix.
# #
br1.enable_br() br1.enable_nat64()
self.simulator.go(10) self.simulator.go(10)
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1) self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
nat64_prefix = br1.get_netdata_nat64_prefix()[0] nat64_prefix = br1.get_netdata_nat64_prefix()[0]
self.assertEqual(br2_local_nat64_prefix, nat64_prefix) self.assertEqual(br2_local_nat64_prefix, nat64_prefix)
self.assertNotEqual(br1_local_nat64_prefix, nat64_prefix) self.assertNotEqual(br1_local_nat64_prefix, nat64_prefix)
self.assertDictIncludes(br1.get_nat64_state(), {
'PrefixManager': NAT64_STATE_IDLE,
'Translator': NAT64_STATE_NOT_RUNNING
})
self.assertDictIncludes(br2.get_nat64_state(), {
'PrefixManager': NAT64_STATE_ACTIVE,
'Translator': NAT64_STATE_ACTIVE
})
#
# Case 6. Disable the routing manager should stop NAT64 prefix manager.
#
#
br2.disable_br()
self.simulator.go(10)
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
nat64_prefix = br1.get_netdata_nat64_prefix()[0]
self.assertEqual(br1_local_nat64_prefix, nat64_prefix)
self.assertNotEqual(br2_local_nat64_prefix, nat64_prefix)
self.assertDictIncludes(br1.get_nat64_state(), {
'PrefixManager': NAT64_STATE_ACTIVE,
'Translator': NAT64_STATE_ACTIVE
})
self.assertDictIncludes(br2.get_nat64_state(), {
'PrefixManager': NAT64_STATE_NOT_RUNNING,
'Translator': NAT64_STATE_NOT_RUNNING
})
#
# Case 7. Enable the routing manager the BR should start NAT64 prefix manager if the prefix manager is enabled.
#
#
br2.enable_br()
self.simulator.go(10)
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
nat64_prefix = br1.get_netdata_nat64_prefix()[0]
self.assertEqual(br1_local_nat64_prefix, nat64_prefix)
self.assertNotEqual(br2_local_nat64_prefix, nat64_prefix)
self.assertDictIncludes(br1.get_nat64_state(), {
'PrefixManager': NAT64_STATE_ACTIVE,
'Translator': NAT64_STATE_ACTIVE
})
self.assertDictIncludes(br2.get_nat64_state(), {
'PrefixManager': NAT64_STATE_IDLE,
'Translator': NAT64_STATE_NOT_RUNNING
})
if __name__ == '__main__': if __name__ == '__main__':
@@ -117,6 +117,7 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
self.simulator.go(5) self.simulator.go(5)
br.start() br.start()
br.enable_nat64()
self.simulator.go(config.LEADER_STARTUP_DELAY) self.simulator.go(config.LEADER_STARTUP_DELAY)
br.bash("service bind9 stop") br.bash("service bind9 stop")
self.simulator.go(330) self.simulator.go(330)
@@ -75,6 +75,7 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
router = self.nodes[ROUTER] router = self.nodes[ROUTER]
br.start() br.start()
br.enable_nat64()
self.simulator.go(config.LEADER_STARTUP_DELAY) self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual('leader', br.get_state()) self.assertEqual('leader', br.get_state())
+16
View File
@@ -2023,6 +2023,22 @@ class NodeImpl:
self.send_command(cmd) self.send_command(cmd)
return self._expect_command_output()[0].split(' ')[0] return self._expect_command_output()[0].split(' ')[0]
def enable_nat64(self):
self.send_command(f'nat64 enable')
self._expect_done()
def disable_nat64(self):
self.send_command(f'nat64 disable')
self._expect_done()
def get_nat64_state(self):
self.send_command('nat64 state')
res = {}
for line in self._expect_command_output():
state = line.split(':')
res[state[0].strip()] = state[1].strip()
return res
def get_nat64_mappings(self): def get_nat64_mappings(self):
cmd = 'nat64 mappings' cmd = 'nat64 mappings'
self.send_command(cmd) self.send_command(cmd)