From b37528645a57ca963dc847a67a2d783d401c20c6 Mon Sep 17 00:00:00 2001 From: Rongli Sun Date: Wed, 15 Apr 2020 10:36:14 +0800 Subject: [PATCH] [bbr] (Un)Subscribe AllDomainBBRs multicast address (#4795) This commit includes: - cache domain prefix in the Thread Network - subscribe/unsubscribe AllDomainBBRs Multicast address - update test to cover AllNetworkBBRs and AllDomainBBRs subscription --- src/core/backbone_router/leader.cpp | 128 ++++++++++++++++-- src/core/backbone_router/leader.hpp | 60 ++++++-- src/core/backbone_router/local.cpp | 1 - src/core/backbone_router/local.hpp | 1 + src/core/net/ip6_address.hpp | 13 +- src/core/thread/mle.cpp | 43 +++++- src/core/thread/mle.hpp | 26 +++- tests/scripts/thread-cert/config.py | 2 + tests/scripts/thread-cert/node.py | 14 ++ .../v1_2_test_backbone_router_service.py | 15 +- 10 files changed, 266 insertions(+), 37 deletions(-) diff --git a/src/core/backbone_router/leader.cpp b/src/core/backbone_router/leader.cpp index 1fa6f70f7..1994499ad 100644 --- a/src/core/backbone_router/leader.cpp +++ b/src/core/backbone_router/leader.cpp @@ -35,16 +35,9 @@ #if (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2) -#include "common/code_utils.hpp" -#include "common/debug.hpp" #include "common/instance.hpp" #include "common/locator-getters.hpp" #include "common/logging.hpp" -#include "common/settings.hpp" - -#include "thread/network_data_leader.hpp" -#include "thread/network_data_tlvs.hpp" -#include "thread/thread_netif.hpp" namespace ot { namespace BackboneRouter { @@ -57,8 +50,11 @@ Leader::Leader(Instance &aInstance) void Leader::Reset(void) { - memset(&mConfig, 0, sizeof(mConfig)); + // Invalid server short address indicates no available Backbone Router service in the Thread Network. mConfig.mServer16 = Mac::kShortAddrInvalid; + + // Domain Prefix Length 0 indicates no available Domain Prefix in the Thread network. + mDomainPrefix.mLength = 0; } otError Leader::GetConfig(BackboneRouterConfig &aConfig) const @@ -87,11 +83,12 @@ exit: return error; } +#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_NETDATA == 1) void Leader::LogBackboneRouterPrimary(State aState, const BackboneRouterConfig &aConfig) const { OT_UNUSED_VARIABLE(aConfig); - otLogInfoNetData("BBR state %s", StateToString(aState)); + otLogInfoNetData("PBBR state: %s", StateToString(aState)); if (aState != kStateRemoved && aState != kStateNone) { @@ -100,6 +97,14 @@ void Leader::LogBackboneRouterPrimary(State aState, const BackboneRouterConfig & } } +void Leader::LogDomainPrefix(DomainPrefixState aState, const otIp6Prefix &aPrefix) const +{ + otLogInfoNetData("Domain Prefix: %s/%d, state: %s", + aPrefix.mLength == 0 ? "" + : static_cast(&aPrefix.mPrefix)->ToString().AsCString(), + aPrefix.mLength, DomainPrefixStateToString(aState)); +} + const char *Leader::StateToString(State aState) { const char *logString = "Unknown"; @@ -107,27 +112,27 @@ const char *Leader::StateToString(State aState) switch (aState) { case kStateNone: - logString = "PBBR: None"; + logString = "None"; break; case kStateAdded: - logString = "PBBR: Added"; + logString = "Added"; break; case kStateRemoved: - logString = "PBBR: Removed"; + logString = "Removed"; break; case kStateToTriggerRereg: - logString = "PBBR: To trigger re-registration"; + logString = "Rereg triggered"; break; case kStateRefreshed: - logString = "PBBR: Refreshed"; + logString = "Refreshed"; break; case kStateUnchanged: - logString = "PBBR: Unchanged"; + logString = "Unchanged"; break; default: @@ -137,7 +142,44 @@ const char *Leader::StateToString(State aState) return logString; } +const char *Leader::DomainPrefixStateToString(DomainPrefixState aState) +{ + const char *logString = "Unknown"; + + switch (aState) + { + case kDomainPrefixNone: + logString = "None"; + break; + + case kDomainPrefixAdded: + logString = "Added"; + break; + + case kDomainPrefixRemoved: + logString = "Removed"; + break; + + case kDomainPrefixRefreshed: + logString = "Refreshed"; + break; + + case kDomainPrefixUnchanged: + logString = "Unchanged"; + break; + } + + return logString; +} +#endif + void Leader::Update(void) +{ + UpdateBackboneRouterPrimary(); + UpdateDomainPrefixConfig(); +} + +void Leader::UpdateBackboneRouterPrimary(void) { BackboneRouterConfig config; State state; @@ -186,6 +228,62 @@ void Leader::Update(void) #endif } +void Leader::UpdateDomainPrefixConfig(void) +{ + NetworkData::Iterator iterator = NetworkData::kIteratorInit; + NetworkData::OnMeshPrefixConfig config; + DomainPrefixState state; + bool found = false; + + while (Get().GetNextOnMeshPrefix(iterator, config) == OT_ERROR_NONE) + { + if (config.mDp) + { + found = true; + break; + } + } + + if (!found) + { + if (mDomainPrefix.mLength != 0) + { + // Domain Prefix does not exist any more. + mDomainPrefix.mLength = 0; + state = kDomainPrefixRemoved; + } + else + { + state = kDomainPrefixNone; + } + } + else if (config.mPrefix.mLength == mDomainPrefix.mLength && + Ip6::Address::PrefixMatch(mDomainPrefix.mPrefix.mFields.m8, config.mPrefix.mPrefix.mFields.m8, + BitVectorBytes(mDomainPrefix.mLength)) >= mDomainPrefix.mLength) + { + state = kDomainPrefixUnchanged; + } + else + { + if (mDomainPrefix.mLength == 0) + { + state = kDomainPrefixAdded; + } + else + { + state = kDomainPrefixRefreshed; + } + + mDomainPrefix = config.mPrefix; + } + + LogDomainPrefix(state, mDomainPrefix); + +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + Get().UpdateAllDomainBackboneRouters(state); +#endif +} + } // namespace BackboneRouter } // namespace ot diff --git a/src/core/backbone_router/leader.hpp b/src/core/backbone_router/leader.hpp index 8ea1a96f3..1cf76dc44 100644 --- a/src/core/backbone_router/leader.hpp +++ b/src/core/backbone_router/leader.hpp @@ -56,16 +56,26 @@ typedef otBackboneRouterConfig BackboneRouterConfig; class Leader : public InstanceLocator { public: - // Primary Backbone Router Service State or State change. + // Primary Backbone Router Service state or state change. enum State { - kStateNone = 0, // Not exist (trigger Backbone Router register its service). - kStateAdded, // Newly added. - kStateRemoved, // Newly removed (trigger Backbone Router register its service). - kStateToTriggerRereg, // Short address or sequence number changes (trigger re-registration). - // May also have ReregistrationDelay or MlrTimeout update. - kStateRefreshed, // Only ReregistrationDelay or MlrTimeout changes. - kStateUnchanged, // No change on Primary Backbone Router information (only for logging). + kStateNone = 0, ///< Not exist (trigger Backbone Router register its service). + kStateAdded, ///< Newly added. + kStateRemoved, ///< Newly removed (trigger Backbone Router register its service). + kStateToTriggerRereg, ///< Short address or sequence number changes (trigger re-registration). + ///< May also have ReregistrationDelay or MlrTimeout update. + kStateRefreshed, ///< Only ReregistrationDelay or MlrTimeout changes. + kStateUnchanged, ///< No change on Primary Backbone Router information (only for logging). + }; + + // Domain Prefix state or state change. + enum DomainPrefixState + { + kDomainPrefixNone = 0, ///< Not available. + kDomainPrefixAdded, ///< Added. + kDomainPrefixRemoved, ///< Removed. + kDomainPrefixRefreshed, ///< Changed. + kDomainPrefixUnchanged, ///< Nothing changed. }; /** @@ -126,11 +136,37 @@ public: */ bool HasPrimary(void) const { return mConfig.mServer16 != Mac::kShortAddrInvalid; } -private: - void LogBackboneRouterPrimary(State aState, const BackboneRouterConfig &aConfig) const; - static const char *StateToString(State aState); + /** + * This method gets the Domain Prefix in the Thread Network. + * + * @retval A pointer to the Domain Prefix or NULL if there is no Domain Prefix. + * + */ + const otIp6Prefix *GetDomainPrefix(void) const { return (mDomainPrefix.mLength == 0) ? NULL : &mDomainPrefix; } - BackboneRouterConfig mConfig; ///< Primary Backbone Router information. + /** + * This method indicates whether or not the Domain Prefix is available in the Thread Network. + * + * @retval TRUE if there is Domain Prefix, FALSE otherwise. + * + */ + bool HasDomainPrefix(void) const { return (mDomainPrefix.mLength > 0); } + +private: + void UpdateBackboneRouterPrimary(void); + void UpdateDomainPrefixConfig(void); +#if (OPENTHREAD_CONFIG_LOG_LEVEL >= OT_LOG_LEVEL_INFO) && (OPENTHREAD_CONFIG_LOG_NETDATA == 1) + void LogBackboneRouterPrimary(State aState, const BackboneRouterConfig &aConfig) const; + void LogDomainPrefix(DomainPrefixState aState, const otIp6Prefix &aPrefix) const; + static const char *StateToString(State aState); + static const char *DomainPrefixStateToString(DomainPrefixState aState); +#else + void LogBackboneRouterPrimary(State, const BackboneRouterConfig &) const {} + void LogDomainPrefix(DomainPrefixState, const otIp6Prefix &) const {} +#endif + + BackboneRouterConfig mConfig; ///< Primary Backbone Router information. + otIp6Prefix mDomainPrefix; ///< Domain Prefix on the Thread Network. }; } // namespace BackboneRouter diff --git a/src/core/backbone_router/local.cpp b/src/core/backbone_router/local.cpp index 2897c3edb..70e0eff03 100644 --- a/src/core/backbone_router/local.cpp +++ b/src/core/backbone_router/local.cpp @@ -40,7 +40,6 @@ #include "common/locator-getters.hpp" #include "common/logging.hpp" #include "common/random.hpp" -#include "thread/mle.hpp" #include "thread/mle_types.hpp" #include "thread/thread_netif.hpp" diff --git a/src/core/backbone_router/local.hpp b/src/core/backbone_router/local.hpp index b8029582e..04ddfd5e0 100644 --- a/src/core/backbone_router/local.hpp +++ b/src/core/backbone_router/local.hpp @@ -41,6 +41,7 @@ #include #include "backbone_router/leader.hpp" +#include "common/locator.hpp" #include "net/netif.hpp" #include "thread/network_data.hpp" diff --git a/src/core/net/ip6_address.hpp b/src/core/net/ip6_address.hpp index af4197c30..ef77b54e2 100644 --- a/src/core/net/ip6_address.hpp +++ b/src/core/net/ip6_address.hpp @@ -325,7 +325,7 @@ public: /** * This method sets the prefix content of Mesh Local Prefix-Based Multicast Address. * - * @param[in] aMeshLocalPrefix A reference to the Mesh Local Prefix. + * @param[in] aMeshLocalPrefix A reference to the Mesh Local Prefix. * */ void SetMulticastNetworkPrefix(const Mle::MeshLocalPrefix &aMeshLocalPrefix) @@ -333,6 +333,17 @@ public: SetMulticastNetworkPrefix(aMeshLocalPrefix.m8, Mle::MeshLocalPrefix::kLength); } + /** + * This method sets the prefix content of Prefix-Based Multicast Address. + * + * @param[in] aPrefix A reference to an IPv6 Prefix. + * + */ + void SetMulticastNetworkPrefix(const otIp6Prefix &aPrefix) + { + SetMulticastNetworkPrefix(aPrefix.mPrefix.mFields.m8, aPrefix.mLength); + } + /** * This method returns a pointer to the Interface Identifier. * diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index 330af0f3d..f3b364c19 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -55,10 +55,6 @@ #include "thread/thread_netif.hpp" #include "thread/time_sync_service.hpp" -#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE -#include "backbone_router/local.hpp" -#endif - using ot::Encoding::BigEndian::HostSwap16; namespace ot { @@ -181,6 +177,13 @@ Mle::Mle(Instance &aInstance) mAllNetworkBackboneRouters.GetAddress().mFields.m8[2] = 0; // Reserved mAllNetworkBackboneRouters.GetAddress().mFields.m8[15] = 3; // Group ID = 3 + // All Domain Backbone Routers Multicast Address. + mAllDomainBackboneRouters.Clear(); + + mAllDomainBackboneRouters.GetAddress().mFields.m8[0] = 0xff; // Multicast + mAllDomainBackboneRouters.GetAddress().mFields.m8[1] = 0x32; // Flags = 3, Scope = 2 + mAllDomainBackboneRouters.GetAddress().mFields.m8[2] = 0; // Reserved + mAllDomainBackboneRouters.GetAddress().mFields.m8[15] = 3; // Group ID = 3 #endif // initialize Mesh Local Prefix @@ -1025,7 +1028,7 @@ void Mle::ApplyMeshLocalPrefix(void) if (Get().IsEnabled()) { - // Subscribe All Network Backbone Routers Multicast Address for both Seconday and Primary state. + // Subscribe All Network Backbone Routers Multicast Address for both Secondary and Primary state. Get().SubscribeMulticast(mAllNetworkBackboneRouters); } @@ -1653,7 +1656,7 @@ void Mle::HandleStateChanged(otChangedFlags aFlags) if (Get().IsEnabled()) { - // Subscribe All Network Backbone Routers Multicast Address for both Seconday and Primary state. + // Subscribe All Network Backbone Routers Multicast Address for both Secondary and Primary state. Get().SubscribeMulticast(mAllNetworkBackboneRouters); } else @@ -4437,5 +4440,33 @@ void Mle::DelayedResponseMetadata::RemoveFrom(Message &aMessage) const OT_UNUSED_VARIABLE(error); } +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +void Mle::UpdateAllDomainBackboneRouters(BackboneRouter::Leader::DomainPrefixState aState) +{ + if (!Get().IsEnabled()) + { + Get().UnsubscribeMulticast(mAllDomainBackboneRouters); + ExitNow(); + } + + if (aState == BackboneRouter::Leader::kDomainPrefixRemoved || + aState == BackboneRouter::Leader::kDomainPrefixRefreshed) + { + Get().UnsubscribeMulticast(mAllDomainBackboneRouters); + } + + if (aState == BackboneRouter::Leader::kDomainPrefixAdded || + aState == BackboneRouter::Leader::kDomainPrefixRefreshed) + { + mAllDomainBackboneRouters.GetAddress().SetMulticastNetworkPrefix( + *Get().GetDomainPrefix()); + Get().SubscribeMulticast(mAllDomainBackboneRouters); + } + +exit: + return; +} +#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE + } // namespace Mle } // namespace ot diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index cb82a2507..5754cd024 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -45,6 +45,9 @@ #include "thread/mle_tlvs.hpp" #include "thread/mle_types.hpp" #include "thread/topology.hpp" +#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE +#include "backbone_router/leader.hpp" +#endif namespace ot { @@ -666,7 +669,27 @@ public: { return mAllNetworkBackboneRouters.GetAddress(); } -#endif + + /** + * This method returns a reference to the All Domain Backbone Routers Multicast Address. + * + * @returns A reference to the All Domain Backbone Routers Multicast Address. + * + */ + const Ip6::Address &GetAllDomainBackboneRoutersAddress(void) const + { + return mAllDomainBackboneRouters.GetAddress(); + } + + /** + * This method updates the subscription of All Domain Backbone Routers Multicast Address. + * + * @param[in] aState The Domain Prefix state or state change. + * + */ + void UpdateAllDomainBackboneRouters(BackboneRouter::Leader::DomainPrefixState aState); + +#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE /** * This method gets the parent when operating in End Device mode. @@ -1850,6 +1873,7 @@ private: #if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE Ip6::NetifUnicastAddress mBackboneRouterPrimaryAloc; Ip6::NetifMulticastAddress mAllNetworkBackboneRouters; + Ip6::NetifMulticastAddress mAllDomainBackboneRouters; #endif otMleCounters mCounters; diff --git a/tests/scripts/thread-cert/config.py b/tests/scripts/thread-cert/config.py index f491dc75c..45f929d00 100644 --- a/tests/scripts/thread-cert/config.py +++ b/tests/scripts/thread-cert/config.py @@ -57,6 +57,8 @@ LINK_LOCAL_ALL_NODES_ADDRESS = 'ff02::1' LINK_LOCAL_ALL_ROUTERS_ADDRESS = 'ff02::2' DOMAIN_PREFIX = 'fd00:7d03:7d03:7d03::/64' +ALL_DOMAIN_BBRS_ADDRESS = 'ff32:40:fd00:7d03:7d03:7d03:0:3' +ALL_NETWORK_BBRS_ADDRESS = 'ff32:40:fdde:ad00:beef:0:0:3' DEFAULT_MASTER_KEY = bytearray([ 0x00, diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 0f762d200..7cb1249d2 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -734,6 +734,20 @@ class Node: return None + def get_ipmaddrs(self): + self.send_command('ipmaddr') + return self._expect_results(r'\S+(:\S*)+') + + def has_ipmaddr(self, address): + ipmaddr = ipaddress.ip_address(address) + ipmaddrs = self.get_ipmaddrs() + for addr in ipmaddrs: + if isinstance(addr, bytearray): + addr = bytes(addr) + if ipaddress.ip_address(addr) == ipmaddr: + return True + return False + def get_addr_leader_aloc(self): addrs = self.get_addrs() for addr in addrs: diff --git a/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py b/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py index fbb5c97db..dabcfc84b 100755 --- a/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py +++ b/tests/scripts/thread-cert/v1_2_test_backbone_router_service.py @@ -96,7 +96,6 @@ class TestBackboneRouterService(thread_cert.TestCase): # 1) First Backbone Router would become the Primary. self.nodes[BBR_1].set_router_selection_jitter(ROUTER_SELECTION_JITTER) self.nodes[BBR_1].set_bbr_registration_jitter(BBR_REGISTRATION_JITTER) - self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) self.nodes[BBR_1].set_backbone_router(seqno=1) self.nodes[BBR_1].start() WAIT_TIME = WAIT_ATTACH + ROUTER_SELECTION_JITTER @@ -107,6 +106,13 @@ class TestBackboneRouterService(thread_cert.TestCase): self.simulator.go(WAIT_TIME) self.assertEqual(self.nodes[BBR_1].get_backbone_router_state(), 'Primary') + assert self.nodes[BBR_1].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS) + assert not self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) + + self.nodes[BBR_1].set_domain_prefix(config.DOMAIN_PREFIX) + WAIT_TIME = WAIT_REDUNDANCE + self.simulator.go(WAIT_TIME) + assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) # 2) Reset BBR_1 and bring it back soon. # Verify that it restores Primary State with sequence number @@ -172,6 +178,10 @@ class TestBackboneRouterService(thread_cert.TestCase): self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Disabled') + assert not self.nodes[BBR_2].has_ipmaddr( + config.ALL_NETWORK_BBRS_ADDRESS) + assert not self.nodes[BBR_2].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) + # Enable Backbone function, it will stay at Secondary state as # there is Primary Backbone Router already. # Here removes the Domain Prefix before enabling backbone function @@ -241,6 +251,9 @@ class TestBackboneRouterService(thread_cert.TestCase): self.assertEqual(self.nodes[BBR_2].get_backbone_router_state(), 'Secondary') + assert self.nodes[BBR_1].has_ipmaddr(config.ALL_NETWORK_BBRS_ADDRESS) + assert self.nodes[BBR_1].has_ipmaddr(config.ALL_DOMAIN_BBRS_ADDRESS) + if __name__ == '__main__': unittest.main()