[router-table] introduce Event to track specific table changes (#12715)

This commit introduces a new `Event` enumeration in `RouterTable`
along with an `Events` bit-field to track and indicate specific changes
that occur within the table. The `SignalTableChanged()` method is
updated to accept these events, replacing the previous parameterless
version. A new `LogEvents()` method is also added to log a summary of
the changes whenever the table is updated, improving debugging and
visibility into the router table's state.
This commit is contained in:
Abtin Keshavarzian
2026-03-23 12:49:12 -05:00
committed by GitHub
parent 6d5bd4157a
commit 13776bc05c
3 changed files with 103 additions and 14 deletions
+4 -1
View File
@@ -331,8 +331,11 @@ void NeighborTable::Signal(Event aEvent, const Neighbor &aNeighbor)
#if OPENTHREAD_FTD
case kRouterAdded:
Get<RouterTable>().SignalTableChanged(RouterTable::kEventNeighborAdded);
break;
case kRouterRemoved:
Get<RouterTable>().SignalTableChanged();
Get<RouterTable>().SignalTableChanged(RouterTable::kEventNeighborRemoved);
break;
#endif
+75 -12
View File
@@ -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<NeighborTable>().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<NeighborTable>().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<Mle::Mle>().IsRouterOrLeader())
{
isSelf = Get<Mle::Mle>().MatchesRouterId(aRouterId);
}
else if (Get<Mle::Mle>().IsDetached())
{
isSelf = Get<Mle::Mle>().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<Mle::Mle>().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<kStringSize> 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;
+24 -1
View File
@@ -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<RouterIdMap>
@@ -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;