mirror of
https://github.com/espressif/openthread.git
synced 2026-08-02 00:57:47 +00:00
[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:
@@ -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.
|
||||
|
||||
@@ -265,7 +265,7 @@ void Link::HandleTimer(void)
|
||||
HandleTimer(child);
|
||||
}
|
||||
|
||||
for (Router &router : Get<RouterTable>().Iterate())
|
||||
for (Router &router : Get<RouterTable>())
|
||||
{
|
||||
HandleTimer(router);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user