From f2f98c565f804318281ea6cb9aa00c11a8636e81 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 30 Jun 2022 12:18:31 -0700 Subject: [PATCH] [routing-manager] skip self-prepared RA when learning host RA header (#7846) This commit updates how `RoutingManager` learns the RA header from host daemons. It adds a new method to determine whether a received RA message is prepared by the `RoutingManager` itself by checking the options (PIO and RIO) from the RA message. When learning/updating the host RA header, we check and skip over such self-prepared RA messages. --- src/core/border_router/routing_manager.cpp | 73 ++++++++++++++++++++++ src/core/border_router/routing_manager.hpp | 1 + 2 files changed, 74 insertions(+) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index 452692bb6..51d6b79bf 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -913,6 +913,68 @@ void RoutingManager::SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefix } } +bool RoutingManager::IsReceivdRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const +{ + // Determines whether or not a received RA message was prepared by + // by `RoutingManager` itself. + + bool isFromManager = false; + uint16_t rioCount = 0; + Ip6::Prefix prefix; + + VerifyOrExit(aRaMessage.ContainsAnyOptions()); + + for (const Ip6::Nd::Option &option : aRaMessage) + { + switch (option.GetType()) + { + case Ip6::Nd::Option::kTypePrefixInfo: + { + // PIO should match `mLocalOnLinkPrefix`. + + const Ip6::Nd::PrefixInfoOption &pio = static_cast(option); + + VerifyOrExit(pio.IsValid()); + pio.GetPrefix(prefix); + + VerifyOrExit(prefix == mLocalOnLinkPrefix); + break; + } + + case Ip6::Nd::Option::kTypeRouteInfo: + { + // RIO (with non-zero lifetime) should match entries from + // `mAdvertisedOmrPrefixes`. We keep track of the number + // of matched RIOs and check after the loop ends that all + // entries were seen. + + const Ip6::Nd::RouteInfoOption &rio = static_cast(option); + + VerifyOrExit(rio.IsValid()); + rio.GetPrefix(prefix); + + if (rio.GetRouteLifetime() != 0) + { + VerifyOrExit(mAdvertisedOmrPrefixes.ContainsMatching(prefix)); + rioCount++; + } + + break; + } + + default: + ExitNow(); + } + } + + VerifyOrExit(rioCount == mAdvertisedOmrPrefixes.GetLength()); + + isFromManager = true; + +exit: + return isFromManager; +} + bool RoutingManager::IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix) { return aBrUlaPrefix.mLength == kBrUlaPrefixLength && aBrUlaPrefix.mPrefix.mFields.m8[0] == 0xfd; @@ -1174,6 +1236,14 @@ void RoutingManager::UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage Ip6::Nd::RouterAdvertMessage::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(!IsReceivdRouterAdvertFromManager(*aRouterAdvertMessage)); + } + oldHeader = mRouterAdvertHeader; mTimeRouterAdvMessageLastUpdate = TimerMilli::GetNow(); @@ -1203,6 +1273,9 @@ void RoutingManager::UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage StartRoutingPolicyEvaluationJitter(kRoutingPolicyEvaluationJitter); } + +exit: + return; } void RoutingManager::ResetDiscoveredPrefixStaleTimer(void) diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index fc2a6583c..3b923207d 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -478,6 +478,7 @@ private: void HandleDiscoveredPrefixTableChanged(void); bool NetworkDataContainsOmrPrefix(const Ip6::Prefix &aPrefix) const; void UpdateRouterAdvertHeader(const Ip6::Nd::RouterAdvertMessage *aRouterAdvertMessage); + bool IsReceivdRouterAdvertFromManager(const Ip6::Nd::RouterAdvertMessage &aRaMessage) const; void ResetDiscoveredPrefixStaleTimer(void); static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);