mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 00:57:47 +00:00
[nat64] add support for RFC8781 NAT64 prefix (#12012)
This commit introduces support for discovering NAT64 prefixes as specified in RFC 8781. The key changes include: - New `Nat64PrefixInfoOption`: A new `Nat64PrefixInfoOption` class is added to represent the PREF64 option in ND messages. This handles parsing the prefix and its lifetime from incoming RAs. - `RxRaTracker` Enhancement: The `RxRaTracker` is updated to process `Nat64PrefixInfoOption` from RAs. It now maintains a list of discovered NAT64 prefixes from routers on the infrastructure link and determines a "favored" prefix among them. - `RoutingManager` Update: The `Nat64PrefixManager` is enhanced to utilize the RA-discovered prefix. - `test_routing_manager` Update: The `TestNat64PrefixSelection` is updated to include cases with RA-discovered prefixes.
This commit is contained in:
@@ -131,6 +131,20 @@ typedef struct otBorderRoutingPrefixTableEntry
|
||||
uint32_t mPreferredLifetime; ///< Preferred lifetime of the on-link prefix when `mIsOnLink`.
|
||||
} otBorderRoutingPrefixTableEntry;
|
||||
|
||||
/**
|
||||
* Represents an entry from the discovered NAT64 prefix table.
|
||||
*
|
||||
* The entries in the discovered table track the NAT64 Prefix Options in the received Router Advertisement messages from
|
||||
* other routers on the infrastructure link.
|
||||
*/
|
||||
typedef struct otBorderRoutingNat64PrefixEntry
|
||||
{
|
||||
otBorderRoutingRouterEntry mRouter; ///< Information about the router advertising this NAT64 prefix.
|
||||
otIp6Prefix mPrefix; ///< The discovered IPv6 prefix.
|
||||
uint32_t mMsecSinceLastUpdate; ///< Milliseconds since last update of this prefix.
|
||||
uint32_t mLifetime; ///< Lifetime of the prefix (in seconds).
|
||||
} otBorderRoutingNat64PrefixEntry;
|
||||
|
||||
/**
|
||||
* Represents a discovered Recursive DNS Server (RDNSS) address entry.
|
||||
*
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (547)
|
||||
#define OPENTHREAD_API_VERSION (548)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -68,6 +68,13 @@ void LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePre
|
||||
RoutePreferenceToString(aPreference));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
void LogNat64PrefixOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime)
|
||||
{
|
||||
LogInfo("- NAT64 Prefix %s (lifetime:%lu)", aPrefix.ToString().AsCString(), ToUlong(aLifetime));
|
||||
}
|
||||
#endif
|
||||
|
||||
void LogRecursiveDnsServerOption(const Ip6::Address &aAddress, uint32_t aLifetime)
|
||||
{
|
||||
LogInfo("- RDNSS %s (lifetime:%lu)", aAddress.ToString().AsCString(), ToUlong(aLifetime));
|
||||
|
||||
@@ -76,6 +76,16 @@ void LogPrefixInfoOption(const Ip6::Prefix &aPrefix,
|
||||
*/
|
||||
void LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePreference aPreference);
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
/**
|
||||
* Logs a NAT64 Prefix Option at info log level.
|
||||
*
|
||||
* @param[in] aPrefix The IPv6 prefix.
|
||||
* @param[in] aLifetime The NAT64 prefix lifetime in seconds.
|
||||
*/
|
||||
void LogNat64PrefixOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Logs a Recursive DNS Server (RDNSS) option at info log level.
|
||||
*
|
||||
@@ -89,6 +99,9 @@ void LogRecursiveDnsServerOption(const Ip6::Address &aAddress, uint32_t aLifetim
|
||||
inline void LogRaHeader(const RouterAdvert::Header &) {}
|
||||
inline void LogPrefixInfoOption(const Ip6::Prefix &, uint32_t, uint32_t, PrefixInfoOption::Flags) {}
|
||||
inline void LogRouteInfoOption(const Ip6::Prefix &, uint32_t, RoutePreference) {}
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
inline void LogNat64PrefixOption(const Ip6::Prefix &, uint32_t) {}
|
||||
#endif
|
||||
inline void LogRecursiveDnsServerOption(const Ip6::Address &, uint32_t) {}
|
||||
|
||||
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
|
||||
@@ -177,6 +177,38 @@ void RoutePrefix::CopyInfoTo(PrefixTableEntry &aEntry, TimeMilli aNow) const
|
||||
aEntry.mRoutePreference = static_cast<otRoutePreference>(GetRoutePreference());
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// Nat64Prefix
|
||||
|
||||
void Nat64Prefix::SetFrom(const Nat64PrefixOption &aNat64Prefix)
|
||||
{
|
||||
IgnoreError(aNat64Prefix.GetPrefix(mPrefix));
|
||||
mValidLifetime = aNat64Prefix.GetLifetime();
|
||||
mLastUpdateTime = TimerMilli::GetNow();
|
||||
}
|
||||
|
||||
void Nat64Prefix::CopyInfoTo(Nat64PrefixEntry &aEntry, TimeMilli aNow) const
|
||||
{
|
||||
aEntry.mPrefix = GetPrefix();
|
||||
aEntry.mMsecSinceLastUpdate = aNow - GetLastUpdateTime();
|
||||
aEntry.mLifetime = GetValidLifetime();
|
||||
}
|
||||
|
||||
bool Nat64Prefix::IsFavoredOver(const Ip6::Prefix &aPrefix) const
|
||||
{
|
||||
bool isFavored = false;
|
||||
|
||||
VerifyOrExit(mPrefix.GetLength() != 0);
|
||||
VerifyOrExit(aPrefix.GetLength() != 0, isFavored = true);
|
||||
|
||||
isFavored = GetPrefix() < aPrefix;
|
||||
|
||||
exit:
|
||||
return isFavored;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// RdnssAddress
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ typedef NetworkData::RoutePreference RoutePreference; ///< Route pr
|
||||
typedef otBorderRoutingPrefixTableIterator PrefixTableIterator; ///< Prefix Table Iterator.
|
||||
typedef otBorderRoutingPrefixTableEntry PrefixTableEntry; ///< Prefix Table Entry.
|
||||
typedef otBorderRoutingRouterEntry RouterEntry; ///< Router Entry.
|
||||
typedef otBorderRoutingNat64PrefixEntry Nat64PrefixEntry; ///< NAT64 Prefix Entry.
|
||||
typedef otBorderRoutingRdnssAddrEntry RdnssAddrEntry; ///< RDNSS Address Entry.
|
||||
typedef otBorderRoutingRdnssAddrCallback RdnssAddrCallback; ///< RDNS Address changed callback.
|
||||
typedef otBorderRoutingIfAddrEntry IfAddrEntry; ///< Infra-if IPv6 Address Entry.
|
||||
@@ -71,6 +72,7 @@ typedef otBorderRoutingMultiAilCallback MultiAilCallback; ///< Multi AI
|
||||
typedef Ip6::Nd::PrefixInfoOption PrefixInfoOption; ///< Prefix Info Option (PIO).
|
||||
typedef Ip6::Nd::RouteInfoOption RouteInfoOption; ///< Route Info Option (RIO).
|
||||
typedef Ip6::Nd::RaFlagsExtOption RaFlagsExtOption; ///< RA Flags Extension Option.
|
||||
typedef Ip6::Nd::Nat64PrefixOption Nat64PrefixOption; ///< NAT64 Prefix Option.
|
||||
typedef Ip6::Nd::RecursiveDnsServerOption RecursiveDnsServerOption; ///< Recursive DNS Server (RDNSS) Option.
|
||||
typedef Ip6::Nd::RouterAdvert RouterAdvert; ///< Router Advertisement (RA).
|
||||
typedef Ip6::Nd::NeighborAdvertMessage NeighborAdvertMessage; ///< Neighbor Advertisement message.
|
||||
@@ -338,6 +340,47 @@ private:
|
||||
RoutePreference mRoutePreference;
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
/**
|
||||
* Represents a NAT64 Prefix.
|
||||
*/
|
||||
class Nat64Prefix : public LifetimedPrefix, public Clearable<Nat64Prefix>
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Sets the NAT64 prefix information from a `Nat64PrefixOption`.
|
||||
*
|
||||
* @param[in] aNat64Prefix The `Nat64PrefixOption` to set from.
|
||||
*/
|
||||
void SetFrom(const Nat64PrefixOption &aNat64Prefix);
|
||||
|
||||
/**
|
||||
* Clears (sets to zero) the valid lifetime of the NAT64 prefix.
|
||||
*/
|
||||
void ClearValidLifetime(void) { mValidLifetime = 0; }
|
||||
|
||||
/**
|
||||
* Copies the NAT64 prefix information to a `Nat64PrefixEntry`.
|
||||
*
|
||||
* @param[out] aEntry The `Nat64PrefixEntry` to copy information to.
|
||||
* @param[in] aNow The current time.
|
||||
*/
|
||||
void CopyInfoTo(Nat64PrefixEntry &aEntry, TimeMilli aNow) const;
|
||||
|
||||
/**
|
||||
* Indicates whether this NAT64 prefix is favored over another NAT64 prefix.
|
||||
*
|
||||
* @param[in] aPrefix The IPv6 prefix to compare against.
|
||||
*
|
||||
* @retval TRUE If this prefix is favored over @p aPrefix.
|
||||
* @retval FALSE If this prefix is not favored over @p aPrefix.
|
||||
*/
|
||||
bool IsFavoredOver(const Ip6::Prefix &aPrefix) const;
|
||||
};
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
/**
|
||||
|
||||
@@ -608,6 +608,9 @@ void RoutingManager::HandleRxRaTrackerDecisionFactorChanged(void)
|
||||
VerifyOrExit(mIsRunning);
|
||||
|
||||
mOnLinkPrefixManager.HandleRxRaTrackerChanged();
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
mNat64PrefixManager.HandleRaDiscoverChanged();
|
||||
#endif
|
||||
mRoutePublisher.Evaluate();
|
||||
|
||||
exit:
|
||||
@@ -2187,6 +2190,7 @@ RoutingManager::Nat64PrefixManager::Nat64PrefixManager(Instance &aInstance)
|
||||
, mEnabled(false)
|
||||
, mTimer(aInstance)
|
||||
{
|
||||
mRaTrackerPrefix.Clear();
|
||||
mInfraIfPrefix.Clear();
|
||||
mLocalPrefix.Clear();
|
||||
mPublishedPrefix.Clear();
|
||||
@@ -2248,16 +2252,29 @@ void RoutingManager::Nat64PrefixManager::GenerateLocalPrefix(const Ip6::Prefix &
|
||||
|
||||
const Ip6::Prefix &RoutingManager::Nat64PrefixManager::GetFavoredPrefix(RoutePreference &aPreference) const
|
||||
{
|
||||
const Ip6::Prefix *favoredPrefix = &mLocalPrefix;
|
||||
const Ip6::Prefix *favoredPrefix;
|
||||
|
||||
aPreference = NetworkData::kRoutePreferenceLow;
|
||||
|
||||
if (mInfraIfPrefix.IsValidNat64() &&
|
||||
if (mRaTrackerPrefix.IsValidNat64() &&
|
||||
Get<RoutingManager>().mOmrPrefixManager.GetFavoredPrefix().IsInfrastructureDerived())
|
||||
{
|
||||
// Per RFC 8781 section 5, discovered NAT64 prefixes from RAs should be favored.
|
||||
favoredPrefix = &mRaTrackerPrefix;
|
||||
aPreference = NetworkData::kRoutePreferenceMedium;
|
||||
}
|
||||
else if (mInfraIfPrefix.IsValidNat64() &&
|
||||
Get<RoutingManager>().mOmrPrefixManager.GetFavoredPrefix().IsInfrastructureDerived())
|
||||
{
|
||||
// We have a valid NAT64 prefix from infrastructure (e.g. using DNS - RFC 7050) and the network is aligned with
|
||||
// an infrastructure-provided OMR prefix.
|
||||
favoredPrefix = &mInfraIfPrefix;
|
||||
aPreference = NetworkData::kRoutePreferenceMedium;
|
||||
}
|
||||
else
|
||||
{
|
||||
favoredPrefix = &mLocalPrefix;
|
||||
}
|
||||
|
||||
return *favoredPrefix;
|
||||
}
|
||||
@@ -2405,6 +2422,19 @@ void RoutingManager::Nat64PrefixManager::HandleInfraIfDiscoverDone(const Ip6::Pr
|
||||
Get<RoutingManager>().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay);
|
||||
}
|
||||
|
||||
void RoutingManager::Nat64PrefixManager::HandleRaDiscoverChanged(void)
|
||||
{
|
||||
const Ip6::Prefix &favoredPrefix = Get<RxRaTracker>().GetFavoredNat64Prefix();
|
||||
|
||||
if (favoredPrefix != mRaTrackerPrefix)
|
||||
{
|
||||
mRaTrackerPrefix = favoredPrefix;
|
||||
LogInfo("RA discovered NAT64 prefix: %s",
|
||||
mRaTrackerPrefix.IsValidNat64() ? mRaTrackerPrefix.ToString().AsCString() : "none");
|
||||
Get<RoutingManager>().ScheduleRoutingPolicyEvaluation(kAfterRandomDelay);
|
||||
}
|
||||
}
|
||||
|
||||
Nat64::State RoutingManager::Nat64PrefixManager::GetState(void) const
|
||||
{
|
||||
Nat64::State state = Nat64::kStateDisabled;
|
||||
|
||||
@@ -827,6 +827,7 @@ private:
|
||||
const Ip6::Prefix &GetFavoredPrefix(RoutePreference &aPreference) const;
|
||||
void Evaluate(void);
|
||||
void HandleInfraIfDiscoverDone(const Ip6::Prefix &aPrefix);
|
||||
void HandleRaDiscoverChanged(void);
|
||||
void HandleTimer(void);
|
||||
|
||||
private:
|
||||
@@ -837,7 +838,8 @@ private:
|
||||
using Nat64Timer = TimerMilliIn<RoutingManager, &RoutingManager::HandleNat64PrefixManagerTimer>;
|
||||
|
||||
bool mEnabled;
|
||||
Ip6::Prefix mInfraIfPrefix; // The latest NAT64 prefix discovered on the infrastructure interface.
|
||||
Ip6::Prefix mRaTrackerPrefix; // The best NAT64 prefix discovered from RAs (RFC 8781).
|
||||
Ip6::Prefix mInfraIfPrefix; // The platform-provided NAT64 prefix (e.g., using DNS - RFC 7050).
|
||||
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).
|
||||
RoutePreference mPublishedPreference; // The published prefix preference.
|
||||
|
||||
@@ -218,6 +218,12 @@ void RxRaTracker::HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket,
|
||||
ProcessRouteInfoOption(static_cast<const RouteInfoOption &>(option), *router);
|
||||
break;
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
case Option::kTypeNat64Prefix:
|
||||
ProcessNat64PrefixOption(static_cast<const Nat64PrefixOption &>(option), *router);
|
||||
break;
|
||||
#endif
|
||||
|
||||
case Option::kTypeRecursiveDnsServer:
|
||||
ProcessRecursiveDnsServerOption(static_cast<const RecursiveDnsServerOption &>(option), *router);
|
||||
break;
|
||||
@@ -433,6 +439,51 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
void RxRaTracker::ProcessNat64PrefixOption(const Nat64PrefixOption &aNat64Prefix, Router &aRouter)
|
||||
{
|
||||
Ip6::Prefix prefix;
|
||||
uint32_t lifetime;
|
||||
Entry<Nat64Prefix> *entry;
|
||||
|
||||
VerifyOrExit(aNat64Prefix.IsValid());
|
||||
SuccessOrExit(aNat64Prefix.GetPrefix(prefix));
|
||||
|
||||
lifetime = aNat64Prefix.GetLifetime();
|
||||
|
||||
LogNat64PrefixOption(prefix, lifetime);
|
||||
|
||||
if (lifetime == 0)
|
||||
{
|
||||
aRouter.mNat64Prefixes.RemoveAndFreeAllMatching(prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = aRouter.mNat64Prefixes.FindMatching(prefix);
|
||||
|
||||
if (entry != nullptr)
|
||||
{
|
||||
entry->SetFrom(aNat64Prefix);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry = AllocateEntry<Nat64Prefix>();
|
||||
if (entry == nullptr)
|
||||
{
|
||||
LogWarn("Discovered too many entries, ignore NAT64 prefix %s", prefix.ToString().AsCString());
|
||||
ExitNow();
|
||||
}
|
||||
|
||||
entry->SetFrom(aNat64Prefix);
|
||||
aRouter.mNat64Prefixes.Push(*entry);
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
#endif // OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
|
||||
void RxRaTracker::ProcessRecursiveDnsServerOption(const RecursiveDnsServerOption &aRdnss, Router &aRouter)
|
||||
{
|
||||
Entry<RdnssAddress> *entry;
|
||||
@@ -521,8 +572,11 @@ exit:
|
||||
template <class Type> RxRaTracker::Entry<Type> *RxRaTracker::AllocateEntry(void)
|
||||
{
|
||||
static_assert(TypeTraits::IsSame<Type, OnLinkPrefix>::kValue || TypeTraits::IsSame<Type, RoutePrefix>::kValue ||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
TypeTraits::IsSame<Type, Nat64Prefix>::kValue ||
|
||||
#endif
|
||||
TypeTraits::IsSame<Type, RdnssAddress>::kValue || TypeTraits::IsSame<Type, IfAddress>::kValue,
|
||||
"Type MUST be RoutePrefix, OnLinkPrefix, RdnssAddress, or IfAddress");
|
||||
"Type MUST be RoutePrefix, OnLinkPrefix, Nat64Prefix, RdnssAddress, or IfAddress");
|
||||
|
||||
Entry<Type> *entry = nullptr;
|
||||
SharedEntry *sharedEntry = mEntryPool.Allocate();
|
||||
@@ -539,6 +593,9 @@ template <> void RxRaTracker::Entry<RxRaTracker::Router>::Free(void)
|
||||
{
|
||||
mOnLinkPrefixes.Free();
|
||||
mRoutePrefixes.Free();
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
mNat64Prefixes.Free();
|
||||
#endif
|
||||
mRdnssAddresses.Free();
|
||||
Get<RxRaTracker>().mRouterPool.Free(*this);
|
||||
}
|
||||
@@ -546,8 +603,11 @@ template <> void RxRaTracker::Entry<RxRaTracker::Router>::Free(void)
|
||||
template <class Type> void RxRaTracker::Entry<Type>::Free(void)
|
||||
{
|
||||
static_assert(TypeTraits::IsSame<Type, OnLinkPrefix>::kValue || TypeTraits::IsSame<Type, RoutePrefix>::kValue ||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
TypeTraits::IsSame<Type, Nat64Prefix>::kValue ||
|
||||
#endif
|
||||
TypeTraits::IsSame<Type, RdnssAddress>::kValue || TypeTraits::IsSame<Type, IfAddress>::kValue,
|
||||
"Type MUST be RoutePrefix, OnLinkPrefix, RdnssAddress, or IfAddress");
|
||||
"Type MUST be RoutePrefix, OnLinkPrefix, Nat64Prefix, RdnssAddress, or IfAddress");
|
||||
|
||||
Get<RxRaTracker>().mEntryPool.Free(*reinterpret_cast<SharedEntry *>(this));
|
||||
}
|
||||
@@ -653,6 +713,16 @@ void RxRaTracker::RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold)
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
for (Nat64Prefix &entry : router.mNat64Prefixes)
|
||||
{
|
||||
if (entry.GetLastUpdateTime() <= aTimeThreshold)
|
||||
{
|
||||
entry.ClearValidLifetime();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (RdnssAddress &entry : router.mRdnssAddresses)
|
||||
{
|
||||
if (entry.GetLastUpdateTime() <= aTimeThreshold)
|
||||
@@ -689,6 +759,9 @@ void RxRaTracker::Evaluate(void)
|
||||
|
||||
router.mOnLinkPrefixes.RemoveAndFreeAllMatching(expirationChecker);
|
||||
router.mRoutePrefixes.RemoveAndFreeAllMatching(expirationChecker);
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
router.mNat64Prefixes.RemoveAndFreeAllMatching(expirationChecker);
|
||||
#endif
|
||||
|
||||
if (router.mRdnssAddresses.RemoveAndFreeAllMatching(expirationChecker))
|
||||
{
|
||||
@@ -698,7 +771,7 @@ void RxRaTracker::Evaluate(void)
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Remove any router entry that no longer has any valid on-link
|
||||
// or route prefixes, RDNSS addresses, or other relevant flags set.
|
||||
// or route prefixes, NAT64 Prefix, RDNSS addresses, or other relevant flags set.
|
||||
|
||||
mRouters.RemoveAllMatching(removedRouters, Router::EmptyChecker());
|
||||
|
||||
@@ -738,6 +811,13 @@ void RxRaTracker::Evaluate(void)
|
||||
|
||||
router.mAllEntriesDisregarded &= entry.ShouldDisregard();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
for (Nat64Prefix &entry : router.mNat64Prefixes)
|
||||
{
|
||||
mDecisionFactors.UpdateFrom(entry);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
@@ -790,6 +870,13 @@ void RxRaTracker::Evaluate(void)
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
for (const Nat64Prefix &entry : router.mNat64Prefixes)
|
||||
{
|
||||
entryExpireTime.UpdateIfEarlier(entry.GetExpireTime());
|
||||
}
|
||||
#endif
|
||||
|
||||
for (const RdnssAddress &entry : router.mRdnssAddresses)
|
||||
{
|
||||
rdnsssAddrExpireTime.UpdateIfEarlier(entry.GetExpireTime());
|
||||
@@ -973,6 +1060,13 @@ void RxRaTracker::HandleRouterTimer(void)
|
||||
entry.ClearValidLifetime();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
for (Nat64Prefix &entry : router.mNat64Prefixes)
|
||||
{
|
||||
entry.ClearValidLifetime();
|
||||
}
|
||||
#endif
|
||||
|
||||
for (RdnssAddress &entry : router.mRdnssAddresses)
|
||||
{
|
||||
entry.ClearLifetime();
|
||||
@@ -1114,6 +1208,24 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
Error RxRaTracker::GetNextNat64PrefixEntry(PrefixTableIterator &aIterator, Nat64PrefixEntry &aEntry) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Iterator &iterator = static_cast<Iterator &>(aIterator);
|
||||
|
||||
ClearAllBytes(aEntry);
|
||||
|
||||
SuccessOrExit(error = iterator.AdvanceToNextNat64PrefixEntry());
|
||||
|
||||
iterator.GetRouter()->CopyInfoTo(aEntry.mRouter, iterator.GetInitTime(), iterator.GetInitUptime());
|
||||
iterator.GetEntry<Nat64Prefix>()->CopyInfoTo(aEntry, iterator.GetInitTime());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
Error RxRaTracker::GetNextRdnssAddrEntry(PrefixTableIterator &aIterator, RdnssAddrEntry &aEntry) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
@@ -1335,6 +1447,30 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
Error RxRaTracker::Iterator::AdvanceToNextNat64PrefixEntry(void)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
VerifyOrExit(GetRouter() != nullptr, error = kErrorNotFound);
|
||||
|
||||
if (HasEntry())
|
||||
{
|
||||
VerifyOrExit(GetType() == kNat64PrefixIterator, error = kErrorInvalidArgs);
|
||||
SetEntry(GetEntry<Nat64Prefix>()->GetNext());
|
||||
}
|
||||
|
||||
while (!HasEntry())
|
||||
{
|
||||
SuccessOrExit(error = AdvanceToNextRouter(kNat64PrefixIterator));
|
||||
SetEntry(GetRouter()->mNat64Prefixes.GetHead());
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
Error RxRaTracker::Iterator::AdvanceToNextRdnssAddrEntry(void)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
@@ -1427,18 +1563,20 @@ bool RxRaTracker::Router::Matches(const EmptyChecker &aChecker)
|
||||
|
||||
bool hasFlags = false;
|
||||
|
||||
// Router can be removed if it does not advertise M or O flags and
|
||||
// also does not have any advertised prefix entries (RIO/PIO) or
|
||||
// RDNSS address entries. If the router already failed to respond
|
||||
// to max NS probe attempts, we consider it as offline and
|
||||
// therefore do not consider its flags anymore.
|
||||
// Router can be removed if it does not advertise M or O flags and also does not have any advertised prefix entries
|
||||
// (RIO/PIO/NAT64) or RDNSS address entries. If the router already failed to respond to max NS probe attempts, we
|
||||
// consider it as offline and therefore do not consider its flags anymore.
|
||||
|
||||
if (IsReachable())
|
||||
{
|
||||
hasFlags = (mManagedAddressConfigFlag || mOtherConfigFlag);
|
||||
}
|
||||
|
||||
return !hasFlags && mOnLinkPrefixes.IsEmpty() && mRoutePrefixes.IsEmpty() && mRdnssAddresses.IsEmpty();
|
||||
return !hasFlags && mOnLinkPrefixes.IsEmpty() && mRoutePrefixes.IsEmpty() && mRdnssAddresses.IsEmpty()
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
&& mNat64Prefixes.IsEmpty()
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
bool RxRaTracker::Router::IsPeerBr(void) const
|
||||
@@ -1569,6 +1707,16 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
void RxRaTracker::DecisionFactors::UpdateFrom(const Nat64Prefix &aNat64Prefix)
|
||||
{
|
||||
if (aNat64Prefix.IsFavoredOver(mFavoredNat64Prefix))
|
||||
{
|
||||
mFavoredNat64Prefix = aNat64Prefix.GetPrefix();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// RxRaTracker::RsSender
|
||||
|
||||
|
||||
@@ -150,6 +150,20 @@ public:
|
||||
*/
|
||||
Error GetNextRouterEntry(PrefixTableIterator &aIterator, RouterEntry &aEntry) const;
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
/**
|
||||
* Iterates over the discovered NAT64 prefix entries.
|
||||
*
|
||||
* @param[in,out] aIterator An iterator.
|
||||
* @param[out] aEntry A reference to the entry to populate.
|
||||
*
|
||||
* @retval kErrorNone Iterated to the next address entry, @p aEntry and @p aIterator are updated.
|
||||
* @retval kErrorNotFound No more entries in the table.
|
||||
* @retval kErrorInvalidArgs The @p aIterator is not valid (e.g. used to iterate over other entry types).
|
||||
*/
|
||||
Error GetNextNat64PrefixEntry(PrefixTableIterator &aIterator, Nat64PrefixEntry &aEntry) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Iterates over the discovered Recursive DNS Server (RDNSS) address entries.
|
||||
*
|
||||
@@ -228,6 +242,15 @@ public:
|
||||
*/
|
||||
const Ip6::Prefix &GetFavoredOnLinkPrefix(void) const { return mDecisionFactors.mFavoredOnLinkPrefix; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
/**
|
||||
* Gets the favored NAT64 prefix among all discovered NAT64 prefixes.
|
||||
*
|
||||
* @returns The favored NAT64 prefix.
|
||||
*/
|
||||
const Ip6::Prefix &GetFavoredNat64Prefix(void) const { return mDecisionFactors.mFavoredNat64Prefix; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the Managed Address Configuration (M) and Other Configuration (O) flags on a Router Advertisement header.
|
||||
*
|
||||
@@ -362,6 +385,9 @@ private:
|
||||
|
||||
using OnLinkPrefixList = OwningList<Entry<OnLinkPrefix>>;
|
||||
using RoutePrefixList = OwningList<Entry<RoutePrefix>>;
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
using Nat64PrefixList = OwningList<Entry<Nat64Prefix>>;
|
||||
#endif
|
||||
using RdnssAddressList = OwningList<Entry<RdnssAddress>>;
|
||||
|
||||
// `mDiscoverTime` tracks the initial discovery time of
|
||||
@@ -377,6 +403,9 @@ private:
|
||||
Ip6::Address mAddress;
|
||||
OnLinkPrefixList mOnLinkPrefixes;
|
||||
RoutePrefixList mRoutePrefixes;
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
Nat64PrefixList mNat64Prefixes;
|
||||
#endif
|
||||
RdnssAddressList mRdnssAddresses;
|
||||
uint32_t mDiscoverTime;
|
||||
TimeMilli mLastUpdateTime;
|
||||
@@ -401,6 +430,7 @@ private:
|
||||
kUnspecified,
|
||||
kRouterIterator,
|
||||
kPrefixIterator,
|
||||
kNat64PrefixIterator,
|
||||
kRdnssAddrIterator,
|
||||
kIfAddrIterator,
|
||||
kNetDataBrIterator, // Used by `NetDataPeerBrTracker`
|
||||
@@ -412,9 +442,12 @@ private:
|
||||
kRoutePrefix,
|
||||
};
|
||||
|
||||
void Init(const Entry<Router> *aRoutersHead, uint32_t aUptime);
|
||||
Error AdvanceToNextRouter(Type aType);
|
||||
Error AdvanceToNextPrefixEntry(void);
|
||||
void Init(const Entry<Router> *aRoutersHead, uint32_t aUptime);
|
||||
Error AdvanceToNextRouter(Type aType);
|
||||
Error AdvanceToNextPrefixEntry(void);
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
Error AdvanceToNextNat64PrefixEntry(void);
|
||||
#endif
|
||||
Error AdvanceToNextRdnssAddrEntry(void);
|
||||
Error AdvanceToNextIfAddrEntry(const Entry<IfAddress> *aListHead);
|
||||
uint32_t GetInitUptime(void) const { return mData0; }
|
||||
@@ -455,6 +488,9 @@ private:
|
||||
SharedEntry *mNext;
|
||||
Entry<OnLinkPrefix> mOnLinkEntry;
|
||||
Entry<RoutePrefix> mRouteEntry;
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
Entry<Nat64Prefix> mNat64PrefixEntry;
|
||||
#endif
|
||||
Entry<RdnssAddress> mRdnssAddrEntry;
|
||||
Entry<IfAddress> mIfAddrEntry;
|
||||
};
|
||||
@@ -470,13 +506,20 @@ private:
|
||||
void UpdateFlagsFrom(const Router &aRouter);
|
||||
void UpdateFrom(const OnLinkPrefix &aOnLinkPrefix);
|
||||
void UpdateFrom(const RoutePrefix &aRoutePrefix);
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
void UpdateFrom(const Nat64Prefix &aNat64Prefix);
|
||||
#endif
|
||||
|
||||
Ip6::Prefix mFavoredOnLinkPrefix;
|
||||
bool mHasNonUlaRoute : 1;
|
||||
bool mHasNonUlaOnLink : 1;
|
||||
bool mHasUlaOnLink : 1;
|
||||
bool mHeaderManagedAddressConfigFlag : 1;
|
||||
bool mHeaderOtherConfigFlag : 1;
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
Ip6::Prefix mFavoredNat64Prefix;
|
||||
#endif
|
||||
bool mHasNonUlaRoute : 1;
|
||||
bool mHasNonUlaOnLink : 1;
|
||||
bool mHasUlaOnLink : 1;
|
||||
bool mHeaderManagedAddressConfigFlag : 1;
|
||||
bool mHeaderOtherConfigFlag : 1;
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
uint16_t mReachablePeerBrCount;
|
||||
#endif
|
||||
@@ -529,6 +572,9 @@ private:
|
||||
void ProcessRaHeader(const RouterAdvert::Header &aRaHeader, Router &aRouter, RouterAdvOrigin aRaOrigin);
|
||||
void ProcessPrefixInfoOption(const PrefixInfoOption &aPio, Router &aRouter);
|
||||
void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter);
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
void ProcessNat64PrefixOption(const Nat64PrefixOption &aNat64Prefix, Router &aRouter);
|
||||
#endif
|
||||
void ProcessRecursiveDnsServerOption(const RecursiveDnsServerOption &aRdnss, Router &aRouter);
|
||||
void UpdateIfAddresses(const Ip6::Address &aAddress);
|
||||
void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
|
||||
@@ -609,6 +655,13 @@ template <> inline RxRaTracker::Entry<OnLinkPrefix> &RxRaTracker::SharedEntry::G
|
||||
|
||||
template <> inline RxRaTracker::Entry<RoutePrefix> &RxRaTracker::SharedEntry::GetEntry(void) { return mRouteEntry; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
template <> inline RxRaTracker::Entry<Nat64Prefix> &RxRaTracker::SharedEntry::GetEntry(void)
|
||||
{
|
||||
return mNat64PrefixEntry;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <> inline RxRaTracker::Entry<RdnssAddress> &RxRaTracker::SharedEntry::GetEntry(void)
|
||||
{
|
||||
return mRdnssAddrEntry;
|
||||
|
||||
@@ -182,6 +182,70 @@ void RaFlagsExtOption::Init(void)
|
||||
OT_UNUSED_VARIABLE(mFlags);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Nat64PrefixOption
|
||||
|
||||
void Nat64PrefixOption::Init(void)
|
||||
{
|
||||
Clear();
|
||||
SetType(kTypeNat64Prefix);
|
||||
SetSize(sizeof(Nat64PrefixOption));
|
||||
}
|
||||
|
||||
const uint8_t Nat64PrefixOption::kPrefixLengths[] = {96, 64, 56, 48, 40, 32};
|
||||
|
||||
void Nat64PrefixOption::SetLifetime(uint32_t aLifetime)
|
||||
{
|
||||
uint32_t scaledLifetime = DivideAndRoundUp(aLifetime, kLifetimeScalingUnit);
|
||||
|
||||
mPrefixAttr = BigEndian::HostSwap16((BigEndian::HostSwap16(mPrefixAttr) & kPrefixLengthCodeMask) |
|
||||
ClampToUint16(scaledLifetime << kScaledLifetimeOffset));
|
||||
}
|
||||
|
||||
void Nat64PrefixOption::SetPrefixLengthCode(const uint8_t aPrefixLengthCode)
|
||||
{
|
||||
mPrefixAttr = BigEndian::HostSwap16((BigEndian::HostSwap16(mPrefixAttr) & ~kPrefixLengthCodeMask) |
|
||||
(aPrefixLengthCode & kPrefixLengthCodeMask));
|
||||
}
|
||||
|
||||
Error Nat64PrefixOption::SetPrefix(const Prefix &aPrefix)
|
||||
{
|
||||
Error error = kErrorInvalidArgs;
|
||||
|
||||
memcpy(mPrefixMsb, aPrefix.GetBytes(), sizeof(mPrefixMsb));
|
||||
|
||||
for (uint8_t code = 0; code < ClampToUint8(GetArrayLength(kPrefixLengths)); code++)
|
||||
{
|
||||
if (kPrefixLengths[code] == aPrefix.mLength)
|
||||
{
|
||||
SetPrefixLengthCode(code);
|
||||
error = kErrorNone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
Error Nat64PrefixOption::GetPrefix(Prefix &aPrefix) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
uint8_t prefixLengthCode = GetPrefixLengthCode();
|
||||
|
||||
VerifyOrExit(prefixLengthCode < GetArrayLength(kPrefixLengths), error = kErrorParse);
|
||||
|
||||
aPrefix.Set(mPrefixMsb, kPrefixLengths[prefixLengthCode]);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
bool Nat64PrefixOption::IsValid(void) const
|
||||
{
|
||||
// Per RFC 8781, the length of the NAT64 Prefix Option MUST be 2 (in units of 8 octets).
|
||||
return (GetLength() == 2) && (GetPrefixLengthCode() < GetArrayLength(kPrefixLengths));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// RecursiveDnsServerOption
|
||||
|
||||
@@ -332,6 +396,27 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error RouterAdvert::TxMessage::AppendNat64PrefixOption(const Prefix &aPrefix, uint32_t aLifetime)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Nat64PrefixOption *pref64;
|
||||
|
||||
VerifyOrExit(aPrefix.IsValidNat64(), error = kErrorInvalidArgs);
|
||||
|
||||
pref64 = static_cast<Nat64PrefixOption *>(AppendOption(sizeof(Nat64PrefixOption)));
|
||||
VerifyOrExit(pref64 != nullptr, error = kErrorNoBufs);
|
||||
|
||||
pref64->Init();
|
||||
pref64->SetLifetime(aLifetime);
|
||||
|
||||
// `SetPrefix()` can fail if `aPrefix` has an unsupported length.
|
||||
// `IsValidNat64()` check above ensures this will not happen.
|
||||
IgnoreError(pref64->SetPrefix(aPrefix));
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error RouterAdvert::TxMessage::AppendRecursiveDnsServerOption(const Address *aAddresses,
|
||||
uint8_t aNumAddresses,
|
||||
uint32_t aLifetime)
|
||||
|
||||
@@ -84,6 +84,7 @@ public:
|
||||
kTypeRouteInfo = 24, ///< Route Information Option.
|
||||
kTypeRecursiveDnsServer = 25, ///< Recursive DNS Server (RDNSS) Option.
|
||||
kTypeRaFlagsExtension = 26, ///< RA Flags Extension Option.
|
||||
kTypeNat64Prefix = 38, ///< NAT64 Prefix Option (aka PREF64 Option).
|
||||
};
|
||||
|
||||
static constexpr uint16_t kLengthUnit = 8; ///< The unit of length in octets.
|
||||
@@ -505,6 +506,119 @@ private:
|
||||
|
||||
static_assert(sizeof(RaFlagsExtOption) == 8, "invalid RaFlagsExtOption structure");
|
||||
|
||||
/**
|
||||
* Represents the NAT64 Prefix Option (aka PREF64 Option).
|
||||
*
|
||||
* See section 4 of RFC 8781 for definition of this option [https://tools.ietf.org/html/rfc8781#section-4]
|
||||
*/
|
||||
OT_TOOL_PACKED_BEGIN
|
||||
class Nat64PrefixOption : public Option, private Clearable<Nat64PrefixOption>
|
||||
{
|
||||
friend class Clearable<Nat64PrefixOption>;
|
||||
|
||||
public:
|
||||
static constexpr Type kType = kTypeNat64Prefix; ///< NAT64 Prefix Option Type.
|
||||
|
||||
/**
|
||||
* Initializes the NAT64 Prefix option with proper type and length and sets all other fields to zero.
|
||||
*/
|
||||
void Init(void);
|
||||
|
||||
/**
|
||||
* Sets the NAT64 prefix lifetime.
|
||||
*
|
||||
* @param[in] aLifetime The prefix lifetime in seconds.
|
||||
*/
|
||||
void SetLifetime(uint32_t aLifetime);
|
||||
|
||||
/**
|
||||
* Returns the NAT64 prefix lifetime in seconds.
|
||||
*
|
||||
* The NAT64 prefix lifetime is encoded by scaled lifetime in units of 8 seconds.
|
||||
*
|
||||
* @returns The prefix lifetime in seconds.
|
||||
*/
|
||||
uint32_t GetLifetime(void) const
|
||||
{
|
||||
return (BigEndian::HostSwap16(mPrefixAttr) >> kScaledLifetimeOffset) * kLifetimeScalingUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix.
|
||||
*
|
||||
* @param[in] aPrefix The prefix contained in this option.
|
||||
*
|
||||
* @retval kErrorNone Successfully set the prefix.
|
||||
* @retval kErrorInvalidArgs The prefix length in @p aPrefix is not a valid NAT64 prefix length (must be one of
|
||||
* 32, 40, 48, 56, 64, or 96).
|
||||
*/
|
||||
Error SetPrefix(const Prefix &aPrefix);
|
||||
|
||||
/**
|
||||
* Gets the prefix in this option.
|
||||
*
|
||||
* @param[out] aPrefix Reference to a `Prefix` to return the prefix.
|
||||
*
|
||||
* @retval kErrorNone Successfully retrieved the prefix.
|
||||
* @retval kErrorParse The Prefix Length Code is not valid.
|
||||
*/
|
||||
Error GetPrefix(Prefix &aPrefix) const;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the option is valid.
|
||||
*
|
||||
* @retval TRUE The option is valid
|
||||
* @retval FALSE The option is not valid.
|
||||
*/
|
||||
bool IsValid(void) const;
|
||||
|
||||
Nat64PrefixOption(void) = delete;
|
||||
|
||||
private:
|
||||
// NAT64 Prefix Option
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | Type | Length | Scaled Lifetime | PLC |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// | |
|
||||
// + +
|
||||
// | Highest 96 bits of the Prefix |
|
||||
// + +
|
||||
// | |
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
static constexpr uint32_t kLifetimeScalingUnit = 8; // Lifetime is scaled in units of 8 seconds.
|
||||
static constexpr uint16_t kScaledLifetimeOffset = 3; // Scaled Lifetime offset in `mPrefixAttr`.
|
||||
static constexpr uint16_t kPrefixLengthCodeMask = 0x07; // Prefix Length Code mask in `mPrefixAttr`.
|
||||
|
||||
static const uint8_t kPrefixLengths[]; // Map from prefix length code to prefix length in bits.
|
||||
|
||||
/**
|
||||
* Returns the NAT64 prefix length code.
|
||||
*
|
||||
* The prefix length code values 0, 1, 2, 3, 4, and 5 indicate the NAT64 prefix length of 96, 64, 56, 48, 40, and 32
|
||||
* bits, respectively.
|
||||
*
|
||||
* @returns The prefix length code.
|
||||
*/
|
||||
uint8_t GetPrefixLengthCode(void) const { return BigEndian::HostSwap16(mPrefixAttr) & kPrefixLengthCodeMask; }
|
||||
|
||||
/**
|
||||
* Sets the NAT64 prefix length code.
|
||||
*
|
||||
* @param[in] aPrefixLengthCode The prefix length code.
|
||||
*/
|
||||
void SetPrefixLengthCode(const uint8_t aPrefixLengthCode);
|
||||
|
||||
uint16_t mPrefixAttr; // The prefix attributes (Scaled Lifetime and Prefix Length Code).
|
||||
uint8_t mPrefixMsb[12];
|
||||
|
||||
} OT_TOOL_PACKED_END;
|
||||
|
||||
static_assert(sizeof(Nat64PrefixOption) == 16, "invalid Nat64PrefixOption structure");
|
||||
|
||||
/**
|
||||
* Represents the Recursive DNS Server (RDNSS) Option.
|
||||
*
|
||||
@@ -939,9 +1053,27 @@ public:
|
||||
*/
|
||||
Error AppendRouteInfoOption(const Prefix &aPrefix, uint32_t aRouteLifetime, RoutePreference aPreference);
|
||||
|
||||
/**
|
||||
* Appends a NAT64 Prefix Option to the RA message.
|
||||
*
|
||||
* @note This is intended for testing only. An OTBR should not advertise a NAT64 prefix option; it should only
|
||||
* process received ones.
|
||||
*
|
||||
* @param[in] aPrefix The prefix.
|
||||
* @param[in] aLifetime The lifetime in seconds.
|
||||
*
|
||||
* @retval kErrorNone Option is appended successfully.
|
||||
* @retval kErrorInvalidArgs Unsupported length for NAT64 prefix.
|
||||
* @retval kErrorNoBufs Insufficient available buffers to grow the message.
|
||||
*/
|
||||
Error AppendNat64PrefixOption(const Prefix &aPrefix, uint32_t aLifetime);
|
||||
|
||||
/**
|
||||
* Append a Recursive DNS Server Option to the RA message.
|
||||
*
|
||||
* @note This is intended for testing only. An OTBR should not advertise an RDNSS option; it should only
|
||||
* process received ones.
|
||||
*
|
||||
* @param[in] aAddresses A pointer to an array of IPv6 addresses.
|
||||
* @param[in] aNumAddresses Number of addresses in @p aAddresses array.
|
||||
* @param[in] aLifetime The lifetime in seconds.
|
||||
|
||||
@@ -613,6 +613,18 @@ void LogRouterAdvert(const Icmp6Packet &aPacket)
|
||||
break;
|
||||
}
|
||||
|
||||
case Ip6::Nd::Option::kTypeNat64Prefix:
|
||||
{
|
||||
const Ip6::Nd::Nat64PrefixOption &nat64Prefix = static_cast<const Ip6::Nd::Nat64PrefixOption &>(option);
|
||||
Ip6::Prefix prefix;
|
||||
|
||||
VerifyOrQuit(nat64Prefix.IsValid());
|
||||
SuccessOrQuit(nat64Prefix.GetPrefix(prefix));
|
||||
|
||||
Log(" NAT64 Prefix - %s, lifetime:%u", prefix.ToString().AsCString(), nat64Prefix.GetLifetime());
|
||||
break;
|
||||
}
|
||||
|
||||
case Ip6::Nd::Option::kTypeRecursiveDnsServer:
|
||||
{
|
||||
const Ip6::Nd::RecursiveDnsServerOption &rdnss =
|
||||
@@ -880,6 +892,18 @@ struct RaFlags : public Clearable<RaFlags>
|
||||
bool mSnacRouterFlag;
|
||||
};
|
||||
|
||||
struct Nat64Prefix
|
||||
{
|
||||
Nat64Prefix(const Ip6::Prefix &aPrefix, uint32_t aLifetime)
|
||||
: mPrefix(aPrefix)
|
||||
, mLifetime(aLifetime)
|
||||
{
|
||||
}
|
||||
|
||||
const Ip6::Prefix &mPrefix;
|
||||
uint32_t mLifetime;
|
||||
};
|
||||
|
||||
struct Rdnss
|
||||
{
|
||||
template <uint16_t kNumAddrs> static Rdnss Create(uint32_t aLifetime, const Ip6::Address (&aAddresses)[kNumAddrs])
|
||||
@@ -906,6 +930,8 @@ void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
|
||||
uint16_t aNumRios,
|
||||
const Rdnss *aRdnsses,
|
||||
uint16_t aNumRdnsses,
|
||||
const Nat64Prefix *aNat64Prefixes,
|
||||
uint16_t aNumNat64Prefixes,
|
||||
const DefaultRoute &aDefaultRoute,
|
||||
const RaFlags &aRaFlags)
|
||||
{
|
||||
@@ -942,6 +968,13 @@ void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
|
||||
SuccessOrQuit(aRaMsg.AppendRouteInfoOption(aRios->mPrefix, aRios->mValidLifetime, aRios->mPreference));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
for (; aNumNat64Prefixes > 0; aNat64Prefixes++, aNumNat64Prefixes--)
|
||||
{
|
||||
SuccessOrQuit(aRaMsg.AppendNat64PrefixOption(aNat64Prefixes->mPrefix, aNat64Prefixes->mLifetime));
|
||||
}
|
||||
#endif
|
||||
|
||||
for (; aNumRdnsses > 0; aRdnsses++, aNumRdnsses--)
|
||||
{
|
||||
SuccessOrQuit(
|
||||
@@ -956,13 +989,16 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
||||
uint16_t aNumRios,
|
||||
const Rdnss *aRdnsses,
|
||||
uint16_t aNumRdnsses,
|
||||
const Nat64Prefix *aNat64Prefixes,
|
||||
uint16_t aNumNat64Prefixes,
|
||||
const DefaultRoute &aDefaultRoute,
|
||||
const RaFlags &aRaFlags)
|
||||
{
|
||||
Ip6::Nd::RouterAdvert::TxMessage raMsg;
|
||||
Icmp6Packet packet;
|
||||
|
||||
BuildRouterAdvert(raMsg, aPios, aNumPios, aRios, aNumRios, aRdnsses, aNumRdnsses, aDefaultRoute, aRaFlags);
|
||||
BuildRouterAdvert(raMsg, aPios, aNumPios, aRios, aNumRios, aRdnsses, aNumRdnsses, aNat64Prefixes, aNumNat64Prefixes,
|
||||
aDefaultRoute, aRaFlags);
|
||||
raMsg.GetAsPacket(packet);
|
||||
|
||||
SendRouterAdvert(aRouterAddress, packet);
|
||||
@@ -977,7 +1013,7 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
||||
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
|
||||
const RaFlags &aRaFlags = RaFlags())
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
}
|
||||
|
||||
template <uint16_t kNumPios>
|
||||
@@ -986,7 +1022,7 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
||||
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
|
||||
const RaFlags &aRaFlags = RaFlags())
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
}
|
||||
|
||||
template <uint16_t kNumRios>
|
||||
@@ -995,19 +1031,19 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
||||
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
|
||||
const RaFlags &aRaFlags = RaFlags())
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, aRios, kNumRios, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, aRios, kNumRios, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
}
|
||||
|
||||
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const Rdnss &aRdnss)
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, &aRdnss, 1,
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, &aRdnss, 1, nullptr, 0,
|
||||
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
|
||||
}
|
||||
|
||||
template <uint16_t kNumRdnsses>
|
||||
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const Rdnss (&aRdnsses)[kNumRdnsses])
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, aRdnsses, kNumRdnsses,
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, aRdnsses, kNumRdnsses, nullptr, 0,
|
||||
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
|
||||
}
|
||||
|
||||
@@ -1015,15 +1051,21 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
|
||||
const DefaultRoute &aDefaultRoute,
|
||||
const RaFlags &aRaFlags = RaFlags())
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
|
||||
}
|
||||
|
||||
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const RaFlags &aRaFlags)
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0,
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, nullptr, 0,
|
||||
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), aRaFlags);
|
||||
}
|
||||
|
||||
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const Nat64Prefix &aNat64Pio)
|
||||
{
|
||||
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, nullptr, 0, &aNat64Pio, 1,
|
||||
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
|
||||
}
|
||||
|
||||
struct OnLinkPrefix : public Pio
|
||||
{
|
||||
OnLinkPrefix(const Ip6::Prefix &aPrefix,
|
||||
@@ -4507,10 +4549,16 @@ void TestAutoEnableOfSrpServer(void)
|
||||
void TestNat64PrefixSelection(void)
|
||||
{
|
||||
Ip6::Prefix localNat64;
|
||||
Ip6::Prefix ailNat64 = PrefixFromString("2000:0:0:1:0:0::", 96);
|
||||
Ip6::Prefix localOmr;
|
||||
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
||||
NetworkData::OnMeshPrefixConfig prefixConfig;
|
||||
Ip6::Prefix omrPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
|
||||
Ip6::Prefix infraIfNat64Prefix = PrefixFromString("2000:0:0:1:0:0::", 96);
|
||||
Ip6::Prefix raTrackerNat64PrefixA = PrefixFromString("2000:0:0:2:0:f::", 96);
|
||||
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
|
||||
Ip6::Prefix raTrackerNat64PrefixB = PrefixFromString("2000:0:0:2:0:0::", 96);
|
||||
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
|
||||
Ip6::Prefix raTrackerNat64PrefixC = PrefixFromString("2000:0:0:2:0:8::", 96);
|
||||
Ip6::Address routerAddressC = AddressFromString("fd00::cccc");
|
||||
uint16_t heapAllocations;
|
||||
|
||||
Log("--------------------------------------------------------------------------------------------");
|
||||
@@ -4530,7 +4578,7 @@ void TestNat64PrefixSelection(void)
|
||||
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Enable Nat64 Prefix Manager. Check local NAT64 prefix in Network Data.
|
||||
// Enable NAT64 Prefix Manager. Check local NAT64 prefix in Network Data.
|
||||
|
||||
sInstance->Get<BorderRouter::RoutingManager>().SetNat64PrefixManagerEnabled(true);
|
||||
|
||||
@@ -4540,10 +4588,10 @@ void TestNat64PrefixSelection(void)
|
||||
VerifyNat64PrefixInNetData(localNat64);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// AIL NAT64 prefix discovered. No infra-derived OMR prefix in Network Data.
|
||||
// Check local NAT64 prefix in Network Data.
|
||||
// InfraIf NAT64 prefix (e.g. using DNS - RFC 7050) discovered. No infra-derived OMR prefix in Network Data. Check
|
||||
// local NAT64 prefix in Network Data.
|
||||
|
||||
DiscoverNat64Prefix(ailNat64);
|
||||
DiscoverNat64Prefix(infraIfNat64Prefix);
|
||||
|
||||
AdvanceTime(20000);
|
||||
|
||||
@@ -4551,7 +4599,7 @@ void TestNat64PrefixSelection(void)
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Add a medium preference OMR prefix into Network Data.
|
||||
// Check AIL NAT64 prefix published in Network Data.
|
||||
// Check InfraIf NAT64 prefix published in Network Data.
|
||||
|
||||
prefixConfig.Clear();
|
||||
prefixConfig.mPrefix = omrPrefix;
|
||||
@@ -4568,14 +4616,60 @@ void TestNat64PrefixSelection(void)
|
||||
AdvanceTime(20000);
|
||||
|
||||
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
||||
VerifyNat64PrefixInNetData(ailNat64);
|
||||
VerifyNat64PrefixInNetData(infraIfNat64Prefix);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// AIL NAT64 prefix removed.
|
||||
// Send an RA from a router advertising a NAT64 prefix.
|
||||
// Check that the RA-discovered NAT64 prefix is now favored and published.
|
||||
|
||||
SendRouterAdvert(routerAddressA, Nat64Prefix(raTrackerNat64PrefixA, kValidLitime));
|
||||
|
||||
AdvanceTime(20000);
|
||||
|
||||
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
||||
VerifyNat64PrefixInNetData(raTrackerNat64PrefixA);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Send two RAs from routers B and C advertising two different NAT64 prefixes.
|
||||
// Check that the numerically smallest prefix is now favored.
|
||||
|
||||
SendRouterAdvert(routerAddressB, Nat64Prefix(raTrackerNat64PrefixB, kValidLitime));
|
||||
SendRouterAdvert(routerAddressC, Nat64Prefix(raTrackerNat64PrefixC, kValidLitime));
|
||||
|
||||
AdvanceTime(20000);
|
||||
|
||||
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
||||
VerifyNat64PrefixInNetData(raTrackerNat64PrefixB);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Remove RA-discovered NAT64 prefix A and B from router A and B.
|
||||
// Check that the remained RA-discovered prefix C is now favored.
|
||||
|
||||
SendRouterAdvert(routerAddressA, Nat64Prefix(raTrackerNat64PrefixA, 0));
|
||||
SendRouterAdvert(routerAddressB, Nat64Prefix(raTrackerNat64PrefixB, 0));
|
||||
|
||||
AdvanceTime(20000);
|
||||
|
||||
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
||||
VerifyNat64PrefixInNetData(raTrackerNat64PrefixC);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// Remove RA-discovered NAT64 prefix C.
|
||||
// Check that the infra-if NAT64 prefix is published again.
|
||||
|
||||
SendRouterAdvert(routerAddressC, Nat64Prefix(raTrackerNat64PrefixC, 0));
|
||||
|
||||
AdvanceTime(20000);
|
||||
|
||||
VerifyOmrPrefixInNetData(omrPrefix, /* aDefaultRoute */ false);
|
||||
VerifyNat64PrefixInNetData(infraIfNat64Prefix);
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
// InfraIf NAT64 prefix removed.
|
||||
// Check local NAT64 prefix in Network Data.
|
||||
|
||||
ailNat64.Clear();
|
||||
DiscoverNat64Prefix(ailNat64);
|
||||
infraIfNat64Prefix.Clear();
|
||||
DiscoverNat64Prefix(infraIfNat64Prefix);
|
||||
|
||||
AdvanceTime(20000);
|
||||
|
||||
@@ -4614,7 +4708,7 @@ template <uint16_t kNumPios> void ReportPdPrefixesAsRa(const Pio (&aPios)[kNumPi
|
||||
Ip6::Nd::RouterAdvert::TxMessage raMsg;
|
||||
Icmp6Packet packet;
|
||||
|
||||
BuildRouterAdvert(raMsg, aPios, kNumPios, nullptr, 0, nullptr, 0,
|
||||
BuildRouterAdvert(raMsg, aPios, kNumPios, nullptr, 0, nullptr, 0, nullptr, 0,
|
||||
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
|
||||
raMsg.GetAsPacket(packet);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user