[routing-manager] track all valid PIOs with on-link (L) flag (#11925)

Removes the `IsValidOnLinkPrefix()` helper functions which required a PIO
to have both the on-link (`L`) flag and either the autonomous address
configuration (`A`) or DHCPv6-PD preferred (`P`) flag to be considered
valid.

The `RxRaTracker` is updated to track any received valid PIO as long as
the on-link (`L`) flag is set, regardless of the `A` or `P` flags.

The `OnLinkPrefix` class is updated to store the state of the `A` and
`P` flags from the PIO. These flags are now checked within
`OnLinkPrefix::IsFavoredOver()` to determine if a prefix is eligible
to be a "favored" on-link prefix, but their absence no longer prevents
the prefix from being tracked.

This change ensures that the routing manager is aware of all non-ULA
on-link prefixes (even those with only the L flag set), which correctly
informs the decision to publish a default route.

This commit also:
- Updates `PrefixInfoOption` in `nd6.hpp` to use a `Flags` typedef and
  named constants instead of bitmasks.
- Updates `LogPrefixInfoOption` to log the state of L, A, and P flags.
- Adds a new unit test, `TestNonUlaPioWithOnlyOnLinkFlag`, to verify
  the new behavior.
This commit is contained in:
Abtin Keshavarzian
2025-09-17 16:06:29 -07:00
committed by GitHub
parent d27527ce54
commit fbc123940e
5 changed files with 229 additions and 72 deletions
+124 -2
View File
@@ -816,16 +816,27 @@ void VerifyNat64PrefixInNetData(const Ip6::Prefix &aNat64Prefix)
struct Pio
{
Pio(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime)
using Flags = Ip6::Nd::PrefixInfoOption::Flags;
static constexpr Flags kOnLinkFlag = Ip6::Nd::PrefixInfoOption::kOnLinkFlag;
static constexpr Flags kAutoConfigFlag = Ip6::Nd::PrefixInfoOption::kAutoConfigFlag;
static constexpr Flags kDhcp6Flag = Ip6::Nd::PrefixInfoOption::kDhcp6PdPreferredFlag;
Pio(const Ip6::Prefix &aPrefix,
uint32_t aValidLifetime,
uint32_t aPreferredLifetime,
Flags aFlags = kOnLinkFlag | kAutoConfigFlag)
: mPrefix(aPrefix)
, mValidLifetime(aValidLifetime)
, mPreferredLifetime(aPreferredLifetime)
, mFlags(aFlags)
{
}
const Ip6::Prefix &mPrefix;
uint32_t mValidLifetime;
uint32_t mPreferredLifetime;
Flags mFlags;
};
struct Rio
@@ -921,7 +932,8 @@ void BuildRouterAdvert(Ip6::Nd::RouterAdvert::TxMessage &aRaMsg,
for (; aNumPios > 0; aPios++, aNumPios--)
{
SuccessOrQuit(aRaMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime));
SuccessOrQuit(aRaMsg.AppendPrefixInfoOption(aPios->mPrefix, aPios->mValidLifetime, aPios->mPreferredLifetime,
aPios->mFlags));
}
for (; aNumRios > 0; aRios++, aNumRios--)
@@ -2050,6 +2062,115 @@ void TestDefaultRoute(void)
FinalizeTest();
}
void TestNonUlaPioWithOnlyOnLinkFlag(void)
{
static constexpr uint32_t kMaxRaTxInterval = 196; // In seconds
Ip6::Prefix localOnLink;
Ip6::Prefix localOmr;
Ip6::Prefix onLinkPrefix = PrefixFromString("2000:abba:baba::", 64);
Ip6::Address routerAddressA = AddressFromString("fd00::aaaa");
uint16_t heapAllocations;
Log("--------------------------------------------------------------------------------------------");
Log("TestNonUlaPioWithOnlyOnLinkFlag");
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");
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the Network Data to include the local OMR and on-link prefix.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Send an RA from router A with a new on-link (PIO) with
// only on-link (L) flag (no A or P).
SendRouterAdvert(routerAddressA, {Pio(onLinkPrefix, kValidLitime, kPreferredLifetime, Pio::kOnLinkFlag)});
sRaValidated = false;
AdvanceTime(10000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the discovered prefix table and ensure info from router A
// is present in the table.
VerifyPrefixTable({OnLinkPrefix(onLinkPrefix, kValidLitime, kPreferredLifetime, routerAddressA)});
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check the Network Data. Now that we have observed a non-ULA
// on-link prefix (even with only on-link `L` flag), a default
// route should be published.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ true);
VerifyExternalRouteInNetData(kDefaultRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that BR is still advertising its local on-link prefix.
AdvanceTime(kMaxRaTxInterval * 1000);
VerifyOrQuit(sRaValidated);
VerifyOrQuit(sExpectedRios.SawAll());
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Disallow responding to NS messages. This should cause
// the router A to be deemed unreachable and its prefix
// entries aged out and then removed.
sRespondToNs = false;
AdvanceTime(kValidLitime * 1000 + 1000);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Check that the discovered prefix table is now empty.
VerifyPrefixTableIsEmpty();
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Validate that the BR is no longer publishing a default route.
VerifyOmrPrefixInNetData(localOmr, /* aDefaultRoute */ false);
VerifyExternalRouteInNetData(kUlaRoute, kWithAdvPioFlagSet);
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
SuccessOrQuit(sInstance->Get<BorderRouter::RoutingManager>().SetEnabled(false));
VerifyOrQuit(heapAllocations == sHeapAllocatedPtrs.GetLength());
Log("End of TestNonUlaPioWithOnlyOnLinkFlag");
FinalizeTest();
}
void TestAdvNonUlaRoute(void)
{
Ip6::Prefix localOnLink;
@@ -5001,6 +5122,7 @@ int main(void)
ot::TestOmrSelection();
ot::TestOmrConfig();
ot::TestDefaultRoute();
ot::TestNonUlaPioWithOnlyOnLinkFlag();
ot::TestAdvNonUlaRoute();
ot::TestFavoredOnLinkPrefix();
ot::TestLocalOnLinkPrefixDeprecation();