[routing-manager] learn and copy M & O flags from discovered routers (#9607)

This commit implements a mechanism in `RoutingManager` to learn the
Managed Address Config `M` and Other Config `O` flags in received RA
message from discovered routers on the infrastructure link and copy
the same flags in the emitted RA message from BR.

If any discovered router on the infrastructure that is not itself a
stub router (i.e., does not include the Stub Router flag) includes
the `M` or `O` flags, the same flag are included in the emitted RA
message. If a discovered router has failed to respond to the maximum
number of NS probe attempts, we consider it as offline and ignore its
flags.

This commit also adds a detailed test case in `test_routing_manager`
to validate the newly added mechanism.
This commit is contained in:
Abtin Keshavarzian
2023-11-20 16:37:08 -08:00
committed by GitHub
parent 364e315768
commit 34dd612008
4 changed files with 428 additions and 37 deletions
+72 -13
View File
@@ -620,6 +620,12 @@ void RoutingManager::SendRouterAdvertisement(RouterAdvTxMode aRaTxMode)
LogInfo("Preparing RA");
mDiscoveredPrefixTable.DetermineAndSetFlags(raMsg);
LogInfo("- RA Header - flags - M:%u O:%u", raMsg.GetHeader().IsManagedAddressConfigFlagSet(),
raMsg.GetHeader().IsOtherConfigFlagSet());
LogInfo("- RA Header - default route - lifetime:%u", raMsg.GetHeader().GetRouterLifetime());
#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE
SuccessOrAssert(raMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true));
LogInfo("- FlagsExt - StubRouter:1");
@@ -1242,7 +1248,7 @@ void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const Ip6
UpdateRouterOnRx(*router);
RemoveRoutersWithNoEntries();
RemoveRoutersWithNoEntriesOrFlags();
exit:
return;
@@ -1472,7 +1478,7 @@ void RoutingManager::DiscoveredPrefixTable::RemovePrefix(const Entry::Matcher &a
VerifyOrExit(!removedEntries.IsEmpty());
FreeEntries(removedEntries);
RemoveRoutersWithNoEntries();
RemoveRoutersWithNoEntriesOrFlags();
SignalTableChanged();
@@ -1482,21 +1488,17 @@ exit:
void RoutingManager::DiscoveredPrefixTable::RemoveAllEntries(void)
{
// Remove all entries from the table and unpublish them
// from Network Data.
// Remove all entries from the table.
for (Router &router : mRouters)
{
if (!router.mEntries.IsEmpty())
{
SignalTableChanged();
}
FreeEntries(router.mEntries);
}
RemoveRoutersWithNoEntries();
FreeRouters(mRouters);
mEntryTimer.Stop();
SignalTableChanged();
}
void RoutingManager::DiscoveredPrefixTable::RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold)
@@ -1592,11 +1594,11 @@ TimeMilli RoutingManager::DiscoveredPrefixTable::CalculateNextStaleTime(TimeMill
return foundOnLink ? Min(onLinkStaleTime, routeStaleTime) : routeStaleTime;
}
void RoutingManager::DiscoveredPrefixTable::RemoveRoutersWithNoEntries(void)
void RoutingManager::DiscoveredPrefixTable::RemoveRoutersWithNoEntriesOrFlags(void)
{
LinkedList<Router> routersToFree;
mRouters.RemoveAllMatching(Router::kContainsNoEntries, routersToFree);
mRouters.RemoveAllMatching(Router::kContainsNoEntriesOrFlags, routersToFree);
FreeRouters(routersToFree);
}
@@ -1668,7 +1670,7 @@ void RoutingManager::DiscoveredPrefixTable::RemoveExpiredEntries(void)
router.mEntries.RemoveAllMatching(Entry::ExpirationChecker(now), expiredEntries);
}
RemoveRoutersWithNoEntries();
RemoveRoutersWithNoEntriesOrFlags();
if (!expiredEntries.IsEmpty())
{
@@ -1792,6 +1794,42 @@ exit:
return;
}
void RoutingManager::DiscoveredPrefixTable::DetermineAndSetFlags(Ip6::Nd::RouterAdvertMessage &aRaMessage) const
{
// Determine the `M` and `O` flags to include in the RA message
// header `aRaMessage` to be emitted.
//
// If any discovered router on infrastructure which is not itself a
// stub router (e.g., another Thread BR) includes the `M` or `O`
// flag, we also include the same flag.
//
// If a router has failed to respond to max number of NS probe
// attempts, we consider it as offline and ignore its flags.
for (const Router &router : mRouters)
{
if (router.mStubRouterFlag)
{
continue;
}
if (router.mNsProbeCount > Router::kMaxNsProbes)
{
continue;
}
if (router.mManagedAddressConfigFlag)
{
aRaMessage.GetHeader().SetManagedAddressConfigFlag();
}
if (router.mOtherConfigFlag)
{
aRaMessage.GetHeader().SetOtherConfigFlag();
}
}
}
void RoutingManager::DiscoveredPrefixTable::InitIterator(PrefixTableIterator &aIterator) const
{
static_cast<Iterator &>(aIterator).Init(mRouters);
@@ -1995,6 +2033,27 @@ uint32_t RoutingManager::DiscoveredPrefixTable::Entry::CalculateExpireDelay(uint
//---------------------------------------------------------------------------------------------------------------------
// DiscoveredPrefixTable::Router
bool RoutingManager::DiscoveredPrefixTable::Router::Matches(EmptyChecker aChecker) const
{
// Checks whether or not a `Router` instance has any useful info. An
// entry can be removed if it does not advertise M or O flags and
// also does not have any advertised prefix entries (RIO/PIO). If
// the router already failed to respond to max NS probe attempts,
// we consider it as offline and therefore do not consider its
// flags anymore.
OT_UNUSED_VARIABLE(aChecker);
bool hasFlags = false;
if (mNsProbeCount <= kMaxNsProbes)
{
hasFlags = (mManagedAddressConfigFlag || mOtherConfigFlag);
}
return !hasFlags && mEntries.IsEmpty();
}
void RoutingManager::DiscoveredPrefixTable::Router::CopyInfoTo(RouterEntry &aEntry) const
{
aEntry.mAddress = mAddress;
+5 -3
View File
@@ -635,6 +635,8 @@ private:
TimeMilli CalculateNextStaleTime(TimeMilli aNow) const;
void DetermineAndSetFlags(Ip6::Nd::RouterAdvertMessage &aRaMessage) const;
void InitIterator(PrefixTableIterator &aIterator) const;
Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
Error GetNextRouter(PrefixTableIterator &aIterator, RouterEntry &aEntry) const;
@@ -770,11 +772,11 @@ private:
enum EmptyChecker : uint8_t
{
kContainsNoEntries
kContainsNoEntriesOrFlags
};
bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; }
bool Matches(EmptyChecker) const { return mEntries.IsEmpty(); }
bool Matches(EmptyChecker aChecker) const;
void CopyInfoTo(RouterEntry &aEntry) const;
Router *mNext;
@@ -816,7 +818,7 @@ private:
bool Contains(const Entry::Checker &aChecker) const;
void RemovePrefix(const Entry::Matcher &aMatcher);
void RemoveOrDeprecateEntriesFromInactiveRouters(void);
void RemoveRoutersWithNoEntries(void);
void RemoveRoutersWithNoEntriesOrFlags(void);
void FreeRouters(LinkedList<Router> &aRouters);
void FreeEntries(LinkedList<Entry> &aEntries);
void UpdateNetworkDataOnChangeTo(Entry &aEntry);
+8
View File
@@ -733,6 +733,14 @@ public:
*/
const Header &GetHeader(void) const { return *reinterpret_cast<const Header *>(mData.GetBytes()); }
/**
* Gets the RA message's header.
*
* @returns The RA message's header.
*
*/
Header &GetHeader(void) { return *reinterpret_cast<Header *>(AsNonConst(mData.GetBytes())); }
/**
* Appends a Prefix Info Option to the RA message.
*
+343 -21
View File
@@ -155,6 +155,18 @@ bool sRespondToNs; // Indicates whether or not to respond to NS.
ExpectedPio sExpectedPio; // Expected PIO in the emitted RA by BR (MUST be seen in RA to set `sRaValidated`).
uint32_t sOnLinkLifetime; // Valid lifetime for local on-link prefix from the last processed RA.
enum ExpectedRaHeaderFlags
{
kRaHeaderFlagsSkipChecking, // Skip checking the RA header flags.
kRaHeaderFlagsNone, // Expect no flag (neither M or O).
kRaHeaderFlagsOnlyM, // Expect M flag only.
kRaHeaderFlagsOnlyO, // Expect O flag only.
kRaHeaderFlagsBothMAndO, // Expect both M and O flags.
};
// The expected RA header flags when validating emitted RA message.
ExpectedRaHeaderFlags sExpectedRaHeaderFlags;
// Array containing deprecating prefixes from PIOs in the last processed RA.
Array<DeprecatingPrefix, kMaxDeprecatingPrefixes> sDeprecatingPrefixes;
@@ -371,9 +383,36 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket)
bool sawExpectedPio = false;
Array<Ip6::Prefix, kMaxPrefixes> pioPrefixes;
Array<Ip6::Prefix, kMaxPrefixes> rioPrefixes;
#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE
bool sawStubRouterFlag = false;
#endif
VerifyOrQuit(raMsg.IsValid());
VerifyOrQuit(raMsg.GetHeader().GetRouterLifetime() == 0);
switch (sExpectedRaHeaderFlags)
{
case kRaHeaderFlagsSkipChecking:
break;
case kRaHeaderFlagsNone:
VerifyOrQuit(!raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(!raMsg.GetHeader().IsOtherConfigFlagSet());
break;
case kRaHeaderFlagsOnlyM:
VerifyOrQuit(raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(!raMsg.GetHeader().IsOtherConfigFlagSet());
break;
case kRaHeaderFlagsOnlyO:
VerifyOrQuit(!raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(raMsg.GetHeader().IsOtherConfigFlagSet());
break;
case kRaHeaderFlagsBothMAndO:
VerifyOrQuit(raMsg.GetHeader().IsManagedAddressConfigFlagSet());
VerifyOrQuit(raMsg.GetHeader().IsOtherConfigFlagSet());
break;
}
sDeprecatingPrefixes.Clear();
for (const Ip6::Nd::Option &option : raMsg)
@@ -456,6 +495,7 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket)
VerifyOrQuit(flagsOption.IsValid());
VerifyOrQuit(flagsOption.IsStubRouterFlagSet());
sawStubRouterFlag = true;
break;
}
#endif
@@ -465,6 +505,10 @@ void ValidateRouterAdvert(const Icmp6Packet &aPacket)
}
}
#if OPENTHREAD_CONFIG_BORDER_ROUTING_STUB_ROUTER_FLAG_IN_EMITTED_RA_ENABLE
VerifyOrQuit(sawStubRouterFlag);
#endif
if (!sRaValidated)
{
switch (sExpectedPio)
@@ -524,6 +568,8 @@ void LogRouterAdvert(const Icmp6Packet &aPacket)
VerifyOrQuit(raMsg.IsValid());
Log(" RA header - M:%u, O:%u", raMsg.GetHeader().IsManagedAddressConfigFlagSet(),
raMsg.GetHeader().IsOtherConfigFlagSet());
Log(" RA header - lifetime %u, prf:%s", raMsg.GetHeader().GetRouterLifetime(),
PreferenceToString(raMsg.GetHeader().GetDefaultRouterPreference()));
@@ -788,13 +834,28 @@ struct DefaultRoute
RoutePreference mPreference;
};
struct RaFlags : public Clearable<RaFlags>
{
RaFlags(void)
: mManagedAddressConfigFlag(false)
, mOtherConfigFlag(false)
, mStubRouterFlag(false)
{
}
bool mManagedAddressConfigFlag;
bool mOtherConfigFlag;
bool mStubRouterFlag;
};
template <size_t N>
uint16_t BuildRouterAdvert(uint8_t (&aBuffer)[N],
const Pio *aPios,
uint16_t aNumPios,
const Rio *aRios,
uint16_t aNumRios,
const DefaultRoute &aDefaultRoute)
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
Ip6::Nd::RouterAdvertMessage::Header header;
uint16_t length;
@@ -802,9 +863,24 @@ uint16_t BuildRouterAdvert(uint8_t (&aBuffer)[N],
header.SetRouterLifetime(aDefaultRoute.mLifetime);
header.SetDefaultRouterPreference(aDefaultRoute.mPreference);
if (aRaFlags.mManagedAddressConfigFlag)
{
header.SetManagedAddressConfigFlag();
}
if (aRaFlags.mOtherConfigFlag)
{
header.SetOtherConfigFlag();
}
{
Ip6::Nd::RouterAdvertMessage raMsg(header, aBuffer);
if (aRaFlags.mStubRouterFlag)
{
SuccessOrQuit(raMsg.AppendFlagsExtensionOption(/* aStubRouterFlag */ true));
}
for (; aNumPios > 0; aPios++, aNumPios--)
{
SuccessOrQuit(
@@ -827,10 +903,11 @@ void SendRouterAdvert(const Ip6::Address &aRouterAddress,
uint16_t aNumPios,
const Rio *aRios,
uint16_t aNumRios,
const DefaultRoute &aDefaultRoute)
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags)
{
uint8_t buffer[kMaxRaSize];
uint16_t length = BuildRouterAdvert(buffer, aPios, aNumPios, aRios, aNumRios, aDefaultRoute);
uint16_t length = BuildRouterAdvert(buffer, aPios, aNumPios, aRios, aNumRios, aDefaultRoute, aRaFlags);
SendRouterAdvert(aRouterAddress, buffer, length);
Log("Sending RA from router %s", aRouterAddress.ToString().AsCString());
@@ -841,37 +918,48 @@ template <uint16_t kNumPios, uint16_t kNumRios>
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const Pio (&aPios)[kNumPios],
const Rio (&aRios)[kNumRios],
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium))
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, aDefaultRoute);
SendRouterAdvert(aRouterAddress, aPios, kNumPios, aRios, kNumRios, aDefaultRoute, aRaFlags);
}
template <uint16_t kNumPios>
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const Pio (&aPios)[kNumPios],
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium))
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, aDefaultRoute);
SendRouterAdvert(aRouterAddress, aPios, kNumPios, nullptr, 0, aDefaultRoute, aRaFlags);
}
template <uint16_t kNumRios>
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const Rio (&aRios)[kNumRios],
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium))
const DefaultRoute &aDefaultRoute = DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, nullptr, 0, aRios, kNumRios, aDefaultRoute);
SendRouterAdvert(aRouterAddress, nullptr, 0, aRios, kNumRios, aDefaultRoute, aRaFlags);
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const DefaultRoute &aDefaultRoute)
void SendRouterAdvert(const Ip6::Address &aRouterAddress,
const DefaultRoute &aDefaultRoute,
const RaFlags &aRaFlags = RaFlags())
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, aDefaultRoute);
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, aDefaultRoute, aRaFlags);
}
void SendRouterAdvert(const Ip6::Address &aRouterAddress, const RaFlags &aRaFlags)
{
SendRouterAdvert(aRouterAddress, nullptr, 0, nullptr, 0, DefaultRoute(0, NetworkData::kRoutePreferenceMedium),
aRaFlags);
}
template <uint16_t kNumPios> void SendRouterAdvertToBorderRoutingProcessIcmp6Ra(const Pio (&aPios)[kNumPios])
{
uint8_t buffer[kMaxRaSize];
uint16_t length =
BuildRouterAdvert(buffer, aPios, kNumPios, nullptr, 0, DefaultRoute(0, NetworkData::kRoutePreferenceMedium));
uint16_t length = BuildRouterAdvert(buffer, aPios, kNumPios, nullptr, 0,
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), RaFlags());
otPlatBorderRoutingProcessIcmp6Ra(sInstance, buffer, length);
Log("Passing RA to otPlatBorderRoutingProcessIcmp6Ra");
@@ -996,6 +1084,66 @@ void VerifyPrefixTable(const OnLinkPrefix *aOnLinkPrefixes,
void VerifyPrefixTableIsEmpty(void) { VerifyPrefixTable(nullptr, 0, nullptr, 0); }
struct InfraRouter
{
InfraRouter(const Ip6::Address &aAddress,
bool aManagedAddressConfigFlag,
bool aOtherConfigFlag,
bool aStubRouterFlag)
: mAddress(aAddress)
{
mFlags.Clear();
mFlags.mManagedAddressConfigFlag = aManagedAddressConfigFlag;
mFlags.mOtherConfigFlag = aOtherConfigFlag;
mFlags.mStubRouterFlag = aStubRouterFlag;
}
Ip6::Address mAddress;
RaFlags mFlags;
};
template <uint16_t kNumRouters> void VerifyDiscoveredRouters(const InfraRouter (&aRouters)[kNumRouters])
{
VerifyDiscoveredRouters(aRouters, kNumRouters);
}
void VerifyDiscoveredRouters(const InfraRouter *aRouters, uint16_t aNumRouters)
{
BorderRouter::RoutingManager::PrefixTableIterator iter;
BorderRouter::RoutingManager::RouterEntry entry;
uint16_t count = 0;
Log("VerifyDiscoveredRouters()");
sInstance->Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(iter);
while (sInstance->Get<BorderRouter::RoutingManager>().GetNextRouterEntry(iter, entry) == kErrorNone)
{
bool didFind = false;
Log(" address:%s, M:%u, O:%u, StubRouter:%u", AsCoreType(&entry.mAddress).ToString().AsCString(),
entry.mManagedAddressConfigFlag, entry.mOtherConfigFlag, entry.mStubRouterFlag);
for (uint16_t index = 0; index < aNumRouters; index++)
{
if (AsCoreType(&entry.mAddress) == aRouters[index].mAddress)
{
VerifyOrQuit(entry.mManagedAddressConfigFlag == aRouters[index].mFlags.mManagedAddressConfigFlag);
VerifyOrQuit(entry.mOtherConfigFlag == aRouters[index].mFlags.mOtherConfigFlag);
VerifyOrQuit(entry.mStubRouterFlag == aRouters[index].mFlags.mStubRouterFlag);
didFind = true;
}
}
VerifyOrQuit(didFind);
count++;
}
VerifyOrQuit(count == aNumRouters);
}
void VerifyDiscoveredRoutersIsEmpty(void) { VerifyDiscoveredRouters(nullptr, 0); }
void InitTest(bool aEnablBorderRouting = false, bool aAfterReset = false)
{
uint32_t delay = 10000;
@@ -1032,19 +1180,20 @@ void InitTest(bool aEnablBorderRouting = false, bool aAfterReset = false)
SuccessOrQuit(otThreadSetEnabled(sInstance, true));
SuccessOrQuit(otBorderRoutingSetEnabled(sInstance, aEnablBorderRouting));
// Reset all test flags
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kNoPio;
sExpectedRios.Clear();
sRespondToNs = true;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Ensure device starts as leader.
AdvanceTime(delay);
VerifyOrQuit(otThreadGetDeviceRole(sInstance) == OT_DEVICE_ROLE_LEADER);
// Reset all test flags
sRsEmitted = false;
sRaValidated = false;
sExpectedPio = kNoPio;
sExpectedRios.Clear();
sRespondToNs = true;
}
void FinalizeTest(void)
@@ -2599,6 +2748,178 @@ void TestRouterNsProbe(void)
FinalizeTest();
}
void TestLearningAndCopyingOfFlags(void)
{
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
Ip6::Address routerAddressB = AddressFromString("fd00::bbbb");
Ip6::Address routerAddressC = AddressFromString("fd00::cccc");
uint16_t heapAllocations;
RaFlags raFlags;
Log("--------------------------------------------------------------------------------------------");
Log("TestLearningAndCopyingOfFlags");
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));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(localOnLink));
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().GetOmrPrefix(localOmr));
Log("Local on-link prefix is %s", localOnLink.ToString().AsCString());
Log("Local OMR prefix is %s", localOmr.ToString().AsCString());
sExpectedRios.Add(localOmr);
AdvanceTime(30000);
VerifyOrQuit(sRsEmitted);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
Log("Received RA was validated");
VerifyDiscoveredRoutersIsEmpty();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with M flag set, and make sure the
// emitted RA from BR also includes M flag.
raFlags.Clear();
raFlags.mManagedAddressConfigFlag = true;
SendRouterAdvert(routerAddressA, raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ false)});
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsOnlyM;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A without the M flag. Now the emitted
// RA should no longer contain the M flag.
raFlags.Clear();
SendRouterAdvert(routerAddressA, raFlags);
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
AdvanceTime(1);
VerifyDiscoveredRoutersIsEmpty();
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with both M and StubRouter flags.
// Since it is from a stub router, the M flag should be ignored.
// Ensure emitted RA does not set the M flag.
raFlags.Clear();
raFlags.mManagedAddressConfigFlag = true;
raFlags.mStubRouterFlag = true;
SendRouterAdvert(routerAddressA, raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ true)});
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router B with O flag and check that emitted
// RA include the same flag.
raFlags.Clear();
raFlags.mOtherConfigFlag = true;
SendRouterAdvert(routerAddressB, raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ true),
InfraRouter(routerAddressB, /* M */ false, /* O */ true, /* StubRouter */ false)});
sRaValidated = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsOnlyO;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router C with M flag and check that emitted
// RA now includes both M and O flags.
raFlags.Clear();
raFlags.mManagedAddressConfigFlag = true;
SendRouterAdvert(routerAddressC, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime)},
DefaultRoute(0, NetworkData::kRoutePreferenceMedium), raFlags);
AdvanceTime(1);
VerifyDiscoveredRouters({InfraRouter(routerAddressA, /* M */ true, /* O */ false, /* StubRouter */ true),
InfraRouter(routerAddressB, /* M */ false, /* O */ true, /* StubRouter */ false),
InfraRouter(routerAddressC, /* M */ true, /* O */ false, /* StubRouter */ false)});
sRaValidated = false;
sExpectedPio = kPioDeprecatingLocalOnLink;
sExpectedRaHeaderFlags = kRaHeaderFlagsBothMAndO;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Stop responding to NS, this should cause all routers
// to age and considered offline
sRespondToNs = false;
sExpectedRaHeaderFlags = kRaHeaderFlagsSkipChecking;
AdvanceTime(300 * 1000);
// Router C should be in the table since it will have a deprecating
// on-link prefix.
VerifyDiscoveredRouters({InfraRouter(routerAddressC, /* M */ true, /* O */ false, /* StubRouter */ false)});
sRaValidated = false;
sExpectedPio = kPioAdvertisingLocalOnLink;
sExpectedRaHeaderFlags = kRaHeaderFlagsNone;
AdvanceTime(610 * 1000);
VerifyOrQuit(sRaValidated);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyDiscoveredRoutersIsEmpty();
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestLearningAndCopyingOfFlags");
FinalizeTest();
}
void TestConflictingPrefix(void)
{
static const otExtendedPanId kExtPanId1 = {{0x01, 0x02, 0x03, 0x04, 0x05, 0x6, 0x7, 0x08}};
@@ -3569,6 +3890,7 @@ int main(void)
ot::TestExtPanIdChange();
ot::TestConflictingPrefix();
ot::TestRouterNsProbe();
ot::TestLearningAndCopyingOfFlags();
#if OPENTHREAD_CONFIG_PLATFORM_FLASH_API_ENABLE
ot::TestSavedOnLinkPrefixes();
#endif
@@ -3580,7 +3902,7 @@ int main(void)
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
ot::TestBorderRoutingProcessPlatfromGeneratedNd();
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
#endif
printf("All tests passed\n");
#else