From e27885ecb4b745fb819a2e311b37fda3bd79248f Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 14 May 2024 11:04:56 -0700 Subject: [PATCH] [routing-manager] track origin of received RA messages (#10229) This commit adds `RouterAdvOrigin` enumeration to track the origin of a received RA message, whether it is from another router on the infrastructure, or self-generated by either the `RoutingManager` module or another software entity running on the device. This is used to exclude prefixes from self-generated `RoutingManager` RAs in the prefix table and simplifies learning and adopting of RA headers from other software entities on the same device. The origin is now logged when a new RA is received for improved debugging. This commit also updates `test_routing_manager` to pass back any sent RA messages to the OT stack. This validates the mechanism for identifying self-generated RA messages. --- src/core/border_router/routing_manager.cpp | 69 ++++++++++++++-------- src/core/border_router/routing_manager.hpp | 15 ++++- tests/unit/test_routing_manager.cpp | 1 + 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index f666c41b2..75a3be9ca 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -699,7 +699,7 @@ void RoutingManager::HandleRsSenderFinished(TimeMilli aStartTime) if (mRaInfo.mHeaderUpdateTime <= aStartTime) { - UpdateRouterAdvertHeader(/* aRouterAdvertMessage */ nullptr); + UpdateRouterAdvertHeader(/* aRouterAdvertMessage */ nullptr, kThisBrOtherEntity); } ScheduleRoutingPolicyEvaluation(kImmediately); @@ -737,26 +737,29 @@ exit: void RoutingManager::HandleRouterAdvertisement(const InfraIf::Icmp6Packet &aPacket, const Ip6::Address &aSrcAddress) { - RouterAdvert::RxMessage routerAdvMessage(aPacket); + RouterAdvert::RxMessage raMsg(aPacket); + RouterAdvOrigin raOrigin = kAnotherRouter; OT_ASSERT(mIsRunning); - VerifyOrExit(routerAdvMessage.IsValid()); + VerifyOrExit(raMsg.IsValid()); Get().GetBorderRoutingCounters().mRaRx++; - LogInfo("Received RA from %s on %s", aSrcAddress.ToString().AsCString(), mInfraIf.ToString().AsCString()); - DumpDebg("[BR-CERT] direction=recv | type=RA |", aPacket.GetBytes(), aPacket.GetLength()); - - mDiscoveredPrefixTable.ProcessRouterAdvertMessage(routerAdvMessage, aSrcAddress); - - // Remember the header and parameters of RA messages which are - // initiated from the infra interface. if (mInfraIf.HasAddress(aSrcAddress)) { - UpdateRouterAdvertHeader(&routerAdvMessage); + raOrigin = mRaInfo.IsRaFromManager(raMsg) ? kThisBrRoutingManager : kThisBrOtherEntity; } + LogInfo("Received RA from %s on %s %s", aSrcAddress.ToString().AsCString(), mInfraIf.ToString().AsCString(), + RouterAdvOriginToString(raOrigin)); + + DumpDebg("[BR-CERT] direction=recv | type=RA |", aPacket.GetBytes(), aPacket.GetLength()); + + mDiscoveredPrefixTable.ProcessRouterAdvertMessage(raMsg, aSrcAddress, raOrigin); + + UpdateRouterAdvertHeader(&raMsg, raOrigin); + exit: return; } @@ -885,24 +888,18 @@ bool RoutingManager::NetworkDataContainsUlaRoute(void) const return contains; } -void RoutingManager::UpdateRouterAdvertHeader(const RouterAdvert::RxMessage *aRouterAdvertMessage) +void RoutingManager::UpdateRouterAdvertHeader(const RouterAdvert::RxMessage *aRaMsg, RouterAdvOrigin aRaOrigin) { // Updates the `mRaInfo` from the given RA message. RouterAdvert::Header oldHeader; - if (aRouterAdvertMessage != nullptr) - { - // We skip and do not update RA header if the received RA message - // was not prepared and sent by `RoutingManager` itself. - - VerifyOrExit(!mRaInfo.IsRaFromManager(*aRouterAdvertMessage)); - } + VerifyOrExit(aRaOrigin == kThisBrOtherEntity); oldHeader = mRaInfo.mHeader; mRaInfo.mHeaderUpdateTime = TimerMilli::GetNow(); - if (aRouterAdvertMessage == nullptr || aRouterAdvertMessage->GetHeader().GetRouterLifetime() == 0) + if (aRaMsg == nullptr || aRaMsg->GetHeader().GetRouterLifetime() == 0) { mRaInfo.mHeader.SetToDefault(); mRaInfo.mIsHeaderFromHost = false; @@ -913,7 +910,7 @@ void RoutingManager::UpdateRouterAdvertHeader(const RouterAdvert::RxMessage *aRo // which indicates to platform that it needs to do the // calculation and update it. - mRaInfo.mHeader = aRouterAdvertMessage->GetHeader(); + mRaInfo.mHeader = aRaMsg->GetHeader(); mRaInfo.mHeader.SetChecksum(0); mRaInfo.mIsHeaderFromHost = true; } @@ -970,6 +967,7 @@ void RoutingManager::ResetDiscoveredPrefixStaleTimer(void) } #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) + void RoutingManager::LogPrefixInfoOption(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime) @@ -983,10 +981,28 @@ void RoutingManager::LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLi LogInfo("- RIO %s (lifetime:%lu, prf:%s)", aPrefix.ToString().AsCString(), ToUlong(aLifetime), RoutePreferenceToString(aPreference)); } + +const char *RoutingManager::RouterAdvOriginToString(RouterAdvOrigin aRaOrigin) +{ + static const char *const kOriginStrings[] = { + "", // (0) kAnotherRouter + "(this BR routing-manager)", // (1) kThisBrRoutingManager + "(this BR other sw entity)", // (2) kThisBrOtherEntity + }; + + static_assert(0 == kAnotherRouter, "kAnotherRouter value is incorrect"); + static_assert(1 == kThisBrRoutingManager, "kThisBrRoutingManager value is incorrect"); + static_assert(2 == kThisBrOtherEntity, "kThisBrOtherEntity value is incorrect"); + + return kOriginStrings[aRaOrigin]; +} + #else + void RoutingManager::LogPrefixInfoOption(const Ip6::Prefix &, uint32_t, uint32_t) {} void RoutingManager::LogRouteInfoOption(const Ip6::Prefix &, uint32_t, RoutePreference) {} -#endif + +#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) //--------------------------------------------------------------------------------------------------------------------- // LifetimedPrefix @@ -1118,11 +1134,16 @@ RoutingManager::DiscoveredPrefixTable::DiscoveredPrefixTable(Instance &aInstance } void RoutingManager::DiscoveredPrefixTable::ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage, - const Ip6::Address &aSrcAddress) + const Ip6::Address &aSrcAddress, + RouterAdvOrigin aRaOrigin) { // Process a received RA message and update the prefix table. - Router *router = mRouters.FindMatching(aSrcAddress); + Router *router; + + VerifyOrExit(aRaOrigin != kThisBrRoutingManager); + + router = mRouters.FindMatching(aSrcAddress); if (router == nullptr) { diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index 4f8aa6a1c..16f4601d4 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -629,6 +629,13 @@ private: kAdvPrefixesFromNetData, }; + enum RouterAdvOrigin : uint8_t // Origin of a received Router Advert message. + { + kAnotherRouter, // From another router on infra-if. + kThisBrRoutingManager, // From this BR generated by `RoutingManager` itself. + kThisBrOtherEntity, // From this BR generated by another sw entity. + }; + enum ScheduleMode : uint8_t // Used in `ScheduleRoutingPolicyEvaluation()` { kImmediately, @@ -738,7 +745,9 @@ private: public: explicit DiscoveredPrefixTable(Instance &aInstance); - void ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage, const Ip6::Address &aSrcAddress); + void ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage, + const Ip6::Address &aSrcAddress, + RouterAdvOrigin aRaOrigin); void ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage); bool ContainsDefaultOrNonUlaRoutePrefix(void) const; @@ -1392,7 +1401,7 @@ private: void UpdateDiscoveredPrefixTableOnNetDataChange(void); bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const; bool NetworkDataContainsUlaRoute(void) const; - void UpdateRouterAdvertHeader(const RouterAdvert::RxMessage *aRouterAdvertMessage); + void UpdateRouterAdvertHeader(const RouterAdvert::RxMessage *aRaMsg, RouterAdvOrigin aRaOrigin); void ResetDiscoveredPrefixStaleTimer(void); static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix); @@ -1402,6 +1411,8 @@ private: static void LogPrefixInfoOption(const Ip6::Prefix &aPrefix, uint32_t aValidLifetime, uint32_t aPreferredLifetime); static void LogRouteInfoOption(const Ip6::Prefix &aPrefix, uint32_t aLifetime, RoutePreference aPreference); + static const char *RouterAdvOriginToString(RouterAdvOrigin aRaOrigin); + //------------------------------------------------------------------------------------------------------------------ // Variables diff --git a/tests/unit/test_routing_manager.cpp b/tests/unit/test_routing_manager.cpp index c2d6fe84f..928a52b5c 100644 --- a/tests/unit/test_routing_manager.cpp +++ b/tests/unit/test_routing_manager.cpp @@ -317,6 +317,7 @@ otError otPlatInfraIfSendIcmp6Nd(uint32_t aInfraIfIndex, Log(" Router Advertisement message"); LogRouterAdvert(packet); ValidateRouterAdvert(packet); + otPlatInfraIfRecvIcmp6Nd(sInstance, kInfraIfIndex, &sInfraIfAddress, aBuffer, aBufferLength); break; case Ip6::Icmp::Header::kTypeNeighborSolicit: