From 549b02e11cf315fd0a20ac79b4ec6c0b37c87f6a Mon Sep 17 00:00:00 2001 From: Simon Lin Date: Wed, 16 Mar 2022 03:47:26 +0800 Subject: [PATCH] [routing-manager] add minimal delay between RAs (#7473) This commit adds minimal delay (3 seconds) between consecutive Router Advertisements according to `6.2.6. Processing Router Solicitations, RFC4861`. --- src/core/border_router/routing_manager.cpp | 13 +++++++++++-- src/core/border_router/routing_manager.hpp | 4 +++- .../border_router/test_multi_thread_networks.py | 3 +++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/core/border_router/routing_manager.cpp b/src/core/border_router/routing_manager.cpp index eab130619..0276b8897 100644 --- a/src/core/border_router/routing_manager.cpp +++ b/src/core/border_router/routing_manager.cpp @@ -72,6 +72,7 @@ RoutingManager::RoutingManager(Instance &aInstance) , mDiscoveredPrefixInvalidTimer(aInstance, HandleDiscoveredPrefixInvalidTimer) , mDiscoveredPrefixStaleTimer(aInstance, HandleDiscoveredPrefixStaleTimer) , mRouterAdvertisementCount(0) + , mLastRouterAdvertisementSendTime(TimerMilli::GetNow()) #if OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE , mVicariousRouterSolicitTimer(aInstance, HandleVicariousRouterSolicitTimer) #endif @@ -772,8 +773,15 @@ void RoutingManager::StartRoutingPolicyEvaluationJitter(uint32_t aJitterMilli) void RoutingManager::StartRoutingPolicyEvaluationDelay(uint32_t aDelayMilli) { - LogInfo("Start evaluating routing policy, scheduled in %u milliseconds", aDelayMilli); - mRoutingPolicyTimer.FireAtIfEarlier(TimerMilli::GetNow() + aDelayMilli); + TimeMilli now = TimerMilli::GetNow(); + TimeMilli evaluateTime = now + aDelayMilli; + TimeMilli earlestTime = mLastRouterAdvertisementSendTime + kMinDelayBetweenRtrAdvs; + + evaluateTime = OT_MAX(evaluateTime, earlestTime); + + LogInfo("Start evaluating routing policy, scheduled in %u milliseconds", evaluateTime - now); + + mRoutingPolicyTimer.FireAtIfEarlier(evaluateTime); } // starts sending Router Solicitations in random delay @@ -928,6 +936,7 @@ void RoutingManager::SendRouterAdvertisement(const OmrPrefixArray &aNewOmrPrefix if (error == kErrorNone) { + mLastRouterAdvertisementSendTime = TimerMilli::GetNow(); LogInfo("Sent Router Advertisement on interface %u", mInfraIfIndex); DumpDebg("[BR-CERT] direction=send | type=RA |", buffer, bufferLength); } diff --git a/src/core/border_router/routing_manager.hpp b/src/core/border_router/routing_manager.hpp index ea9e454da..43017e81d 100644 --- a/src/core/border_router/routing_manager.hpp +++ b/src/core/border_router/routing_manager.hpp @@ -220,6 +220,7 @@ private: static constexpr uint32_t kMaxRtrSolicitationDelay = 1; // Max delay for initial solicitation. In sec. static constexpr uint32_t kRoutingPolicyEvaluationJitter = 1000; // Jitter for routing policy evaluation. In msec. static constexpr uint32_t kRtrSolicitationRetryDelay = 60; // The delay before retrying failed RS tx. In Sec. + static constexpr uint32_t kMinDelayBetweenRtrAdvs = 3000; // Min delay (msec) between consecutive RAs. // The STALE_RA_TIME in seconds. The Routing Manager will consider the prefixes // and learned RA parameters STALE when they are not refreshed in STALE_RA_TIME @@ -413,7 +414,8 @@ private: TimerMilli mDiscoveredPrefixInvalidTimer; TimerMilli mDiscoveredPrefixStaleTimer; - uint32_t mRouterAdvertisementCount; + uint32_t mRouterAdvertisementCount; + TimeMilli mLastRouterAdvertisementSendTime; #if OPENTHREAD_CONFIG_BORDER_ROUTING_VICARIOUS_RS_ENABLE TimerMilli mVicariousRouterSolicitTimer; diff --git a/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py b/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py index c75026b69..ca7e382d9 100755 --- a/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py +++ b/tests/scripts/thread-cert/border_router/test_multi_thread_networks.py @@ -108,6 +108,9 @@ class MultiThreadNetworks(thread_cert.TestCase): self.simulator.go(5) self.assertEqual('router', router2.get_state()) + # Wait for network to stabilize + self.simulator.go(15) + self.collect_ipaddrs() logging.info("BR1 addrs: %r", br1.get_addrs())