[routing-manager] fix small OMR prefix election issue (#7405)
This commit fixes two small issues regarding OMR prefix election:
- This commit handles the case where `mLocalOmrPrefix` is already in
Leader's Network Data, but not locally added. It is possible when
the BR restores the Network Data from Leader. In such case the BR
should re-add `mLocalOmrPrefix` to local Network Data so that it
keeps advertising OMR Prefix. Otherwise, the OMR Prefix will be
removed from Leader's Network Data because of Network Data
inconsistentency, and then all BRs start to re-elect OMR Prefix. So,
the change will make the OMR Prefix more stable in some corner
cases.
- The change here checks if `mLocalOmrPrefix` was added to the Local
Network Data, instead of checking if `mLocalOmrPrefix` is added to
the Leader's Network Data. Here the BR has already decided that it
should not be advertising `mLocalOmrPrefix`. Whether or not
`mLocalOmrPrefix` is in Leader's Network Data is relevant. The BR
only needs to remove `mLocalOmrPrefix` from Local Network Data and
eventually Local Network Data will synchronize with Leader's Network
Data. The original code also has a potential issue that the BR may
send `NET_DATA.ntf` to Leader indefinitely when these conditions are
met:
- `mLocalOmrPrefix` was added to Local Network Data
- `mLocalOmrPrefix` is not added to Leader' Network Data because
there is no more space in Leader's Network Data
diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp
index d7686d5..69d3287 100644
--- a/src/core/border_router/routing_manager.cpp
+++ b/src/core/border_router/routing_manager.cpp
@@ -462,18 +462,29 @@
// The `aNewOmrPrefixes` remains empty if we fail to publish
// the local OMR prefix.
}
- else if (publishedLocalOmrPrefix != nullptr && smallestOmrPrefix != publishedLocalOmrPrefix)
+ else
{
- LogInfo("EvaluateOmrPrefix: There is already a smaller OMR prefix %s in the Thread network",
- smallestOmrPrefix->ToString().AsCString());
+ OT_ASSERT(smallestOmrPrefix != nullptr);
- UnpublishLocalOmrPrefix();
+ if (*smallestOmrPrefix == mLocalOmrPrefix)
+ {
+ IgnoreError(PublishLocalOmrPrefix());
+ }
+ else if (IsOmrPrefixAddedToLocalNetworkData())
+ {
+ LogInfo("EvaluateOmrPrefix: There is already a smaller OMR prefix %s in the Thread network",
+ smallestOmrPrefix->ToString().AsCString());
- // Remove the local OMR prefix from the list by overwriting it
- // with the last element and then popping it from the list.
+ UnpublishLocalOmrPrefix();
- *publishedLocalOmrPrefix = *aNewOmrPrefixes.Back();
- aNewOmrPrefixes.PopBack();
+ // 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();
+ }
+ }
}
}
@@ -484,6 +495,8 @@
OT_ASSERT(mIsRunning);
+ VerifyOrExit(!IsOmrPrefixAddedToLocalNetworkData());
+
omrPrefixConfig.Clear();
omrPrefixConfig.mPrefix = mLocalOmrPrefix;
omrPrefixConfig.mStable = true;
@@ -505,6 +518,7 @@
LogInfo("Publishing local OMR prefix %s in Thread network", mLocalOmrPrefix.ToString().AsCString());
}
+exit:
return error;
}
@@ -514,6 +528,8 @@
VerifyOrExit(mIsRunning);
+ VerifyOrExit(IsOmrPrefixAddedToLocalNetworkData());
+
SuccessOrExit(error = Get<NetworkData::Local>().RemoveOnMeshPrefix(mLocalOmrPrefix));
Get<NetworkData::Notifier>().HandleServerDataUpdated();
@@ -527,6 +543,11 @@
}
}
+bool RoutingManager::IsOmrPrefixAddedToLocalNetworkData(void) const
+{
+ return Get<NetworkData::Local>().ContainsOnMeshPrefix(mLocalOmrPrefix);
+}
+
Error RoutingManager::AddExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64)
{
Error error;
diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp
index 01325f8..cd6e14b 100644
--- a/src/core/border_router/routing_manager.hpp
+++ b/src/core/border_router/routing_manager.hpp
@@ -305,6 +305,7 @@
void EvaluateOmrPrefix(OmrPrefixArray &aNewOmrPrefixes);
Error PublishLocalOmrPrefix(void);
void UnpublishLocalOmrPrefix(void);
+ bool IsOmrPrefixAddedToLocalNetworkData(void) const;
Error AddExternalRoute(const Ip6::Prefix &aPrefix, RoutePreference aRoutePreference, bool aNat64 = false);
void RemoveExternalRoute(const Ip6::Prefix &aPrefix);
void StartRouterSolicitationDelay(void);
diff --git a/src/core/thread/network_data_local.cpp b/src/core/thread/network_data_local.cpp
index 8095a95..b558140 100644
--- a/src/core/thread/network_data_local.cpp
+++ b/src/core/thread/network_data_local.cpp
@@ -69,6 +69,20 @@
return RemovePrefix(aPrefix, NetworkDataTlv::kTypeBorderRouter);
}
+bool Local::ContainsOnMeshPrefix(const Ip6::Prefix &aPrefix) const
+{
+ const PrefixTlv *tlv;
+ bool contains = false;
+
+ VerifyOrExit((tlv = FindPrefix(aPrefix)) != nullptr);
+ VerifyOrExit(tlv->FindSubTlv(NetworkDataTlv::kTypeBorderRouter) != nullptr);
+
+ contains = true;
+
+exit:
+ return contains;
+}
+
Error Local::AddHasRoutePrefix(const ExternalRouteConfig &aConfig)
{
Error error = kErrorInvalidArgs;
diff --git a/src/core/thread/network_data_local.hpp b/src/core/thread/network_data_local.hpp
index de28794..1123af6 100644
--- a/src/core/thread/network_data_local.hpp
+++ b/src/core/thread/network_data_local.hpp
@@ -98,6 +98,17 @@
Error RemoveOnMeshPrefix(const Ip6::Prefix &aPrefix);
/**
+ * This method indicates whether or not the Thread Network Data contains a given on mesh prefix.
+ *
+ * @param[in] aPrefix The on mesh prefix to check.
+ *
+ * @retval TRUE if Network Data contains mesh prefix @p aPrefix.
+ * @retval FALSE if Network Data does not contain mesh prefix @p aPrefix.
+ *
+ */
+ bool ContainsOnMeshPrefix(const Ip6::Prefix &aPrefix) const;
+
+ /**
* This method adds a Has Route entry to the Thread Network data.
*
* @param[in] aConfig A reference to the external route configuration.