diff --git a/src/core/thread/neighbor_table.cpp b/src/core/thread/neighbor_table.cpp index da17296af..490ca8ed0 100644 --- a/src/core/thread/neighbor_table.cpp +++ b/src/core/thread/neighbor_table.cpp @@ -331,8 +331,11 @@ void NeighborTable::Signal(Event aEvent, const Neighbor &aNeighbor) #if OPENTHREAD_FTD case kRouterAdded: + Get().SignalTableChanged(RouterTable::kEventNeighborAdded); + break; + case kRouterRemoved: - Get().SignalTableChanged(); + Get().SignalTableChanged(RouterTable::kEventNeighborRemoved); break; #endif diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 00b9efbd9..d7085255e 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -42,6 +42,7 @@ RouterTable::RouterTable(Instance &aInstance) , mChangedTask(aInstance) , mRouterIdSequenceLastUpdated(0) , mRouterIdSequence(Random::NonCrypto::GetUint8()) + , mEvents(0) #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE , mMinRouterId(0) , mMaxRouterId(Mle::kMaxRouterId) @@ -52,10 +53,12 @@ RouterTable::RouterTable(Instance &aInstance) void RouterTable::Clear(void) { + Events events = !mRouters.IsEmpty() ? kEventRouterRemoved : 0; + ClearNeighbors(); mRouterIdMap.Clear(); mRouters.Clear(); - SignalTableChanged(); + SignalTableChanged(events); } bool RouterTable::IsRouteTlvIdSequenceMoreRecent(const Mle::RouteTlv &aRouteTlv) const @@ -71,7 +74,7 @@ void RouterTable::ClearNeighbors(void) if (router.IsStateValid()) { Get().Signal(NeighborTable::kRouterRemoved, router); - SignalTableChanged(); + SignalTableChanged(kEventNeighborRemoved); } router.SetState(Neighbor::kStateInvalid); @@ -92,7 +95,8 @@ Router *RouterTable::AddRouter(uint8_t aRouterId) router->SetNextHopToInvalid(); mRouterIdMap.SetIndex(aRouterId, mRouters.IndexOf(*router)); - SignalTableChanged(); + + SignalTableChanged(IsSelfRouterId(aRouterId) ? kEventSelfRouterAdded : kEventRouterAdded); exit: return router; @@ -103,6 +107,8 @@ void RouterTable::RemoveRouter(Router &aRouter) // Remove an existing `aRouter` entry from `mRouters` and update the // `mRouterIdMap`. + bool isSelf = IsSelfRouterId(aRouter.GetRouterId()); + if (aRouter.IsStateValid()) { Get().Signal(NeighborTable::kRouterRemoved, aRouter); @@ -120,7 +126,23 @@ void RouterTable::RemoveRouter(Router &aRouter) mRouterIdMap.SetIndex(aRouter.GetRouterId(), mRouters.IndexOf((aRouter))); } - SignalTableChanged(); + SignalTableChanged(isSelf ? kEventSelfRouterRemoved : kEventRouterRemoved); +} + +bool RouterTable::IsSelfRouterId(uint8_t aRouterId) const +{ + bool isSelf = false; + + if (Get().IsRouterOrLeader()) + { + isSelf = Get().MatchesRouterId(aRouterId); + } + else if (Get().IsDetached()) + { + isSelf = Get().GetLeaderId() == aRouterId; + } + + return isSelf; } Router *RouterTable::Allocate(void) @@ -225,7 +247,7 @@ void RouterTable::RemoveRouterLink(Router &aRouter) { aRouter.SetLinkQualityOut(kLinkQuality0); aRouter.SetLastHeard(TimerMilli::GetNow()); - SignalTableChanged(); + SignalTableChanged(kEventLinkQualityOutChanged); } for (Router &router : mRouters) @@ -233,7 +255,7 @@ void RouterTable::RemoveRouterLink(Router &aRouter) if (router.GetNextHop() == aRouter.GetRouterId()) { router.SetNextHopToInvalid(); - SignalTableChanged(); + SignalTableChanged(kEventNextHopOrCostChanged); if (GetLinkCost(router) >= Mle::kMaxRouteCost) { @@ -594,7 +616,7 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor if (neighbor->GetLinkQualityOut() != linkQuality) { neighbor->SetLinkQualityOut(linkQuality); - SignalTableChanged(); + SignalTableChanged(kEventLinkQualityOutChanged); } // If the `aRouteTlv` indicates that the neighboring @@ -654,14 +676,14 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor { if (router->SetNextHopAndCost(aNeighborId, cost)) { - SignalTableChanged(); + SignalTableChanged(kEventNextHopOrCostChanged); } } else if (nextHop == neighbor) { router->SetNextHopToInvalid(); router->SetLastHeard(TimerMilli::GetNow()); - SignalTableChanged(); + SignalTableChanged(kEventNextHopOrCostChanged); } } else @@ -672,7 +694,7 @@ void RouterTable::UpdateRoutes(const Mle::RouteTlv &aRouteTlv, uint8_t aNeighbor if (newCost < curCost) { router->SetNextHopAndCost(aNeighborId, cost); - SignalTableChanged(); + SignalTableChanged(kEventNextHopOrCostChanged); } } } @@ -719,7 +741,7 @@ void RouterTable::UpdateRouterOnFtdChild(const Mle::RouteTlv &aRouteTlv, uint8_t if (router->SetNextHopAndCost(nextHopId, cost)) { - SignalTableChanged(); + SignalTableChanged(kEventNextHopOrCostChanged); } } } @@ -878,11 +900,16 @@ void RouterTable::RouterIdMap::HandleTimeTick(void) } } -void RouterTable::SignalTableChanged(void) { mChangedTask.Post(); } +void RouterTable::SignalTableChanged(Events aEvents) +{ + mEvents |= aEvents; + mChangedTask.Post(); +} void RouterTable::HandleTableChanged(void) { #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) + LogEvents(); LogRouteTable(); #endif @@ -891,9 +918,45 @@ void RouterTable::HandleTableChanged(void) #endif Get().UpdateAdvertiseInterval(); + + mEvents = 0; } #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) + +void RouterTable::LogEvents(void) const +{ + static constexpr uint16_t kStringSize = 128; + + static const char *const kEventStrings[] = { + "router+", // kEventRouterAdded (1 << 0) + "router-", // kEventRouterRemoved (1 << 1) + "self+", // kEventSelfRouterAdded (1 << 2) + "self-", // kEventSelfRouterRemoved (1 << 3) + "nexthop|cost", // kEventNextHopOrCostChanged (1 << 4) + "lqo", // kEventLinkQualityOutChanged (1 << 5) + "nbr+", // kEventNeighborAdded (1 << 6) + "nbr-", // kEventNeighborRemoved (1 << 7) + }; + + String string; + + VerifyOrExit(mEvents != 0); + + for (uint8_t bit = 0; bit < GetArrayLength(kEventStrings); bit++) + { + if (GetBit(mEvents, bit)) + { + string.Append(" %s", kEventStrings[bit]); + } + } + + LogInfo("Route table changed [%s ]", string.AsCString()); + +exit: + return; +} + void RouterTable::LogRouteTable(void) const { static constexpr uint16_t kStringSize = 128; diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index c22806664..22764326f 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -54,6 +54,26 @@ class RouterTable : public InstanceLocator, private NonCopyable friend class NeighborTable; public: + /** + * Represents the events emitted by `RouterTable` to signal changes. + */ + enum Event : uint16_t + { + kEventRouterAdded = 1 << 0, ///< A router entry is added to the table (router ID is allocated). + kEventRouterRemoved = 1 << 1, ///< A router entry is removed from the table (router ID released). + kEventSelfRouterAdded = 1 << 2, ///< Same as `kEventRouterAdded` but the new entry is this device. + kEventSelfRouterRemoved = 1 << 3, ///< Same as `kEventRouterRemoved` but the removed entry is this device. + kEventNextHopOrCostChanged = 1 << 4, ///< Next hop or cost changed for an existing router entry. + kEventLinkQualityOutChanged = 1 << 5, ///< Link Quality Out changed for an existing router entry. + kEventNeighborAdded = 1 << 6, ///< A router neighbor is added (link established to a router). + kEventNeighborRemoved = 1 << 7, ///< A router neighbor is removed (router is no longer a neighbor). + }; + + /** + * Represents a bit-field of `Event` values. + */ + typedef uint16_t Events; + /** * Constructor. * @@ -422,8 +442,10 @@ private: return AsNonConst(AsConst(this)->FindRouter(aMatcher)); } - void SignalTableChanged(void); + bool IsSelfRouterId(uint8_t aRouterId) const; + void SignalTableChanged(Events aEvents); void HandleTableChanged(void); + void LogEvents(void) const; void LogRouteTable(void) const; class RouterIdMap : public Clearable @@ -464,6 +486,7 @@ private: RouterIdMap mRouterIdMap; TimeMilli mRouterIdSequenceLastUpdated; uint8_t mRouterIdSequence; + Events mEvents; #if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE uint8_t mMinRouterId; uint8_t mMaxRouterId;