[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.
*
*/
#define OPENTHREAD_API_VERSION (251)
#define OPENTHREAD_API_VERSION (252)
/**
* @addtogroup api-instance
+67
View File
@@ -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
View File
@@ -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
View File
@@ -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
+30
View File
@@ -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
//---------------------------------------------------------------------------------------------------------------------
+41 -2
View File
@@ -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).
+42 -8
View File
@@ -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 -4
View File
@@ -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())
+16
View File
@@ -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)