[routing-manager] enhance selection of prefixes to advertise as RIO (#7936)

This commit updated how `RoutingManager` selects the set of prefixes
to advertise as RIO in emitted RA messages from the BR.  The related
code is now moved to `SendRouterAdvertisement()` method (instead of
previously being in `EvaluateOmrPrefix()`). Since the array for
storing the advertised prefixes has a limited size (configurable
through an OT build-time setting), we add more important prefixes
first in the array to ensure that they are advertised in the RA
message. The following order is used: (1) Local OMR prefix (if
added in Network Data), (2) currently favored OMR prefix, (3) any
other OMR prefixes from Network Data, (4) any other on-mesh prefix
(excluding Domain Prefix) from Network Data.
This commit is contained in:
Abtin Keshavarzian
2022-07-26 12:41:07 -07:00
committed by GitHub
parent 5755797937
commit 209716aa19
2 changed files with 159 additions and 67 deletions
+142 -61
View File
@@ -295,8 +295,7 @@ void RoutingManager::Stop(void)
mIsAdvertisingLocalNat64Prefix = false;
}
#endif
// Use empty OMR & on-link prefixes to invalidate possible advertised prefixes.
SendRouterAdvertisement(OnMeshPrefixArray());
SendRouterAdvertisement(kInvalidateAllPrevPrefixes);
mAdvertisedPrefixes.Clear();
mOnLinkPrefixDeprecateTimer.Stop();
@@ -419,7 +418,7 @@ void RoutingManager::UpdateDiscoveredPrefixTableOnNetDataChange(void)
mDiscoveredPrefixTable.SetAllowDefaultRouteInNetData(foundDefRouteOmrPrefix);
}
void RoutingManager::EvaluateOmrPrefix(OnMeshPrefixArray &aNewPrefixes)
void RoutingManager::EvaluateOmrPrefix(void)
{
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
NetworkData::OnMeshPrefixConfig onMeshPrefixConfig;
@@ -430,22 +429,6 @@ void RoutingManager::EvaluateOmrPrefix(OnMeshPrefixArray &aNewPrefixes)
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, onMeshPrefixConfig) == kErrorNone)
{
if (!onMeshPrefixConfig.mOnMesh || onMeshPrefixConfig.mDp)
{
continue;
}
if (!aNewPrefixes.Contains(onMeshPrefixConfig.GetPrefix()))
{
Error error = aNewPrefixes.PushBack(onMeshPrefixConfig.GetPrefix());
if (error != kErrorNone)
{
LogWarn("EvaluateOmrPrefix: Too many on-mesh prefixes, ignoring prefix %s",
onMeshPrefixConfig.GetPrefix().ToString().AsCString());
}
}
if (!IsValidOmrPrefix(onMeshPrefixConfig) || !onMeshPrefixConfig.mPreferred)
{
continue;
@@ -468,11 +451,6 @@ void RoutingManager::EvaluateOmrPrefix(OnMeshPrefixArray &aNewPrefixes)
SuccessOrExit(mLocalOmrPrefix.AddToNetData());
mFavoredOmrPrefix.SetFrom(mLocalOmrPrefix);
if (!aNewPrefixes.Contains(mLocalOmrPrefix.GetPrefix()))
{
SuccessOrExit(aNewPrefixes.PushBack(mLocalOmrPrefix.GetPrefix()));
}
}
else if (mFavoredOmrPrefix.GetPrefix() == mLocalOmrPrefix.GetPrefix())
{
@@ -480,19 +458,10 @@ void RoutingManager::EvaluateOmrPrefix(OnMeshPrefixArray &aNewPrefixes)
}
else if (mLocalOmrPrefix.IsAddedInNetData())
{
OnMeshPrefix *entry;
LogInfo("EvaluateOmrPrefix: There is already a preferred OMR prefix %s in the Thread network",
mFavoredOmrPrefix.GetPrefix().ToString().AsCString());
mLocalOmrPrefix.RemoveFromNetData();
entry = aNewPrefixes.Find(mLocalOmrPrefix.GetPrefix());
if (entry != nullptr)
{
aNewPrefixes.Remove(*entry);
}
}
exit:
@@ -672,28 +641,17 @@ void RoutingManager::EvaluateRoutingPolicy(void)
{
OT_ASSERT(mIsRunning);
OnMeshPrefixArray newPrefixes;
LogInfo("Evaluating routing policy");
// 0. Evaluate on-link, OMR and NAT64 prefixes.
EvaluateOnLinkPrefix();
EvaluateOmrPrefix(newPrefixes);
EvaluateOmrPrefix();
#if OPENTHREAD_CONFIG_BORDER_ROUTING_NAT64_ENABLE
EvaluateNat64Prefix();
#endif
// 1. Send Router Advertisement message if necessary.
SendRouterAdvertisement(newPrefixes);
if (newPrefixes.IsEmpty())
{
// This is the very exceptional case and happens only when we failed to publish
// our local OMR prefix to the Thread network. We schedule the routing policy
// timer to re-evaluate our routing policy in the future.
LogWarn("No OMR prefix advertised! Start Routing Policy timer for future evaluation");
}
SendRouterAdvertisement(kAdvPrefixesFromNetData);
// 2. Schedule routing policy timer with random interval for the next Router Advertisement.
{
@@ -708,9 +666,6 @@ void RoutingManager::EvaluateRoutingPolicy(void)
StartRoutingPolicyEvaluationDelay(Time::SecToMsec(nextSendDelay));
}
// 3. Update advertised prefixes.
mAdvertisedPrefixes = newPrefixes;
}
void RoutingManager::StartRoutingPolicyEvaluationJitter(uint32_t aJitterMilli)
@@ -773,7 +728,7 @@ Error RoutingManager::SendRouterSolicitation(void)
return mInfraIf.Send(packet, destAddress);
}
void RoutingManager::SendRouterAdvertisement(const OnMeshPrefixArray &aNewPrefixes)
void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
{
// RA message max length is derived to accommodate:
//
@@ -787,8 +742,10 @@ void RoutingManager::SendRouterAdvertisement(const OnMeshPrefixArray &aNewPrefix
sizeof(Ip6::Nd::RouterAdvertMessage::Header) + sizeof(Ip6::Nd::PrefixInfoOption) +
2 * kMaxOnMeshPrefixes * (sizeof(Ip6::Nd::RouteInfoOption) + sizeof(Ip6::Prefix));
uint8_t buffer[kMaxRaLength];
Ip6::Nd::RouterAdvertMessage raMsg(mRouterAdvertHeader, buffer);
uint8_t buffer[kMaxRaLength];
Ip6::Nd::RouterAdvertMessage raMsg(mRouterAdvertHeader, buffer);
NetworkData::Iterator iterator;
NetworkData::OnMeshPrefixConfig prefixConfig;
// Append PIO for local on-link prefix. Ensure it is either being
// advertised or deprecated.
@@ -815,25 +772,113 @@ void RoutingManager::SendRouterAdvertisement(const OnMeshPrefixArray &aNewPrefix
validLifetime, preferredLifetime);
}
// Invalidate previously advertised prefixes if they are no
// longer in the new prefix array.
// Determine which previously advertised prefixes need to be
// invalidated. Under `kInvalidateAllPrevPrefixes` mode we need
// to invalidate all. Under `kAdvPrefixesFromNetData` mode, we
// check Network Data entries and invalidate any previously
// advertised prefix that is no longer present in the Network
// Data. We go through all Network Data prefixes and mark the
// ones we find in `mAdvertisedPrefixes` as deleted by setting
// the prefix length to zero). By the end, the remaining entries
// in the array with a non-zero prefix length are invalidated.
if (aRaTxMode != kInvalidateAllPrevPrefixes)
{
iterator = NetworkData::kIteratorInit;
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone)
{
if (!prefixConfig.mOnMesh || prefixConfig.mDp || (prefixConfig.GetPrefix() == mLocalOmrPrefix.GetPrefix()))
{
continue;
}
mAdvertisedPrefixes.MarkAsDeleted(prefixConfig.GetPrefix());
}
if (mLocalOmrPrefix.IsAddedInNetData())
{
mAdvertisedPrefixes.MarkAsDeleted(mLocalOmrPrefix.GetPrefix());
}
}
for (const OnMeshPrefix &prefix : mAdvertisedPrefixes)
{
if (!aNewPrefixes.Contains(prefix))
if (prefix.GetLength() != 0)
{
SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, /* aRouteLifetime */ 0, mRouteInfoOptionPreference));
LogInfo("RouterAdvert: Added RIO for %s (lifetime=0)", prefix.ToString().AsCString());
}
}
for (const OnMeshPrefix &prefix : aNewPrefixes)
{
SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, kDefaultOmrPrefixLifetime, mRouteInfoOptionPreference));
// Discover and add prefixes from Network Data to advertise as
// RIO in the Router Advertisement message.
LogInfo("RouterAdvert: Added RIO for %s (lifetime=%u)", prefix.ToString().AsCString(),
kDefaultOmrPrefixLifetime);
mAdvertisedPrefixes.Clear();
if (aRaTxMode == kAdvPrefixesFromNetData)
{
// `mAdvertisedPrefixes` array has a limited size. We add more
// important prefixes first in the array to ensure they are
// advertised in the RA message. Note that `Add()` method
// will ensure to add a prefix only once (will check if
// prefix is already present in the array).
// (1) Local OMR prefix.
if (mLocalOmrPrefix.IsAddedInNetData())
{
mAdvertisedPrefixes.Add(mLocalOmrPrefix.GetPrefix());
}
// (2) Favored OMR prefix.
if (!mFavoredOmrPrefix.IsEmpty())
{
mAdvertisedPrefixes.Add(mFavoredOmrPrefix.GetPrefix());
}
// (3) All other OMR prefixes.
iterator = NetworkData::kIteratorInit;
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone)
{
// Local OMR prefix is added to the array depending on
// `mLocalOmrPrefix.IsAddedInNetData()` at step (1). As
// we iterate through the Network Data prefixes, we skip
// over entries matching the local OMR prefix. This
// ensures that we stop including it in emitted RA
// message as soon as we decide to remove it from Network
// Data. Note that upon requesting it to be removed from
// Network Data the change needs to be registered with
// leader and can take some time to be updated in Network
// Data.
if (IsValidOmrPrefix(prefixConfig) && (prefixConfig.GetPrefix() != mLocalOmrPrefix.GetPrefix()))
{
mAdvertisedPrefixes.Add(prefixConfig.GetPrefix());
}
}
// (4) All other on-mesh prefixes (excluding Domain Prefix).
iterator = NetworkData::kIteratorInit;
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, prefixConfig) == kErrorNone)
{
if (prefixConfig.mOnMesh && !prefixConfig.mDp && !IsValidOmrPrefix(prefixConfig))
{
mAdvertisedPrefixes.Add(prefixConfig.GetPrefix());
}
}
for (const OnMeshPrefix &prefix : mAdvertisedPrefixes)
{
SuccessOrAssert(raMsg.AppendRouteInfoOption(prefix, kDefaultOmrPrefixLifetime, mRouteInfoOptionPreference));
LogInfo("RouterAdvert: Added RIO for %s (lifetime=%u)", prefix.ToString().AsCString(),
kDefaultOmrPrefixLifetime);
}
}
if (raMsg.ContainsAnyOptions())
@@ -2079,6 +2124,42 @@ exit:
return;
}
//---------------------------------------------------------------------------------------------------------------------
// OnMeshPrefixArray
void RoutingManager::OnMeshPrefixArray::Add(const OnMeshPrefix &aPrefix)
{
// Checks if `aPrefix` is already present in the array and if not
// adds it as new entry.
Error error;
VerifyOrExit(!Contains(aPrefix));
error = PushBack(aPrefix);
if (error != kErrorNone)
{
LogWarn("Too many on-mesh prefixes in net data, ignoring prefix %s", aPrefix.ToString().AsCString());
}
exit:
return;
}
void RoutingManager::OnMeshPrefixArray::MarkAsDeleted(const OnMeshPrefix &aPrefix)
{
// Searches for a matching entry to `aPrefix` and if found marks
// it as deleted by setting prefix length to zero.
OnMeshPrefix *entry = Find(aPrefix);
if (entry != nullptr)
{
entry->SetLength(0);
}
}
} // namespace BorderRouter
} // namespace ot
+17 -6
View File
@@ -313,6 +313,12 @@ private:
static_assert(kRtrAdvStaleTime >= 1800 && kRtrAdvStaleTime <= kDefaultOnLinkPrefixLifetime,
"invalid RA STALE time");
enum RouterAdvTxMode : uint8_t // Used in `SendRouterAdvertisement()`
{
kInvalidateAllPrevPrefixes,
kAdvPrefixesFromNetData,
};
class DiscoveredPrefixTable : public InstanceLocator
{
// This class maintains the discovered on-link and route prefixes
@@ -509,10 +515,6 @@ private:
RoutePreference mPreference;
};
typedef Ip6::Prefix OnMeshPrefix;
typedef Array<OnMeshPrefix, kMaxOnMeshPrefixes> OnMeshPrefixArray;
class LocalOmrPrefix : InstanceLocator
{
public:
@@ -529,6 +531,15 @@ private:
bool mIsAddedInNetData;
};
typedef Ip6::Prefix OnMeshPrefix;
class OnMeshPrefixArray : public Array<OnMeshPrefix, kMaxOnMeshPrefixes>
{
public:
void Add(const OnMeshPrefix &aPrefix);
void MarkAsDeleted(const OnMeshPrefix &aPrefix);
};
void EvaluateState(void);
void Start(void);
void Stop(void);
@@ -548,12 +559,12 @@ private:
void EvaluateRoutingPolicy(void);
void StartRoutingPolicyEvaluationJitter(uint32_t aJitterMilli);
void StartRoutingPolicyEvaluationDelay(uint32_t aDelayMilli);
void EvaluateOmrPrefix(OnMeshPrefixArray &aNewPrefixes);
void EvaluateOmrPrefix(void);
Error PublishExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false);
void UnpublishExternalRoute(const Ip6::Prefix &aPrefix);
void StartRouterSolicitationDelay(void);
Error SendRouterSolicitation(void);
void SendRouterAdvertisement(const OnMeshPrefixArray &aNewPrefixes);
void SendRouterAdvertisement(RouterAdvTxMode aRaTxMode);
bool IsRouterSolicitationInProgress(void) const;
static void HandleRouterSolicitTimer(Timer &aTimer);