mirror of
https://github.com/espressif/openthread.git
synced 2026-07-27 14:27:47 +00:00
[nat64] add runtime switch for NAT64 prefix publisher and translator (#8194)
This commit is contained in:
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (251)
|
||||
#define OPENTHREAD_API_VERSION (252)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -226,6 +226,73 @@ otError otNat64GetNextAddressMapping(otInstance * aInstance,
|
||||
otNat64AddressMappingIterator *aIterator,
|
||||
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.
|
||||
*
|
||||
|
||||
+65
-3
@@ -1855,7 +1855,7 @@ Done
|
||||
|
||||
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
|
||||
> nat64 cidr
|
||||
@@ -1863,11 +1863,73 @@ This command is only available when device enables NAT64 translator.
|
||||
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
|
||||
|
||||
Get the NAT64 translator mappings.
|
||||
|
||||
This command is only available when device enables NAT64 translator.
|
||||
`OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE` is required.
|
||||
|
||||
```bash
|
||||
> nat64 mappings
|
||||
@@ -1885,7 +1947,7 @@ This command is only available when device enables NAT64 translator.
|
||||
|
||||
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
|
||||
> nat64 counters
|
||||
|
||||
+74
-4
@@ -84,7 +84,7 @@
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
#include <openthread/trel.h>
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
#include <openthread/nat64.h>
|
||||
#endif
|
||||
|
||||
@@ -735,15 +735,84 @@ exit:
|
||||
}
|
||||
#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[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
bool enable;
|
||||
|
||||
if (aArgs[0].IsEmpty())
|
||||
{
|
||||
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
|
||||
* @code
|
||||
@@ -932,6 +1001,7 @@ template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[])
|
||||
errorCounters.mCount6To4[i]);
|
||||
}
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
else
|
||||
{
|
||||
ExitNow(error = OT_ERROR_INVALID_COMMAND);
|
||||
@@ -940,7 +1010,7 @@ template <> otError Interpreter::Process<Cmd("nat64")>(Arg aArgs[])
|
||||
exit:
|
||||
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)
|
||||
template <> otError Interpreter::Process<Cmd("bbr")>(Arg aArgs[])
|
||||
@@ -7091,7 +7161,7 @@ otError Interpreter::ProcessCommand(Arg aArgs[])
|
||||
#endif
|
||||
CmdEntry("mode"),
|
||||
CmdEntry("multiradio"),
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE || OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
CmdEntry("nat64"),
|
||||
#endif
|
||||
#if OPENTHREAD_FTD
|
||||
|
||||
@@ -46,6 +46,12 @@
|
||||
|
||||
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
|
||||
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));
|
||||
}
|
||||
|
||||
otNat64State otNat64GetTranslatorState(otInstance *aInstance)
|
||||
{
|
||||
return MapEnum(AsCoreType(aInstance).Get<Nat64::Translator>().GetState());
|
||||
}
|
||||
#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)
|
||||
{
|
||||
return AsCoreType(aFirst) == AsCoreType(aSecond);
|
||||
|
||||
@@ -170,6 +170,12 @@ exit:
|
||||
}
|
||||
|
||||
#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 error = kErrorNone;
|
||||
@@ -2328,6 +2334,7 @@ void RoutingManager::OnMeshPrefixArray::MarkAsDeleted(const OnMeshPrefix &aPrefi
|
||||
|
||||
RoutingManager::Nat64PrefixManager::Nat64PrefixManager(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mEnabled(false)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
mInfraIfPrefix.Clear();
|
||||
@@ -2335,13 +2342,41 @@ RoutingManager::Nat64PrefixManager::Nat64PrefixManager(Instance &aInstance)
|
||||
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)
|
||||
{
|
||||
VerifyOrExit(mEnabled);
|
||||
LogInfo("Starting Nat64PrefixManager");
|
||||
mTimer.Start(0);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void RoutingManager::Nat64PrefixManager::Stop(void)
|
||||
{
|
||||
LogInfo("Stopping Nat64PrefixManager");
|
||||
|
||||
if (mPublishedPrefix.IsValidNat64())
|
||||
{
|
||||
Get<RoutingManager>().UnpublishExternalRoute(mPublishedPrefix);
|
||||
@@ -2350,6 +2385,10 @@ void RoutingManager::Nat64PrefixManager::Stop(void)
|
||||
mPublishedPrefix.Clear();
|
||||
mInfraIfPrefix.Clear();
|
||||
mTimer.Stop();
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
Get<Nat64::Translator>().SetNat64Prefix(mPublishedPrefix);
|
||||
#endif
|
||||
}
|
||||
|
||||
void RoutingManager::Nat64PrefixManager::GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix)
|
||||
@@ -2387,6 +2426,8 @@ void RoutingManager::Nat64PrefixManager::Evaluate(void)
|
||||
NetworkData::ExternalRouteConfig netdataPrefixConfig;
|
||||
bool shouldPublish;
|
||||
|
||||
VerifyOrExit(mEnabled);
|
||||
|
||||
LogInfo("Evaluating NAT64 prefix");
|
||||
|
||||
prefix = GetFavoredPrefix(preference);
|
||||
@@ -2430,6 +2471,9 @@ void RoutingManager::Nat64PrefixManager::Evaluate(void)
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
Get<Nat64::Translator>().SetNat64Prefix(mPublishedPrefix);
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
bool RoutingManager::Nat64PrefixManager::ShouldPublish(NetworkData::ExternalRouteConfig &aRouteConfig) const
|
||||
@@ -2449,6 +2493,8 @@ exit:
|
||||
|
||||
void RoutingManager::Nat64PrefixManager::HandleTimer(void)
|
||||
{
|
||||
OT_ASSERT(mEnabled);
|
||||
|
||||
Discover();
|
||||
|
||||
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
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -218,6 +218,27 @@ public:
|
||||
Error GetOnLinkPrefix(Ip6::Prefix &aPrefix);
|
||||
|
||||
#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.
|
||||
*
|
||||
@@ -334,6 +355,15 @@ public:
|
||||
void HandleSrpServerAutoEnableMode(void);
|
||||
#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:
|
||||
static constexpr uint8_t kMaxOnMeshPrefixes = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_ON_MESH_PREFIXES;
|
||||
|
||||
@@ -666,11 +696,18 @@ private:
|
||||
// interface prefix, maintaining the discovered prefix
|
||||
// lifetime, and selection of the NAT64 prefix to publish in
|
||||
// Network Data.
|
||||
//
|
||||
// Calling methods except GeneratrLocalPrefix and SetEnabled
|
||||
// when disabled becomes no-op.
|
||||
|
||||
explicit Nat64PrefixManager(Instance &aInstance);
|
||||
|
||||
void Start(void);
|
||||
void Stop(void);
|
||||
void SetEnabled(bool aEnabled);
|
||||
Nat64::State GetState(void) const;
|
||||
|
||||
void Start(void);
|
||||
void Stop(void);
|
||||
|
||||
void GenerateLocalPrefix(const Ip6::Prefix &aBrUlaPrefix);
|
||||
const Ip6::Prefix &GetLocalPrefix(void) const { return mLocalPrefix; }
|
||||
const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const;
|
||||
@@ -684,6 +721,8 @@ private:
|
||||
|
||||
using Nat64Timer = TimerMilliIn<RoutingManager, &RoutingManager::HandleNat64PrefixManagerTimer>;
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
Ip6::Prefix mInfraIfPrefix; // The latest NAT64 prefix discovered on the infrastructure interface.
|
||||
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).
|
||||
|
||||
@@ -50,6 +50,7 @@ RegisterLogModule("Nat64");
|
||||
|
||||
Translator::Translator(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mEnabled(false)
|
||||
, mMappingExpirerTimer(aInstance)
|
||||
{
|
||||
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());
|
||||
}
|
||||
|
||||
uint16_t Translator::ReleaseExpiredMappings(void)
|
||||
uint16_t Translator::ReleaseMappings(LinkedList<AddressMapping> &aMappings)
|
||||
{
|
||||
uint16_t numRemoved = 0;
|
||||
TimeMilli now = TimerMilli::GetNow();
|
||||
LinkedList<AddressMapping> idleMappings;
|
||||
uint16_t numRemoved = 0;
|
||||
|
||||
mActiveAddressMappings.RemoveAllMatching(now, idleMappings);
|
||||
|
||||
for (AddressMapping *idleMapping = idleMappings.Pop(); idleMapping != nullptr; idleMapping = idleMappings.Pop())
|
||||
for (AddressMapping *mapping = aMappings.Pop(); mapping != nullptr; mapping = aMappings.Pop())
|
||||
{
|
||||
numRemoved++;
|
||||
ReleaseMapping(*idleMapping);
|
||||
ReleaseMapping(*mapping);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
AddressMapping *mapping = nullptr;
|
||||
@@ -590,6 +596,34 @@ void Translator::ProtocolCounters::Count4To6Packet(uint8_t aProtocol, uint64_t a
|
||||
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 ot
|
||||
|
||||
|
||||
@@ -37,8 +37,6 @@
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
|
||||
#include "common/array.hpp"
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
@@ -50,6 +48,16 @@
|
||||
namespace ot {
|
||||
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.
|
||||
*
|
||||
@@ -140,6 +148,26 @@ public:
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@@ -325,6 +353,7 @@ private:
|
||||
Error TranslateIcmp4(Message &aMessage);
|
||||
Error TranslateIcmp6(Message &aMessage);
|
||||
|
||||
uint16_t ReleaseMappings(LinkedList<AddressMapping> &aMappings);
|
||||
void ReleaseMapping(AddressMapping &aMapping);
|
||||
uint16_t ReleaseExpiredMappings(void);
|
||||
AddressMapping *AllocateMapping(const Ip6::Address &aIp6Addr);
|
||||
@@ -335,6 +364,8 @@ private:
|
||||
|
||||
using MappingTimer = TimerMilliIn<Translator, &Translator::HandleMappingExpirerTimer>;
|
||||
|
||||
bool mEnabled;
|
||||
|
||||
uint64_t mNextMappingId;
|
||||
|
||||
Array<Ip4::Address, kAddressMappingPoolSize> mIp4AddressPool;
|
||||
@@ -349,14 +380,16 @@ private:
|
||||
ProtocolCounters mCounters;
|
||||
ErrorCounters mErrorCounters;
|
||||
};
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
|
||||
} // namespace Nat64
|
||||
|
||||
DefineMapEnum(otNat64State, Nat64::State);
|
||||
#if OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
DefineCoreType(otNat64ProtocolCounters, Nat64::Translator::ProtocolCounters);
|
||||
DefineCoreType(otNat64ErrorCounters, Nat64::Translator::ErrorCounters);
|
||||
#endif
|
||||
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_TRANSLATOR_ENABLE
|
||||
|
||||
#endif // NAT64_TRANSLATOR_HPP_
|
||||
|
||||
@@ -26,10 +26,12 @@
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
from typing import Mapping
|
||||
import unittest
|
||||
|
||||
import config
|
||||
import thread_cert
|
||||
import enum
|
||||
|
||||
# Test description:
|
||||
# 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_STATE_DISABLED = 'Disabled'
|
||||
NAT64_STATE_NOT_RUNNING = 'NotRunning'
|
||||
NAT64_STATE_IDLE = 'Idle'
|
||||
NAT64_STATE_ACTIVE = 'Active'
|
||||
|
||||
|
||||
class Nat64MultiBorderRouter(thread_cert.TestCase):
|
||||
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):
|
||||
br1 = self.nodes[BR1]
|
||||
router = self.nodes[ROUTER]
|
||||
@@ -91,6 +111,7 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
|
||||
self.simulator.go(5)
|
||||
|
||||
br1.start()
|
||||
br1.enable_nat64()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
br1.bash("service bind9 stop")
|
||||
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.
|
||||
#
|
||||
br2.start()
|
||||
br2.enable_nat64()
|
||||
self.simulator.go(config.BORDER_ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual('router', br2.get_state())
|
||||
|
||||
@@ -117,17 +139,33 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
|
||||
nat64_prefix = br1.get_netdata_nat64_prefix()[0]
|
||||
self.assertEqual(nat64_prefix, br2_infra_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.
|
||||
#
|
||||
br2.disable_br()
|
||||
br2.disable_nat64()
|
||||
self.simulator.go(10)
|
||||
|
||||
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
|
||||
nat64_prefix = br1.get_netdata_nat64_prefix()[0]
|
||||
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
|
||||
@@ -135,7 +173,7 @@ class Nat64MultiBorderRouter(thread_cert.TestCase):
|
||||
#
|
||||
br2.bash("service bind9 stop")
|
||||
self.simulator.go(5)
|
||||
br2.enable_br()
|
||||
br2.enable_nat64()
|
||||
|
||||
self.simulator.go(10)
|
||||
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]
|
||||
self.assertEqual(nat64_prefix, br1_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.disable_br()
|
||||
br1.disable_nat64()
|
||||
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
|
||||
nat64_prefix = br1.get_netdata_nat64_prefix()[0]
|
||||
self.assertEqual(br2_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.
|
||||
#
|
||||
br1.enable_br()
|
||||
br1.enable_nat64()
|
||||
|
||||
self.simulator.go(10)
|
||||
self.assertEqual(len(br1.get_netdata_nat64_prefix()), 1)
|
||||
nat64_prefix = br1.get_netdata_nat64_prefix()[0]
|
||||
self.assertEqual(br2_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__':
|
||||
|
||||
@@ -117,6 +117,7 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
self.simulator.go(5)
|
||||
|
||||
br.start()
|
||||
br.enable_nat64()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
br.bash("service bind9 stop")
|
||||
self.simulator.go(330)
|
||||
|
||||
@@ -75,6 +75,7 @@ class Nat64SingleBorderRouter(thread_cert.TestCase):
|
||||
router = self.nodes[ROUTER]
|
||||
|
||||
br.start()
|
||||
br.enable_nat64()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual('leader', br.get_state())
|
||||
|
||||
|
||||
@@ -2023,6 +2023,22 @@ class NodeImpl:
|
||||
self.send_command(cmd)
|
||||
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):
|
||||
cmd = 'nat64 mappings'
|
||||
self.send_command(cmd)
|
||||
|
||||
Reference in New Issue
Block a user