mirror of
https://github.com/espressif/openthread.git
synced 2026-06-06 05:24:51 +00:00
[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:
committed by
GitHub
parent
24d633d99d
commit
c0babfe319
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user