[routing-manager] add manual OMR prefix configuration on BR (#11365)

This commit introduces a new mechanism in `RoutingManager` to
configure OMR prefix handling on a Border Router. This provides
manual administration options to explicitly set a custom OMR prefix
or disable it, in addition to the existing default behavior where the
BR automatically selects and manages the OMR prefix. These new
administrative configurations can also be used during testing,
particularly for certification tests.

This commit adds new public OpenThread APIs and a CLI command,
`br omrconfig`, for this functionality. Notably, the new APIs allow
updating the OMR configuration while the BR is enabled and running,
and the implementation correctly adjusts to the new requested
behavior.

A new detailed test case is added to the `test_routing_manager` unit
test, covering the new behavior.
This commit is contained in:
Abtin Keshavarzian
2025-04-01 13:10:29 -07:00
committed by GitHub
parent f8c8f8fb1c
commit 42fbcbde2c
8 changed files with 733 additions and 37 deletions
+275 -1
View File
@@ -709,7 +709,7 @@ Ip6::Address AddressFromString(const char *aString)
return address;
}
void VerifyOmrPrefixInNetData(const Ip6::Prefix &aOmrPrefix, bool aDefaultRoute)
void VerifyOmrPrefixInNetData(const Ip6::Prefix &aOmrPrefix, bool aDefaultRoute, RoutePreference *aPreference = nullptr)
{
otNetworkDataIterator iterator = OT_NETWORK_DATA_ITERATOR_INIT;
NetworkData::OnMeshPrefixConfig prefixConfig;
@@ -724,6 +724,11 @@ void VerifyOmrPrefixInNetData(const Ip6::Prefix &aOmrPrefix, bool aDefaultRoute)
VerifyOrQuit(prefixConfig.mOnMesh == true);
VerifyOrQuit(prefixConfig.mDefaultRoute == aDefaultRoute);
if (aPreference != nullptr)
{
VerifyOrQuit(prefixConfig.mPreference == *aPreference);
}
VerifyOrQuit(otNetDataGetNextOnMeshPrefix(sInstance, &iterator, &prefixConfig) == kErrorNotFound);
}
@@ -1625,6 +1630,274 @@ void TestOmrSelection(void)
FinalizeTest();
}
void TestOmrConfig(void)
{
using OmrConfig = BorderRouter::RoutingManager::OmrConfig;
static constexpr OmrConfig kOmrConfigAuto = BorderRouter::RoutingManager::kOmrConfigAuto;
static constexpr OmrConfig kOmrConfigCustom = BorderRouter::RoutingManager::kOmrConfigCustom;
static constexpr OmrConfig kOmrConfigDisabled = BorderRouter::RoutingManager::kOmrConfigDisabled;
Ip6::Prefix localOmr;
RoutePreference preference;
Ip6::Prefix prefix;
Ip6::Prefix customPrefix = PrefixFromString("2000:0000:1111:4444::", 64);
uint16_t heapAllocations;
OmrConfig omrConfig;
Log("--------------------------------------------------------------------------------------------");
Log("TestOmrConfig");
InitTest();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Start Routing Manager. Check emitted RS and RA messages.
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
heapAllocations = sHeapAllocatedPtrs.GetLength();
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(true));
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
VerifyOrQuit(omrConfig == kOmrConfigAuto);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Update OMR config to disable it
preference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigDisabled, nullptr, preference));
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
VerifyOrQuit(omrConfig == kOmrConfigDisabled);
AdvanceTime(100);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Make sure BR emits RA with the new OMR prefix now, and deprecates the old OMR prefix.
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(20 * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime);
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow);
// Check Network Data. We should now see no OMR prefix in the Network Data.
VerifyNoOmrPrefixInNetData();
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
VerifyOrQuit(prefix.GetLength() == 0);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Update OMR config back `kOmrConfigAuto` mode.
preference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigAuto, nullptr, preference));
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
VerifyOrQuit(omrConfig == kOmrConfigAuto);
AdvanceTime(100);
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
AdvanceTime(30 * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Update OMR config to `kOmrConfigCustom` mode to use a custom prefix
preference = NetworkData::kRoutePreferenceMedium;
SuccessOrQuit(
sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigCustom, &customPrefix, preference));
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(&prefix, &preference);
VerifyOrQuit(omrConfig == kOmrConfigCustom);
VerifyOrQuit(prefix == customPrefix);
VerifyOrQuit(preference == NetworkData::kRoutePreferenceMedium);
AdvanceTime(100);
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(customPrefix);
sExpectedRios.Add(localOmr);
AdvanceTime(60 * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Update the custom prefix preference value to high.
preference = NetworkData::kRoutePreferenceHigh;
SuccessOrQuit(
sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigCustom, &customPrefix, preference));
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(&prefix, &preference);
VerifyOrQuit(omrConfig == kOmrConfigCustom);
VerifyOrQuit(prefix == customPrefix);
VerifyOrQuit(preference == NetworkData::kRoutePreferenceHigh);
AdvanceTime(100);
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(customPrefix);
sExpectedRios.Add(localOmr);
AdvanceTime(60 * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Wait for previous local OMR to be fully deprecated and validate that is no
// longer seen in the emitted RA.
AdvanceTime(350 * 1000);
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Add(customPrefix);
AdvanceTime(200 * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOmrPrefixInNetData(customPrefix, /* aDefaultRoute */ false, &preference);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
VerifyOrQuit(prefix == customPrefix);
VerifyOrQuit(preference == NetworkData::kRoutePreferenceHigh);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Switch back to `kOmrConfigDiable` mode. Check that custom prefix is
// removed from Network Data and we see it deprecating in emitted RAs.
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigDisabled, nullptr, preference));
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
VerifyOrQuit(omrConfig == kOmrConfigDisabled);
AdvanceTime(100);
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(customPrefix);
AdvanceTime(60 * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime <= kRioDeprecatingLifetime);
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceLow);
VerifyNoOmrPrefixInNetData();
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
VerifyOrQuit(prefix.GetLength() == 0);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Switch back to `kOmrConfigAuto` mode.
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetOmrConfig(kOmrConfigAuto, nullptr, preference));
omrConfig = sInstance->Get<BorderRouter::RoutingManager>().GetOmrConfig(nullptr, nullptr);
VerifyOrQuit(omrConfig == kOmrConfigAuto);
AdvanceTime(100);
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRios.Clear();
sExpectedRios.Add(localOmr);
sExpectedRios.Add(customPrefix);
AdvanceTime(60 * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
VerifyOrQuit(sExpectedRios[0].mLifetime == kRioValidLifetime);
VerifyOrQuit(sExpectedRios[0].mPreference == NetworkData::kRoutePreferenceMedium);
VerifyOrQuit(sExpectedRios[1].mLifetime <= kRioDeprecatingLifetime);
VerifyOrQuit(sExpectedRios[1].mPreference == NetworkData::kRoutePreferenceLow);
preference = NetworkData::kRoutePreferenceLow;
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false, &preference);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetFavoredOmrPrefix(prefix, preference));
VerifyOrQuit(prefix == localOmr);
VerifyOrQuit(preference == NetworkData::kRoutePreferenceLow);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestOmrConfig");
FinalizeTest();
}
void TestDefaultRoute(void)
{
Ip6::Prefix localOnLink;
@@ -4714,6 +4987,7 @@ int main(void)
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
ot::TestSamePrefixesFromMultipleRouters();
ot::TestOmrSelection();
ot::TestOmrConfig();
ot::TestDefaultRoute();
ot::TestAdvNonUlaRoute();
ot::TestFavoredOnLinkPrefix();