[router-table] simplify tracking of routers and allocated IDs (#8483)

This commit simplifies how `RouterTable` tracks the allocated Router
IDs and the `Router` entries. A new class `RouterIdMap` is added
which tracks the currently allocated Router IDs. For allocated IDs,
it also tracks the index of the `Router` entry in `mRouters` array.
For unallocated IDs, it tracks the remaining reuse delay time in
seconds (using the same underlying `uint8_t` per Router ID). This new
class makes it easier to find a `Router` by its ID. With this change,
we no longer need to keep the `mRouters` array sorted based on Router
ID (this was used when populating `RouteTlv`).

This commit also changes the `mRouters` to use `Array<Router>` which
will then tracks its length and also simplify range-based `for`
iteration over `RouterTable` entries.
This commit is contained in:
Abtin Keshavarzian
2022-12-13 23:07:45 -08:00
committed by GitHub
parent 2db38b0335
commit 144d480ca9
7 changed files with 252 additions and 283 deletions
+36
View File
@@ -39,6 +39,7 @@
#include "common/code_utils.hpp"
#include "common/const_cast.hpp"
#include "common/error.hpp"
#include "common/locator.hpp"
#include "common/numeric_limits.hpp"
#include "common/type_traits.hpp"
@@ -146,6 +147,24 @@ public:
*/
Array(const Array &aOtherArray) { *this = aOtherArray; }
/**
* This constructor initializes the array as empty and initializes its elements by calling `Init(Instance &)`
* method on every element.
*
* This constructor uses method `Init(Instance &aInstance)` on `Type`.
*
* @param[in] aInstance The OpenThread instance.
*
*/
explicit Array(Instance &aInstance)
: mLength(0)
{
for (Type &element : mElements)
{
element.Init(aInstance);
}
}
/**
* This method clears the array.
*
@@ -558,6 +577,23 @@ public:
return *this;
}
/**
* This method indicates whether a given entry pointer is from the array buffer.
*
* This method does not check the current length of array and only checks that @p aEntry is pointing to an address
* contained within underlying C array buffer.
*
* @param[in] aEntry A pointer to an entry to check.
*
* @retval TRUE The @p aEntry is from the array.
* @retval FALSE The @p aEntry is not from the array.
*
*/
bool IsInArrayBuffer(const Type *aEntry) const
{
return (&mElements[0] <= aEntry) && (aEntry < GetArrayEnd(mElements));
}
// The following methods are intended to support range-based `for`
// loop iteration over the array elements and should not be used
// directly.
+1 -1
View File
@@ -265,7 +265,7 @@ void Link::HandleTimer(void)
HandleTimer(child);
}
for (Router &router : Get<RouterTable>().Iterate())
for (Router &router : Get<RouterTable>())
{
HandleTimer(router);
}
+1 -1
View File
@@ -238,7 +238,7 @@ void KeyManager::ResetFrameCounters(void)
#if OPENTHREAD_FTD
// reset router frame counters
for (Router &router : Get<RouterTable>().Iterate())
for (Router &router : Get<RouterTable>())
{
router.SetKeySequence(0);
router.GetLinkFrameCounters().Reset();
+6 -6
View File
@@ -1755,7 +1755,7 @@ bool MleRouter::HasNeighborWithGoodLinkQuality(void) const
ExitNow();
}
for (Router &router : Get<RouterTable>().Iterate())
for (const Router &router : Get<RouterTable>())
{
if (!router.IsStateValid())
{
@@ -1935,7 +1935,7 @@ void MleRouter::HandleTimeTick(void)
}
// update router state
for (Router &router : Get<RouterTable>().Iterate())
for (Router &router : Get<RouterTable>())
{
uint32_t age;
@@ -3978,7 +3978,7 @@ void MleRouter::SendAddressSolicitResponse(const Coap::Message &aRequest,
routerMaskTlv.Init();
routerMaskTlv.SetIdSequence(mRouterTable.GetRouterIdSequence());
routerMaskTlv.SetAssignedRouterIdMask(mRouterTable.GetRouterIdSet());
mRouterTable.GetRouterIdSet(routerMaskTlv.GetAssignedRouterIdMask());
SuccessOrExit(routerMaskTlv.AppendTo(*message));
}
@@ -4107,7 +4107,7 @@ void MleRouter::FillConnectivityTlv(ConnectivityTlv &aTlv)
aTlv.SetActiveRouters(mRouterTable.GetActiveRouterCount());
for (Router &router : Get<RouterTable>().Iterate())
for (const Router &router : Get<RouterTable>())
{
if (router.GetRloc16() == GetRloc16())
{
@@ -4150,7 +4150,7 @@ bool MleRouter::HasMinDowngradeNeighborRouters(void)
{
uint8_t routerCount = 0;
for (Router &router : Get<RouterTable>().Iterate())
for (const Router &router : Get<RouterTable>())
{
if (!router.IsStateValid())
{
@@ -4172,7 +4172,7 @@ bool MleRouter::HasOneNeighborWithComparableConnectivity(const RouteTlv &aRouteT
bool rval = true;
// process local neighbor routers
for (Router &router : Get<RouterTable>().Iterate())
for (const Router &router : Get<RouterTable>())
{
LinkQuality localLinkQuality;
LinkQuality peerLinkQuality;
+147 -199
View File
@@ -44,58 +44,24 @@ namespace ot {
RegisterLogModule("RouterTable");
RouterTable::Iterator::Iterator(Instance &aInstance)
: InstanceLocator(aInstance)
, ItemPtrIterator(Get<RouterTable>().GetFirstEntry())
{
}
void RouterTable::Iterator::Advance(void) { mItem = Get<RouterTable>().GetNextEntry(mItem); }
RouterTable::RouterTable(Instance &aInstance)
: InstanceLocator(aInstance)
, mRouters(aInstance)
, mRouterIdSequenceLastUpdated(0)
, mRouterIdSequence(Random::NonCrypto::GetUint8())
, mActiveRouterCount(0)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
, mMinRouterId(0)
, mMaxRouterId(Mle::kMaxRouterId)
#endif
{
for (Router &router : mRouters)
{
router.Init(aInstance);
}
Clear();
}
const Router *RouterTable::GetFirstEntry(void) const
{
const Router *router = &mRouters[0];
VerifyOrExit(router->GetRloc16() != 0xffff, router = nullptr);
exit:
return router;
}
const Router *RouterTable::GetNextEntry(const Router *aRouter) const
{
VerifyOrExit(aRouter != nullptr);
aRouter++;
VerifyOrExit(aRouter < &mRouters[Mle::kMaxRouters], aRouter = nullptr);
VerifyOrExit(aRouter->GetRloc16() != 0xffff, aRouter = nullptr);
exit:
return aRouter;
}
void RouterTable::Clear(void)
{
ClearNeighbors();
mAllocatedRouterIds.Clear();
memset(mRouterIdReuseDelay, 0, sizeof(mRouterIdReuseDelay));
UpdateAllocation();
mRouterIdMap.Clear();
mRouters.Clear();
}
void RouterTable::ClearNeighbors(void)
@@ -111,89 +77,40 @@ void RouterTable::ClearNeighbors(void)
}
}
bool RouterTable::IsAllocated(uint8_t aRouterId) const { return mAllocatedRouterIds.Contains(aRouterId); }
void RouterTable::UpdateAllocation(void)
Router *RouterTable::AddRouter(uint8_t aRouterId)
{
uint8_t indexMap[Mle::kMaxRouterId + 1];
// Add a new `Router` entry to `mRouters` array with given
// `aRouterId` and update the `mRouterIdMap`.
mActiveRouterCount = 0;
Router *router = mRouters.PushBack();
// build index map
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
VerifyOrExit(router != nullptr);
router->Clear();
router->SetRloc16(Mle::Rloc16FromRouterId(aRouterId));
router->SetNextHop(Mle::kInvalidRouterId);
mRouterIdMap.SetIndex(aRouterId, mRouters.IndexOf(*router));
exit:
return router;
}
void RouterTable::RemoveRouter(Router &aRouter)
{
// Remove an existing `aRouter` entry from `mRouters` and update the
// `mRouterIdMap`.
mRouterIdMap.Release(aRouter.GetRouterId());
mRouters.Remove(aRouter);
// Removing `aRouter` from `mRouters` array will replace it with
// the last entry in the array (if not already the last entry) so
// we update the index in `mRouteIdMap` for the moved entry.
if (IsAllocated(aRouter.GetRouterId()))
{
if (IsAllocated(routerId) && mActiveRouterCount < Mle::kMaxRouters)
{
indexMap[routerId] = mActiveRouterCount++;
}
else
{
indexMap[routerId] = Mle::kInvalidRouterId;
}
}
// shift entries forward
for (int index = Mle::kMaxRouters - 2; index >= 0; index--)
{
uint8_t routerId = mRouters[index].GetRouterId();
uint8_t newIndex;
if (routerId > Mle::kMaxRouterId || indexMap[routerId] == Mle::kInvalidRouterId)
{
continue;
}
newIndex = indexMap[routerId];
if (newIndex > index)
{
mRouters[newIndex] = mRouters[index];
}
}
// shift entries backward
for (uint8_t index = 1; index < Mle::kMaxRouters; index++)
{
uint8_t routerId = mRouters[index].GetRouterId();
uint8_t newIndex;
if (routerId > Mle::kMaxRouterId || indexMap[routerId] == Mle::kInvalidRouterId)
{
continue;
}
newIndex = indexMap[routerId];
if (newIndex < index)
{
mRouters[newIndex] = mRouters[index];
}
}
// fix replaced entries
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
{
uint8_t index = indexMap[routerId];
if (index != Mle::kInvalidRouterId)
{
Router &router = mRouters[index];
if (router.GetRouterId() != routerId)
{
router.Clear();
router.SetRloc16(Mle::Rloc16FromRouterId(routerId));
router.SetNextHop(Mle::kInvalidRouterId);
}
}
}
// clear unused entries
for (uint8_t index = mActiveRouterCount; index < Mle::kMaxRouters; index++)
{
Router &router = mRouters[index];
router.Clear();
router.SetRloc16(0xffff);
mRouterIdMap.SetIndex(aRouter.GetRouterId(), mRouters.IndexOf((aRouter)));
}
}
@@ -203,7 +120,7 @@ Router *RouterTable::Allocate(void)
uint8_t numAvailable = 0;
uint8_t selectedRouterId = Mle::kInvalidRouterId;
VerifyOrExit(mActiveRouterCount < Mle::kMaxRouters);
VerifyOrExit(!mRouters.IsFull());
// count available router ids
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
@@ -212,7 +129,7 @@ Router *RouterTable::Allocate(void)
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
#endif
{
if (!IsAllocated(routerId) && mRouterIdReuseDelay[routerId] == 0)
if (mRouterIdMap.CanAllocate(routerId))
{
numAvailable++;
@@ -239,16 +156,14 @@ exit:
Router *RouterTable::Allocate(uint8_t aRouterId)
{
Router *rval = nullptr;
Router *router = nullptr;
VerifyOrExit(aRouterId <= Mle::kMaxRouterId && mActiveRouterCount < Mle::kMaxRouters && !IsAllocated(aRouterId) &&
mRouterIdReuseDelay[aRouterId] == 0);
VerifyOrExit(aRouterId <= Mle::kMaxRouterId && mRouterIdMap.CanAllocate(aRouterId));
mAllocatedRouterIds.Add(aRouterId);
UpdateAllocation();
router = AddRouter(aRouterId);
VerifyOrExit(router != nullptr);
rval = FindRouterById(aRouterId);
rval->SetLastHeard(TimerMilli::GetNow());
router->SetLastHeard(TimerMilli::GetNow());
mRouterIdSequence++;
mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
@@ -257,38 +172,34 @@ Router *RouterTable::Allocate(uint8_t aRouterId)
LogNote("Allocate router id %d", aRouterId);
exit:
return rval;
return router;
}
Error RouterTable::Release(uint8_t aRouterId)
{
Error error = kErrorNone;
uint16_t rloc16 = Mle::Rloc16FromRouterId(aRouterId);
Router *router;
Error error = kErrorNone;
Router *router;
OT_ASSERT(aRouterId <= Mle::kMaxRouterId);
VerifyOrExit(Get<Mle::MleRouter>().IsLeader(), error = kErrorInvalidState);
VerifyOrExit(IsAllocated(aRouterId), error = kErrorNotFound);
router = FindNeighbor(rloc16);
router = FindRouterById(aRouterId);
VerifyOrExit(router != nullptr, error = kErrorNotFound);
if (router != nullptr)
if (router->IsStateValid())
{
Get<NeighborTable>().Signal(NeighborTable::kRouterRemoved, *router);
}
mAllocatedRouterIds.Remove(aRouterId);
UpdateAllocation();
RemoveRouter(*router);
mRouterIdReuseDelay[aRouterId] = Mle::kRouterIdReuseDelay;
for (router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router))
for (Router &otherRouter : mRouters)
{
if (router->GetNextHop() == aRouterId)
if (otherRouter.GetNextHop() == aRouterId)
{
router->SetNextHop(Mle::kInvalidRouterId);
router->SetCost(0);
otherRouter.SetNextHop(Mle::kInvalidRouterId);
otherRouter.SetCost(0);
}
}
@@ -296,7 +207,8 @@ Error RouterTable::Release(uint8_t aRouterId)
mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
Get<AddressResolver>().Remove(aRouterId);
Get<NetworkData::Leader>().RemoveBorderRouter(rloc16, NetworkData::Leader::kMatchModeRouterId);
Get<NetworkData::Leader>().RemoveBorderRouter(Mle::Rloc16FromRouterId(aRouterId),
NetworkData::Leader::kMatchModeRouterId);
Get<Mle::MleRouter>().ResetAdvertiseInterval();
LogNote("Release router id %d", aRouterId);
@@ -313,14 +225,14 @@ void RouterTable::RemoveRouterLink(Router &aRouter)
aRouter.SetLastHeard(TimerMilli::GetNow());
}
for (Router *cur = GetFirstEntry(); cur != nullptr; cur = GetNextEntry(cur))
for (Router &router : mRouters)
{
if (cur->GetNextHop() == aRouter.GetRouterId())
if (router.GetNextHop() == aRouter.GetRouterId())
{
cur->SetNextHop(Mle::kInvalidRouterId);
cur->SetCost(0);
router.SetNextHop(Mle::kInvalidRouterId);
router.SetCost(0);
if (GetLinkCost(*cur) >= Mle::kMaxRouteCost)
if (GetLinkCost(router) >= Mle::kMaxRouteCost)
{
Get<Mle::MleRouter>().ResetAdvertiseInterval();
}
@@ -338,17 +250,7 @@ void RouterTable::RemoveRouterLink(Router &aRouter)
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;
return mRouters.FindMatching(aMatcher);
}
Router *RouterTable::FindNeighbor(uint16_t aRloc16)
@@ -375,13 +277,11 @@ Router *RouterTable::FindNeighbor(const Mac::Address &aMacAddress)
const Router *RouterTable::FindRouterById(uint8_t aRouterId) const
{
const Router *router = nullptr;
uint16_t rloc16;
// Skip if invalid router id is passed.
VerifyOrExit(aRouterId < Mle::kInvalidRouterId);
VerifyOrExit(aRouterId <= Mle::kMaxRouterId);
rloc16 = Mle::Rloc16FromRouterId(aRouterId);
router = FindRouter(Router::AddressMatcher(rloc16, Router::kInStateAny));
VerifyOrExit(IsAllocated(aRouterId));
router = &mRouters[mRouterIdMap.GetIndex(aRouterId)];
exit:
return router;
@@ -429,16 +329,16 @@ Router *RouterTable::GetLeader(void) { return FindRouterById(Get<Mle::MleRouter>
uint32_t RouterTable::GetLeaderAge(void) const
{
return (mActiveRouterCount > 0) ? Time::MsecToSec(TimerMilli::GetNow() - mRouterIdSequenceLastUpdated) : 0xffffffff;
return (!mRouters.IsEmpty()) ? Time::MsecToSec(TimerMilli::GetNow() - mRouterIdSequenceLastUpdated) : 0xffffffff;
}
uint8_t RouterTable::GetNeighborCount(void) const
{
uint8_t count = 0;
for (const Router *router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router))
for (const Router &router : mRouters)
{
if (router->IsStateValid())
if (router.IsStateValid())
{
count++;
}
@@ -461,28 +361,48 @@ exit:
void RouterTable::UpdateRouterIdSet(uint8_t aRouterIdSequence, const Mle::RouterIdSet &aRouterIdSet)
{
bool shouldAdd = false;
mRouterIdSequence = aRouterIdSequence;
mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
VerifyOrExit(mAllocatedRouterIds != aRouterIdSet);
// Remove all previously allocated routers that are now removed in
// new `aRouterIdSet`.
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
{
// If was allocated but removed in new Router Id Set
if (IsAllocated(routerId) && !aRouterIdSet.Contains(routerId))
if (IsAllocated(routerId) == aRouterIdSet.Contains(routerId))
{
continue;
}
if (IsAllocated(routerId))
{
Router *router = FindRouterById(routerId);
OT_ASSERT(router != nullptr);
router->SetNextHop(Mle::kInvalidRouterId);
RemoveRouterLink(*router);
RemoveRouter(*router);
}
else
{
shouldAdd = true;
}
}
mAllocatedRouterIds.Remove(routerId);
VerifyOrExit(shouldAdd);
// Now add all new routers in `aRouterIdSet`.
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
{
if (!IsAllocated(routerId) && aRouterIdSet.Contains(routerId))
{
AddRouter(routerId);
}
}
mAllocatedRouterIds = aRouterIdSet;
UpdateAllocation();
Get<Mle::MleRouter>().ResetAdvertiseInterval();
exit:
@@ -492,15 +412,17 @@ exit:
void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighbor) const
{
uint8_t routerIdSequence = mRouterIdSequence;
Mle::RouterIdSet routerIdSet = mAllocatedRouterIds;
uint8_t routerCount;
Mle::RouterIdSet routerIdSet;
uint8_t routerIndex;
mRouterIdMap.GetAsRouterIdSet(routerIdSet);
if ((aNeighbor != nullptr) && Mle::IsActiveRouter(aNeighbor->GetRloc16()))
{
// Sending a Link Accept message that may require truncation
// of Route64 TLV.
routerCount = mActiveRouterCount;
uint8_t routerCount = mRouters.GetLength();
if (routerCount > Mle::kLinkAcceptMaxRouters)
{
@@ -536,18 +458,23 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb
aRouteTlv.SetRouterIdSequence(routerIdSequence);
aRouteTlv.SetRouterIdMask(routerIdSet);
routerCount = 0;
routerIndex = 0;
for (const Router *router = GetFirstEntry(); router != nullptr; router = GetNextEntry(router))
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
{
if (!routerIdSet.Contains(router->GetRouterId()))
const Router *router;
if (!routerIdSet.Contains(routerId))
{
continue;
}
router = FindRouterById(routerId);
OT_ASSERT(router != nullptr);
if (router->GetRloc16() == Get<Mle::Mle>().GetRloc16())
{
aRouteTlv.SetRouteData(routerCount, kLinkQuality0, kLinkQuality0, 1);
aRouteTlv.SetRouteData(routerIndex, kLinkQuality0, kLinkQuality0, 1);
}
else
{
@@ -574,36 +501,30 @@ void RouterTable::FillRouteTlv(Mle::RouteTlv &aRouteTlv, const Neighbor *aNeighb
routeCost = 0;
}
aRouteTlv.SetRouteData(routerCount, router->GetLinkQualityIn(), router->GetLinkQualityOut(), routeCost);
aRouteTlv.SetRouteData(routerIndex, router->GetLinkQualityIn(), router->GetLinkQualityOut(), routeCost);
}
routerCount++;
routerIndex++;
}
aRouteTlv.SetRouteDataLength(routerCount);
aRouteTlv.SetRouteDataLength(routerIndex);
}
void RouterTable::HandleTimeTick(void)
{
Mle::MleRouter &mle = Get<Mle::MleRouter>();
mRouterIdMap.HandleTimeTick();
if (mle.IsLeader())
VerifyOrExit(Get<Mle::MleRouter>().IsLeader());
// Update router id sequence
if (GetLeaderAge() >= Mle::kRouterIdSequencePeriod)
{
// update router id sequence
if (GetLeaderAge() >= Mle::kRouterIdSequencePeriod)
{
mRouterIdSequence++;
mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
}
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
{
if (mRouterIdReuseDelay[routerId] > 0)
{
mRouterIdReuseDelay[routerId]--;
}
}
mRouterIdSequence++;
mRouterIdSequenceLastUpdated = TimerMilli::GetNow();
}
exit:
return;
}
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
@@ -627,14 +548,41 @@ exit:
}
#endif
void RouterTable::RouterIdMap::GetAsRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const
{
aRouterIdSet.Clear();
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
{
if (IsAllocated(routerId))
{
aRouterIdSet.Add(routerId);
}
}
}
void RouterTable::RouterIdMap::HandleTimeTick(void)
{
for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++)
{
// If Router ID is not allocated the `mIndexes` tracks the
// remaining reuse delay time in seconds.
if (!IsAllocated(routerId) && (mIndexes[routerId] > 0))
{
mIndexes[routerId]--;
}
}
}
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void RouterTable::LogRouteTable(void)
void RouterTable::LogRouteTable(void) const
{
static constexpr uint16_t kStringSize = 128;
LogInfo("Route table");
for (Router &router : Iterate())
for (const Router &router : mRouters)
{
String<kStringSize> string;
+53 -76
View File
@@ -33,6 +33,7 @@
#if OPENTHREAD_FTD
#include "common/array.hpp"
#include "common/const_cast.hpp"
#include "common/encoding.hpp"
#include "common/iterator_utils.hpp"
@@ -49,41 +50,8 @@ namespace ot {
class RouterTable : public InstanceLocator, private NonCopyable
{
friend class NeighborTable;
class IteratorBuilder;
public:
/**
* This class represents an iterator for iterating through entries in the router table.
*
*/
class Iterator : public InstanceLocator, public ItemPtrIterator<Router, Iterator>
{
friend class ItemPtrIterator<Router, Iterator>;
friend class IteratorBuilder;
public:
/**
* This constructor initializes an `Iterator` instance to start from beginning of the router table.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit Iterator(Instance &aInstance);
private:
enum IteratorType : uint8_t
{
kEndIterator,
};
Iterator(Instance &aInstance, IteratorType)
: InstanceLocator(aInstance)
{
}
void Advance(void);
};
/**
* Constructor.
*
@@ -148,7 +116,7 @@ public:
* @returns The number of active routers in the Thread network.
*
*/
uint8_t GetActiveRouterCount(void) const { return mActiveRouterCount; }
uint8_t GetActiveRouterCount(void) const { return mRouters.GetLength(); }
/**
* This method returns the leader in the Thread network.
@@ -258,8 +226,7 @@ public:
*/
bool Contains(const Neighbor &aNeighbor) const
{
return mRouters <= &static_cast<const Router &>(aNeighbor) &&
&static_cast<const Router &>(aNeighbor) < mRouters + Mle::kMaxRouters;
return mRouters.IsInArrayBuffer(&static_cast<const Router &>(aNeighbor));
}
/**
@@ -308,7 +275,7 @@ public:
* @retval FALSE if @p aRouterId is not allocated.
*
*/
bool IsAllocated(uint8_t aRouterId) const;
bool IsAllocated(uint8_t aRouterId) const { return mRouterIdMap.IsAllocated(aRouterId); }
/**
* This method updates the Router ID allocation set.
@@ -325,7 +292,7 @@ public:
* @returns The allocated Router ID set.
*
*/
const Mle::RouterIdSet &GetRouterIdSet(void) const { return mAllocatedRouterIds; }
void GetRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const { return mRouterIdMap.GetAsRouterIdSet(aRouterIdSet); }
/**
* This method fills a Route TLV.
@@ -346,18 +313,6 @@ public:
*/
void HandleTimeTick(void);
/**
* This method enables range-based `for` loop iteration over all Router entries in the Router table.
*
* This method should be used as follows:
*
* for (Router &router : Get<RouterTable>().Iterate()) { ... }
*
* @returns An `IteratorBuilder` instance.
*
*/
IteratorBuilder Iterate(void) { return IteratorBuilder(GetInstance()); }
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
void GetRouterIdRange(uint8_t &aMinRouterId, uint8_t &aMaxRouterId) const;
@@ -369,30 +324,23 @@ public:
* This method logs the route table.
*
*/
void LogRouteTable(void);
void LogRouteTable(void) const;
#else
void LogRouteTable(void) {}
void LogRouteTable(void) const {}
#endif
// The following methods are intended to support range-based `for`
// loop iteration over the router and should not be used
// directly.
Router *begin(void) { return mRouters.begin(); }
Router *end(void) { return mRouters.end(); }
const Router *begin(void) const { return mRouters.begin(); }
const Router *end(void) const { return mRouters.end(); }
private:
class IteratorBuilder : public InstanceLocator
{
public:
explicit IteratorBuilder(Instance &aInstance)
: InstanceLocator(aInstance)
{
}
Iterator begin(void) { return Iterator(GetInstance()); }
Iterator end(void) { return Iterator(GetInstance(), Iterator::kEndIterator); }
};
void UpdateAllocation(void);
const Router *GetFirstEntry(void) const;
const Router *GetNextEntry(const Router *aRouter) const;
Router *GetFirstEntry(void) { return AsNonConst(AsConst(this)->GetFirstEntry()); }
Router *GetNextEntry(Router *aRouter) { return AsNonConst(AsConst(this)->GetNextEntry(aRouter)); }
Router *AddRouter(uint8_t aRouterId);
void RemoveRouter(Router &aRouter);
Router *FindNeighbor(uint16_t aRloc16);
Router *FindNeighbor(const Mac::ExtAddress &aExtAddress);
Router *FindNeighbor(const Mac::Address &aMacAddress);
@@ -402,12 +350,41 @@ private:
return AsNonConst(AsConst(this)->FindRouter(aMatcher));
}
Router mRouters[Mle::kMaxRouters];
Mle::RouterIdSet mAllocatedRouterIds;
uint8_t mRouterIdReuseDelay[Mle::kMaxRouterId + 1];
TimeMilli mRouterIdSequenceLastUpdated;
uint8_t mRouterIdSequence;
uint8_t mActiveRouterCount;
class RouterIdMap
{
public:
// The `RouterIdMap` tracks which Router IDs are allocated.
// For allocated IDs, tracks the index of the `Router` entry
// in `mRouters` array. For unallocated IDs, tracks the
// remaining reuse delay time (in seconds).
RouterIdMap(void) { Clear(); }
void Clear(void) { memset(mIndexes, 0, sizeof(mIndexes)); }
bool IsAllocated(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kAllocatedFlag); }
uint8_t GetIndex(uint8_t aRouterId) const { return (mIndexes[aRouterId] & kIndexMask); }
void SetIndex(uint8_t aRouterId, uint8_t aIndex) { mIndexes[aRouterId] = kAllocatedFlag | aIndex; }
bool CanAllocate(uint8_t aRouterId) const { return (mIndexes[aRouterId] == 0); }
void Release(uint8_t aRouterId) { mIndexes[aRouterId] = Mle::kRouterIdReuseDelay; }
void GetAsRouterIdSet(Mle::RouterIdSet &aRouterIdSet) const;
void HandleTimeTick(void);
private:
// The high bit in `mIndexes[aRouterId]` indicates whether or
// not the router ID is allocated. The lower 7 bits give either
// the index in `mRouter` array or remaining reuse delay time.
static constexpr uint8_t kAllocatedFlag = 1 << 7;
static constexpr uint8_t kIndexMask = 0x7f;
static_assert(Mle::kRouterIdReuseDelay <= kIndexMask, "Mle::kRouterIdReuseDelay does not fit in 7 bits");
uint8_t mIndexes[Mle::kMaxRouterId + 1];
};
Array<Router, Mle::kMaxRouters> mRouters;
RouterIdMap mRouterIdMap;
TimeMilli mRouterIdSequenceLastUpdated;
uint8_t mRouterIdSequence;
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
uint8_t mMinRouterId;
uint8_t mMaxRouterId;
+8
View File
@@ -249,6 +249,14 @@ public:
*/
const Mle::RouterIdSet &GetAssignedRouterIdMask(void) const { return mAssignedRouterIdMask; }
/**
* This method gets the Assigned Router ID Mask.
*
* @returns The Assigned Router ID Mask.
*
*/
Mle::RouterIdSet &GetAssignedRouterIdMask(void) { return mAssignedRouterIdMask; }
/**
* This method sets the Assigned Router ID Mask.
*