From 6c75a53bdce804763ca82ebb09a443ac2144df7b Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Thu, 6 Aug 2020 13:18:06 -0700 Subject: [PATCH] [topology] adding 'Neighbor::AddressMatcher' (#5354) This commit adds new a type `Neighbor::AddressMactehr` which is used to filter and find a neighbor (child/router) with a given MAC address matching a given `Neighbor::StateFilter`. This new type helps simplify related code in `ChildTable`/`RouterTbale`. --- src/core/thread/child_table.cpp | 82 ++++++------------------ src/core/thread/child_table.hpp | 8 ++- src/core/thread/router_table.cpp | 60 ++++++----------- src/core/thread/router_table.hpp | 6 ++ src/core/thread/topology.cpp | 30 +++++++++ src/core/thread/topology.hpp | 106 +++++++++++++++++++++++++++++-- tests/unit/test_child_table.cpp | 8 +++ 7 files changed, 189 insertions(+), 111 deletions(-) diff --git a/src/core/thread/child_table.cpp b/src/core/thread/child_table.cpp index 909f55aa6..187d50c03 100644 --- a/src/core/thread/child_table.cpp +++ b/src/core/thread/child_table.cpp @@ -105,13 +105,23 @@ exit: Child *ChildTable::GetNewChild(void) { - Child *child = mChildren; + Child *child = FindChild(Child::AddressMatcher(Child::kInStateInvalid)); + + VerifyOrExit(child != nullptr, OT_NOOP); + child->Clear(); + +exit: + return child; +} + +const Child *ChildTable::FindChild(const Child::AddressMatcher &aMatcher) const +{ + const Child *child = mChildren; for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++) { - if (child->IsStateInvalid()) + if (child->Matches(aMatcher)) { - child->Clear(); ExitNow(); } } @@ -124,76 +134,22 @@ exit: Child *ChildTable::FindChild(uint16_t aRloc16, Child::StateFilter aFilter) { - Child *child = mChildren; - - for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++) - { - if (child->MatchesFilter(aFilter) && (child->GetRloc16() == aRloc16)) - { - ExitNow(); - } - } - - child = nullptr; - -exit: - return child; + return FindChild(Child::AddressMatcher(aRloc16, aFilter)); } -Child *ChildTable::FindChild(const Mac::ExtAddress &aAddress, Child::StateFilter aFilter) +Child *ChildTable::FindChild(const Mac::ExtAddress &aExtAddress, Child::StateFilter aFilter) { - Child *child = mChildren; - - for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++) - { - if (child->MatchesFilter(aFilter) && (child->GetExtAddress() == aAddress)) - { - ExitNow(); - } - } - - child = nullptr; - -exit: - return child; + return FindChild(Child::AddressMatcher(aExtAddress, aFilter)); } -Child *ChildTable::FindChild(const Mac::Address &aAddress, Child::StateFilter aFilter) +Child *ChildTable::FindChild(const Mac::Address &aMacAddress, Child::StateFilter aFilter) { - Child *child = nullptr; - - switch (aAddress.GetType()) - { - case Mac::Address::kTypeShort: - child = FindChild(aAddress.GetShort(), aFilter); - break; - - case Mac::Address::kTypeExtended: - child = FindChild(aAddress.GetExtended(), aFilter); - break; - - default: - break; - } - - return child; + return FindChild(Child::AddressMatcher(aMacAddress, aFilter)); } bool ChildTable::HasChildren(Child::StateFilter aFilter) const { - bool rval = false; - const Child *child = mChildren; - - for (uint16_t num = mMaxChildrenAllowed; num != 0; num--, child++) - { - if (child->MatchesFilter(aFilter)) - { - ExitNow(rval = true); - } - } - -exit: - return rval; + return (FindChild(Child::AddressMatcher(aFilter)) != nullptr); } uint16_t ChildTable::GetNumChildren(Child::StateFilter aFilter) const diff --git a/src/core/thread/child_table.hpp b/src/core/thread/child_table.hpp index eafcf6833..9963553e2 100644 --- a/src/core/thread/child_table.hpp +++ b/src/core/thread/child_table.hpp @@ -397,7 +397,13 @@ private: Child::StateFilter mFilter; }; - void RefreshStoredChildren(void); + Child *FindChild(const Child::AddressMatcher &aMatcher) + { + return const_cast(const_cast(this)->FindChild(aMatcher)); + } + + const Child *FindChild(const Child::AddressMatcher &aMatcher) const; + void RefreshStoredChildren(void); uint16_t mMaxChildrenAllowed; Child mChildren[kMaxChildren]; diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 4b8a77478..27aaab65b 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -342,19 +342,27 @@ uint8_t RouterTable::GetActiveLinkCount(void) const return activeLinks; } +const Router *RouterTable::FindRouter(const Router::AddressMatcher &aMatcher) const +{ + const Router *router; + + for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) + { + if (router->Matches(aMatcher)) + { + break; + } + } + + return router; +} + Router *RouterTable::GetNeighbor(uint16_t aRloc16) { Router *router = nullptr; VerifyOrExit(aRloc16 != Get().GetRloc16(), OT_NOOP); - - for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) - { - if (router->IsStateValid() && router->GetRloc16() == aRloc16) - { - ExitNow(); - } - } + router = FindRouter(Router::AddressMatcher(aRloc16, Router::kInStateValid)); exit: return router; @@ -362,20 +370,7 @@ exit: Router *RouterTable::GetNeighbor(const Mac::ExtAddress &aExtAddress) { - Router *router = nullptr; - - VerifyOrExit(aExtAddress != Get().GetExtAddress(), OT_NOOP); - - for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) - { - if (router->IsStateValid() && router->GetExtAddress() == aExtAddress) - { - ExitNow(); - } - } - -exit: - return router; + return FindRouter(Router::AddressMatcher(aExtAddress, Router::kInStateValid)); } const Router *RouterTable::GetRouter(uint8_t aRouterId) const @@ -387,14 +382,7 @@ const Router *RouterTable::GetRouter(uint8_t aRouterId) const VerifyOrExit(aRouterId < Mle::kInvalidRouterId, OT_NOOP); rloc16 = Mle::Mle::Rloc16FromRouterId(aRouterId); - - for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) - { - if (router->GetRloc16() == rloc16) - { - break; - } - } + router = FindRouter(Router::AddressMatcher(rloc16, Router::kInStateAny)); exit: return router; @@ -402,17 +390,7 @@ exit: Router *RouterTable::GetRouter(const Mac::ExtAddress &aExtAddress) { - Router *router = nullptr; - - for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router)) - { - if (router->GetExtAddress() == aExtAddress) - { - break; - } - } - - return router; + return FindRouter(Router::AddressMatcher(aExtAddress, Router::kInStateAny)); } otError RouterTable::GetRouterInfo(uint16_t aRouterId, Router::Info &aRouterInfo) diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index 88be5a2f0..2fb06a6d3 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -423,6 +423,12 @@ private: return const_cast(const_cast(this)->GetNextEntry(aRouter)); } + const Router *FindRouter(const Router::AddressMatcher &aMatcher) const; + Router * FindRouter(const Router::AddressMatcher &aMatcher) + { + return const_cast(const_cast(this)->FindRouter(aMatcher)); + } + Router mRouters[Mle::kMaxRouters]; Mle::RouterIdSet mAllocatedRouterIds; uint8_t mRouterIdReuseDelay[Mle::kMaxRouterId + 1]; diff --git a/src/core/thread/topology.cpp b/src/core/thread/topology.cpp index f372896e2..25652145e 100644 --- a/src/core/thread/topology.cpp +++ b/src/core/thread/topology.cpp @@ -41,6 +41,28 @@ namespace ot { +bool Neighbor::AddressMatcher::Matches(const Neighbor &aNeighbor) const +{ + bool matches = false; + + VerifyOrExit(aNeighbor.MatchesFilter(mStateFilter), OT_NOOP); + + if (mShortAddress != Mac::kShortAddrInvalid) + { + VerifyOrExit(mShortAddress == aNeighbor.GetRloc16(), OT_NOOP); + } + + if (mExtAddress != nullptr) + { + VerifyOrExit(*mExtAddress == aNeighbor.GetExtAddress(), OT_NOOP); + } + + matches = true; + +exit: + return matches; +} + void Neighbor::Info::SetFrom(const Neighbor &aNeighbor) { Clear(); @@ -112,6 +134,10 @@ bool Neighbor::MatchesFilter(StateFilter aFilter) const matches = IsStateValidOrAttaching(); break; + case kInStateInvalid: + matches = IsStateInvalid(); + break; + case kInStateAnyExceptInvalid: matches = !IsStateInvalid(); break; @@ -119,6 +145,10 @@ bool Neighbor::MatchesFilter(StateFilter aFilter) const case kInStateAnyExceptValidOrRestoring: matches = !IsStateValidOrRestoring(); break; + + case kInStateAny: + matches = true; + break; } return matches; diff --git a/src/core/thread/topology.hpp b/src/core/thread/topology.hpp index 1dc7e5f88..218334c7c 100644 --- a/src/core/thread/topology.hpp +++ b/src/core/thread/topology.hpp @@ -83,12 +83,96 @@ public: */ enum StateFilter { - kInStateValid, ///< Accept child only in `kStateValid`. - kInStateValidOrRestoring, ///< Accept child with `IsStateValidOrRestoring()` being `true`. - kInStateChildIdRequest, ///< Accept child only in `Child:kStateChildIdRequest`. - kInStateValidOrAttaching, ///< Accept child with `IsStateValidOrAttaching()` being `true`. - kInStateAnyExceptInvalid, ///< Accept child in any state except `kStateInvalid`. - kInStateAnyExceptValidOrRestoring, ///< Accept child in any state except `IsStateValidOrRestoring()`. + kInStateValid, ///< Accept neighbor only in `kStateValid`. + kInStateValidOrRestoring, ///< Accept neighbor with `IsStateValidOrRestoring()` being `true`. + kInStateChildIdRequest, ///< Accept neighbor only in `Child:kStateChildIdRequest`. + kInStateValidOrAttaching, ///< Accept neighbor with `IsStateValidOrAttaching()` being `true`. + kInStateInvalid, ///< Accept neighbor only in `kStateInvalid`. + kInStateAnyExceptInvalid, ///< Accept neighbor in any state except `kStateInvalid`. + kInStateAnyExceptValidOrRestoring, ///< Accept neighbor in any state except `IsStateValidOrRestoring()`. + kInStateAny, ///< Accept neighbor in any state. + }; + + /** + * This class represents an Address Matcher used to find a neighbor (child/router) with a given MAC address also + * matching a given state filter. + * + */ + class AddressMatcher + { + public: + /** + * This constructor initializes the `AddressMatcher` with a given MAC short address (RCOC16) and state filter. + * + * @param[in] aShortAddress A MAC short address (RLOC16). + * @param[in] aStateFilter A state filter. + * + */ + AddressMatcher(Mac::ShortAddress aShortAddress, StateFilter aStateFilter) + : AddressMatcher(aStateFilter, aShortAddress, nullptr) + { + } + + /** + * This constructor initializes the `AddressMatcher` with a given MAC extended address and state filter. + * + * @param[in] aExtAddress A MAC extended address. + * @param[in] aStateFilter A state filter. + * + */ + AddressMatcher(const Mac::ExtAddress &aExtAddress, StateFilter aStateFilter) + : AddressMatcher(aStateFilter, Mac::kShortAddrInvalid, &aExtAddress) + { + } + + /** + * This constructor initializes the `AddressMatcher` with a given MAC address and state filter. + * + * @param[in] aMacAddress A MAC address. + * @param[in] aStateFilter A state filter. + * + */ + AddressMatcher(const Mac::Address &aMacAddress, StateFilter aStateFilter) + : AddressMatcher(aStateFilter, + aMacAddress.IsShort() ? aMacAddress.GetShort() + : static_cast(Mac::kShortAddrInvalid), + aMacAddress.IsExtended() ? &aMacAddress.GetExtended() : nullptr) + { + } + + /** + * This constructor initializes the `AddressMatcher` with a given state filter (it accepts any address). + * + * @param[in] aStateFilter A state filter. + * + */ + explicit AddressMatcher(StateFilter aStateFilter) + : AddressMatcher(aStateFilter, Mac::kShortAddrInvalid, nullptr) + { + } + + /** + * This method indicates if a given neighbor matches the address and state filter of `AddressMatcher`. + * + * @param[in] aNeighbor A neighbor. + * + * @retval TRUE Neighbor @p aNeighbor matches the address and state filter. + * @retval FALSE Neighbor @p aNeighbor does not match the address or state filter. + * + */ + bool Matches(const Neighbor &aNeighbor) const; + + private: + AddressMatcher(StateFilter aStateFilter, Mac::ShortAddress aShortAddress, const Mac::ExtAddress *aExtAddress) + : mStateFilter(aStateFilter) + , mShortAddress(aShortAddress) + , mExtAddress(aExtAddress) + { + } + + StateFilter mStateFilter; + Mac::ShortAddress mShortAddress; + const Mac::ExtAddress *mExtAddress; }; /** @@ -210,6 +294,16 @@ public: */ bool MatchesFilter(StateFilter aFilter) const; + /** + * This method indicates whether neighbor matches a given `AddressMatcher`. + * + * @param[in] aMatcher An `AddressMatcher` to match against. + * + * @returns TRUE if the neighbor matches the address and state filter of @p aMatcher, FALSE otherwise. + * + */ + bool Matches(const AddressMatcher &aMatcher) const { return aMatcher.Matches(*this); } + /** * This method gets the device mode flags. * diff --git a/tests/unit/test_child_table.cpp b/tests/unit/test_child_table.cpp index 4cd463d4e..fd66c65ab 100644 --- a/tests/unit/test_child_table.cpp +++ b/tests/unit/test_child_table.cpp @@ -96,9 +96,17 @@ static bool StateMatchesFilter(Child::State aState, Child::StateFilter aFilter) rval = child.IsStateValidOrAttaching(); break; + case Child::kInStateInvalid: + rval = child.IsStateInvalid(); + break; + case Child::kInStateAnyExceptValidOrRestoring: rval = !child.IsStateValidOrRestoring(); break; + + case Child::kInStateAny: + rval = true; + break; } return rval;