[routing-manager] add OmrPrefix class, include OMR preference in RIO (#7778)

This commit updates `RoutingManager` to track the preference of the
discovered OMR prefixes from Thread Network Data and advertise the
OMR prefixes with the same preference in Route Info Options in the
emitted Router Advertisements.

This commit adds `OmrPrefix` class (which tracks an OMR prefix along
with its preference) and provides helpers method (e.g., method to
compare two OMR prefixes to determine which one is favored, `ToString
()` method). The `EvaluateOmrPrefix()` is updated to use the new
`OmrPrefix` class.
This commit is contained in:
Abtin Keshavarzian
2022-06-02 15:33:12 -07:00
committed by GitHub
parent 24d633d99d
commit c0babfe319
3 changed files with 142 additions and 51 deletions
+112 -50
View File
@@ -365,85 +365,98 @@ void RoutingManager::EvaluateOmrPrefix(OmrPrefixArray &aNewOmrPrefixes)
{
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
NetworkData::OnMeshPrefixConfig onMeshPrefixConfig;
Ip6::Prefix * electedOmrPrefix = nullptr;
signed int electedOmrPrefixPreference = 0;
Ip6::Prefix * publishedLocalOmrPrefix = nullptr;
OmrPrefix * favoredOmrEntry = nullptr;
OmrPrefix * localOmrEntry = nullptr;
OT_ASSERT(mIsRunning);
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, onMeshPrefixConfig) == kErrorNone)
{
const Ip6::Prefix &prefix = onMeshPrefixConfig.GetPrefix();
OmrPrefix *entry;
if (!IsValidOmrPrefix(onMeshPrefixConfig))
{
continue;
}
if (aNewOmrPrefixes.Contains(prefix))
{
// Ignore duplicate prefixes.
continue;
}
entry = aNewOmrPrefixes.FindMatching(onMeshPrefixConfig.GetPrefix());
if (aNewOmrPrefixes.PushBack(prefix) != kErrorNone)
if (entry != nullptr)
{
LogWarn("EvaluateOmrPrefix: Too many OMR prefixes, ignoring prefix %s", prefix.ToString().AsCString());
continue;
// Update the entry if we find the same prefix with higher
// preference in network data
if (onMeshPrefixConfig.GetPreference() <= entry->GetPreference())
{
continue;
}
entry->SetPreference(onMeshPrefixConfig.GetPreference());
}
else
{
entry = aNewOmrPrefixes.PushBack();
if (entry == nullptr)
{
LogWarn("EvaluateOmrPrefix: Too many OMR prefixes, ignoring prefix %s",
onMeshPrefixConfig.GetPrefix().ToString().AsCString());
continue;
}
entry->InitFrom(onMeshPrefixConfig);
}
if (onMeshPrefixConfig.mPreferred)
{
if (electedOmrPrefix == nullptr || onMeshPrefixConfig.mPreference > electedOmrPrefixPreference ||
(onMeshPrefixConfig.mPreference == electedOmrPrefixPreference && prefix < *electedOmrPrefix))
if ((favoredOmrEntry == nullptr) || (entry->IsFavoredOver(*favoredOmrEntry)))
{
electedOmrPrefix = aNewOmrPrefixes.Back();
electedOmrPrefixPreference = onMeshPrefixConfig.mPreference;
favoredOmrEntry = entry;
}
}
if (prefix == mLocalOmrPrefix)
if (entry->GetPrefix() == mLocalOmrPrefix)
{
publishedLocalOmrPrefix = aNewOmrPrefixes.Back();
localOmrEntry = entry;
}
}
// Decide if we need to add or remove our local OMR prefix.
if (electedOmrPrefix == nullptr)
if (favoredOmrEntry == nullptr)
{
LogInfo("EvaluateOmrPrefix: No preferred OMR prefixes found in Thread network");
if (PublishLocalOmrPrefix() == kErrorNone)
{
IgnoreError(aNewOmrPrefixes.PushBack(mLocalOmrPrefix));
}
// The `aNewOmrPrefixes` remains empty if we fail to publish
// the local OMR prefix.
SuccessOrExit(PublishLocalOmrPrefix());
localOmrEntry = aNewOmrPrefixes.PushBack();
VerifyOrExit(localOmrEntry != nullptr);
localOmrEntry->Init(mLocalOmrPrefix, NetworkData::kRoutePreferenceMedium);
}
else
else if (favoredOmrEntry == localOmrEntry)
{
if (*electedOmrPrefix == mLocalOmrPrefix)
{
IgnoreError(PublishLocalOmrPrefix());
}
else if (IsOmrPrefixAddedToLocalNetworkData())
{
LogInfo("EvaluateOmrPrefix: There is already a preferred OMR prefix %s (pref=%d) in the Thread network",
electedOmrPrefix->ToString().AsCString(), electedOmrPrefixPreference);
IgnoreError(PublishLocalOmrPrefix());
}
else if (IsOmrPrefixAddedToLocalNetworkData())
{
LogInfo("EvaluateOmrPrefix: There is already a preferred OMR prefix %s in the Thread network",
favoredOmrEntry->ToString().AsCString());
UnpublishLocalOmrPrefix();
UnpublishLocalOmrPrefix();
if (localOmrEntry != nullptr)
{
// Remove the local OMR prefix from the list by overwriting it
// with the last element and then popping it from the list.
if (publishedLocalOmrPrefix != nullptr)
{
*publishedLocalOmrPrefix = *aNewOmrPrefixes.Back();
aNewOmrPrefixes.PopBack();
}
// with popped last entry in the list.
*localOmrEntry = *aNewOmrPrefixes.PopBack();
}
}
exit:
return;
}
Error RoutingManager::PublishLocalOmrPrefix(void)
@@ -874,13 +887,14 @@ void RoutingManager::SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefix
// Invalidate the advertised OMR prefixes if they are no longer in the new OMR prefix array.
for (const Ip6::Prefix &advertisedOmrPrefix : mAdvertisedOmrPrefixes)
for (const OmrPrefix &advertisedOmrPrefix : mAdvertisedOmrPrefixes)
{
if (!aNewOmrPrefixes.Contains(advertisedOmrPrefix))
if (!aNewOmrPrefixes.ContainsMatching(advertisedOmrPrefix.GetPrefix()))
{
RouterAdv::RouteInfoOption *rio;
OT_ASSERT(bufferLength + RouterAdv::RouteInfoOption::OptionSizeForPrefix(advertisedOmrPrefix.GetLength()) <=
OT_ASSERT(bufferLength + RouterAdv::RouteInfoOption::OptionSizeForPrefix(
advertisedOmrPrefix.GetPrefix().GetLength()) <=
sizeof(buffer));
rio = reinterpret_cast<RouterAdv::RouteInfoOption *>(buffer + bufferLength);
@@ -888,7 +902,7 @@ void RoutingManager::SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefix
// Set zero route lifetime to immediately invalidate the advertised OMR prefix.
rio->Init();
rio->SetRouteLifetime(0);
rio->SetPrefix(advertisedOmrPrefix);
rio->SetPrefix(advertisedOmrPrefix.GetPrefix());
bufferLength += rio->GetSize();
@@ -897,18 +911,20 @@ void RoutingManager::SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefix
}
}
for (const Ip6::Prefix &newOmrPrefix : aNewOmrPrefixes)
for (const OmrPrefix &newOmrPrefix : aNewOmrPrefixes)
{
RouterAdv::RouteInfoOption *rio;
OT_ASSERT(bufferLength + RouterAdv::RouteInfoOption::OptionSizeForPrefix(newOmrPrefix.GetLength()) <=
OT_ASSERT(bufferLength +
RouterAdv::RouteInfoOption::OptionSizeForPrefix(newOmrPrefix.GetPrefix().GetLength()) <=
sizeof(buffer));
rio = reinterpret_cast<RouterAdv::RouteInfoOption *>(buffer + bufferLength);
rio->Init();
rio->SetRouteLifetime(kDefaultOmrPrefixLifetime);
rio->SetPrefix(newOmrPrefix);
rio->SetPreference(newOmrPrefix.GetPreference());
rio->SetPrefix(newOmrPrefix.GetPrefix());
bufferLength += rio->GetSize();
@@ -1254,7 +1270,7 @@ void RoutingManager::UpdateDiscoveredOmrPrefix(const RouterAdv::RouteInfoOption
// messages are usually faster than Thread Network Data propagation).
// They are the reasons why we need both the checks.
VerifyOrExit(!mAdvertisedOmrPrefixes.Contains(prefix));
VerifyOrExit(!mAdvertisedOmrPrefixes.ContainsMatching(prefix));
VerifyOrExit(!NetworkDataContainsOmrPrefix(prefix));
LogInfo("Discovered OMR prefix (%s, %u seconds) from %s", prefix.ToString().AsCString(), aRio.GetRouteLifetime(),
@@ -1315,8 +1331,8 @@ void RoutingManager::InvalidateDiscoveredPrefixes(void)
// Data).
if ((prefix.GetExpireTime() <= now) ||
(!prefix.IsOnLinkPrefix() &&
(mAdvertisedOmrPrefixes.Contains(prefix.GetPrefix()) || NetworkDataContainsOmrPrefix(prefix.GetPrefix()))))
(!prefix.IsOnLinkPrefix() && (mAdvertisedOmrPrefixes.ContainsMatching(prefix.GetPrefix()) ||
NetworkDataContainsOmrPrefix(prefix.GetPrefix()))))
{
UnpublishExternalRoute(prefix.GetPrefix());
@@ -1560,6 +1576,52 @@ uint32_t RoutingManager::ExternalPrefix::GetPrefixExpireDelay(uint32_t aValidLif
return delay;
}
//---------------------------------------------------------------------------------------------------------------------
// OmrPrefix
void RoutingManager::OmrPrefix::Init(const Ip6::Prefix &aPrefix, RoutePreference aPreference)
{
mPrefix = aPrefix;
mPreference = aPreference;
}
void RoutingManager::OmrPrefix::InitFrom(NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig)
{
Init(aOnMeshPrefixConfig.GetPrefix(), aOnMeshPrefixConfig.GetPreference());
}
bool RoutingManager::OmrPrefix::IsFavoredOver(const OmrPrefix &aOther) const
{
// This method determines whether this OMR prefix is favored
// over `aOther` prefix. A prefix with higher preference is
// favored. If the preference is the same, then the smaller
// prefix (in the sense defined by `Ip6::Prefix`) is favored.
return (mPreference > aOther.mPreference) || ((mPreference == aOther.mPreference) && (mPrefix < aOther.mPrefix));
}
RoutingManager::OmrPrefix::InfoString RoutingManager::OmrPrefix::ToString(void) const
{
InfoString string;
string.Append("%s (prf:", mPrefix.ToString().AsCString());
switch (mPreference)
{
case NetworkData::kRoutePreferenceHigh:
string.Append("high)");
break;
case NetworkData::kRoutePreferenceMedium:
string.Append("med)");
break;
case NetworkData::kRoutePreferenceLow:
string.Append("low)");
break;
}
return string;
}
} // namespace BorderRouter
} // namespace ot
+22 -1
View File
@@ -55,6 +55,7 @@
#include "common/error.hpp"
#include "common/locator.hpp"
#include "common/notifier.hpp"
#include "common/string.hpp"
#include "common/timer.hpp"
#include "net/ip6.hpp"
#include "thread/network_data.hpp"
@@ -278,7 +279,27 @@ private:
bool mIsOnLinkPrefix;
};
typedef Array<Ip6::Prefix, kMaxOmrPrefixNum> OmrPrefixArray;
class OmrPrefix // An OMR Prefix
{
public:
static constexpr uint16_t kInfoStringSize = 60;
typedef String<kInfoStringSize> InfoString;
void Init(const Ip6::Prefix &aPrefix, RoutePreference aPreference);
void InitFrom(NetworkData::OnMeshPrefixConfig &aOnMeshPrefixConfig);
const Ip6::Prefix &GetPrefix(void) const { return mPrefix; }
RoutePreference GetPreference(void) const { return mPreference; }
void SetPreference(RoutePreference aPreference) { mPreference = aPreference; }
bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; }
bool IsFavoredOver(const OmrPrefix &aOther) const;
InfoString ToString(void) const;
private:
Ip6::Prefix mPrefix;
RoutePreference mPreference;
};
typedef Array<OmrPrefix, kMaxOmrPrefixNum> OmrPrefixArray;
typedef Array<ExternalPrefix, kMaxDiscoveredPrefixNum> ExternalPrefixArray;
void EvaluateState(void);
+8
View File
@@ -190,6 +190,14 @@ public:
*/
Ip6::Prefix &GetPrefix(void) { return AsCoreType(&mPrefix); }
/**
* This method gets the preference.
*
* @return The preference.
*
*/
RoutePreference GetPreference(void) const { return RoutePreferenceFromValue(RoutePreferenceToValue(mPreference)); }
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE
/**
* This method indicates whether or not the prefix configuration is valid.