[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:
Yang Song
2025-10-31 07:35:36 -07:00
committed by GitHub
parent 537d790c0d
commit 4e2a570d0e
13 changed files with 694 additions and 41 deletions
+14
View File
@@ -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.
*
+1 -1
View File
@@ -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
+7
View File
@@ -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));
+13
View File
@@ -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)
+32
View File
@@ -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
+43
View File
@@ -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
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/**
+32 -2
View File
@@ -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;
+3 -1
View File
@@ -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.
+157 -9
View File
@@ -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
+61 -8
View File
@@ -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;
+85
View File
@@ -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)
+132
View File
@@ -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.
+114 -20
View File
@@ -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);