[trel] implement delayed peer removal in PeerTable (#11511)

This commit updates `Trel::Peer` and `PeerTable` to allow scheduling a
`Peer` for removal from the table after a given delay. This enables
smoother peer removal, especially for transient issues, by avoiding
abrupt disconnections.

To implement this, a `State` has been added to the `Peer` class,
tracking whether a peer is in `kStateValid` or `kStateRemoving`. If a
peer scheduled for removal is discovered again, it will be re-added
and marked as valid. Logging is also updated to show these new state
transitions. Additionally, `EvictPeer()` is updated to prioritize
evicting peers already scheduled for removal.

To ensure consistent API behavior, peers that are scheduled for
removal are skipped when iterating over the peer table using
`otTrelGetNextPeer()` or `otTrelGetNumberOfPeers()`.
This commit is contained in:
Abtin Keshavarzian
2025-05-20 11:53:55 -07:00
committed by GitHub
parent 526fcf548a
commit 4f692464d5
4 changed files with 123 additions and 41 deletions
+65 -9
View File
@@ -51,11 +51,13 @@ void Peer::Init(Instance &aInstance)
AsCoreType(&mExtAddress).Clear();
AsCoreType(&mExtPanId).Clear();
AsCoreType(&mSockAddr).Clear();
mState = kStateValid;
}
void Peer::Free(void)
{
Log(kRemoving);
Log(kDeleted);
#if OPENTHREAD_CONFIG_TREL_USE_HEAP_ENABLE
Heap::Allocatable<Peer>::Free();
@@ -65,6 +67,22 @@ void Peer::Free(void)
#endif
}
void Peer::ScheduleToRemoveAfter(uint32_t aDelay)
{
VerifyOrExit(IsStateValid());
mRemoveTime = TimerMilli::GetNow() + aDelay;
SetState(kStateRemoving);
Get<PeerTable>().mTimer.FireAtIfEarlier(mRemoveTime);
Log(kRemoving);
LogInfo(" after %u msec", aDelay);
exit:
return;
}
bool Peer::Matches(const NonNeighborMatcher &aMatcher) const
{
// Matches only if the peer is not a neighbor. This is used when
@@ -96,17 +114,21 @@ const char *Peer::ActionToString(Action aAction)
{
static const char *const kActionStrings[] = {
"Added", // (0) kAdded
"Updated", // (1) kUpdated
"Removing", // (2) kRemoving
"Evicting", // (3) kEvicting
"Re-added", // (1) kReAdded,
"Updated", // (2) kUpdated
"Removing", // (3) kRemoving
"Deleted", // (4) kDeleted
"Evicting", // (5) kEvicting
};
struct EnumCheck
{
InitEnumValidatorCounter();
ValidateNextEnum(kAdded);
ValidateNextEnum(kReAdded);
ValidateNextEnum(kUpdated);
ValidateNextEnum(kRemoving);
ValidateNextEnum(kDeleted);
ValidateNextEnum(kEvicting);
};
@@ -120,6 +142,7 @@ const char *Peer::ActionToString(Action aAction)
PeerTable::PeerTable(Instance &aInstance)
: InstanceLocator(aInstance)
, mTimer(aInstance)
{
}
@@ -164,10 +187,16 @@ Error PeerTable::EvictPeer(void)
Error error = kErrorNotFound;
OwnedPtr<Peer> peerToEvict;
// We first try to evict a peer belonging to a different PAN.
// If not found, we evict a non-neighbor peer.
// We first try to evict a peer already scheduled to be removed.
// Then try to evict a peer belonging to a different PAN. If not
// found, we evict a non-neighbor peer.
peerToEvict = RemoveMatching(Peer::OtherExtPanIdMatcher(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
peerToEvict = RemoveMatching(Peer::kStateRemoving);
if (peerToEvict == nullptr)
{
peerToEvict = RemoveMatching(Peer::OtherExtPanIdMatcher(Get<MeshCoP::ExtendedPanIdManager>().GetExtPanId()));
}
if (peerToEvict == nullptr)
{
@@ -183,11 +212,36 @@ exit:
return error;
}
void PeerTable::HandleTimer(void)
{
TimeMilli now = TimerMilli::GetNow();
NextFireTime nextFireTime(now);
RemoveAndFreeAllMatching(Peer::ExpireChecker(now));
for (const Peer &peer : *this)
{
if (peer.IsStateRemoving())
{
nextFireTime.UpdateIfEarlier(peer.mRemoveTime);
}
}
mTimer.FireAtIfEarlier(nextFireTime);
}
const Peer *PeerTable::GetNextPeer(PeerIterator &aIterator) const
{
const Peer *entry = static_cast<const Peer *>(aIterator);
VerifyOrExit(entry != nullptr);
while (!entry->IsStateValid())
{
entry = entry->GetNext();
VerifyOrExit(entry != nullptr);
}
aIterator = entry->GetNext();
exit:
@@ -200,8 +254,10 @@ uint16_t PeerTable::GetNumberOfPeers(void) const
for (const Peer &peer : *this)
{
OT_UNUSED_VARIABLE(peer);
count++;
if (peer.IsStateValid())
{
count++;
}
}
return count;
+38 -25
View File
@@ -48,6 +48,7 @@
#include "common/non_copyable.hpp"
#include "common/owning_list.hpp"
#include "common/pool.hpp"
#include "common/timer.hpp"
#include "mac/mac_types.hpp"
#include "meshcop/extended_panid.hpp"
#include "net/socket.hpp"
@@ -110,33 +111,21 @@ public:
*/
void SetSockAddr(const Ip6::SockAddr &aSockAddr) { mSockAddr = aSockAddr; }
/**
* Indicates whether the peer matches a given Extended Address.
*
* @param[in] aExtAddress A Extended Address to match with.
*
* @retval TRUE if the peer matches @p aExtAddress.
* @retval FALSE if the peer does not match @p aExtAddress.
*/
bool Matches(const Mac::ExtAddress &aExtAddress) const { return GetExtAddress() == aExtAddress; }
/**
* Indicates whether the peer matches a given Socket Address.
*
* @param[in] aSockAddr A Socket Address to match with.
*
* @retval TRUE if the peer matches @p aSockAddr.
* @retval FALSE if the peer does not match @p aSockAddr.
*/
bool Matches(const Ip6::SockAddr &aSockAddr) const { return GetSockAddr() == aSockAddr; }
private:
enum State : uint8_t
{
kStateValid,
kStateRemoving,
};
enum Action : uint8_t
{
kAdded,
kUpdated,
kRemoving,
kEvicting,
kAdded, // Added a new peer.
kReAdded, // Re-added a peer (discovered again) that was scheduled for removal.
kUpdated, // Updated an existing peer.
kRemoving, // Scheduling a peer to be removed after delay.
kDeleted, // Fully removing and deleting the peer from the table.
kEvicting, // Evicting the peer to make space for new one.
};
struct OtherExtPanIdMatcher // Matches if Ext PAN ID is different.
@@ -159,12 +148,30 @@ private:
NeighborTable &mNeighborTable;
};
struct ExpireChecker // Matches if the peer is in `kStateRemoving` and already expired.
{
explicit ExpireChecker(TimeMilli aNow)
: mNow(aNow)
{
}
TimeMilli mNow;
};
void Init(Instance &aInstance);
void Free(void);
void SetState(State aState) { mState = aState; }
bool IsStateValid(void) const { return mState == kStateValid; }
bool IsStateRemoving(void) const { return mState == kStateRemoving; }
void SetExtAddress(const Mac::ExtAddress &aExtAddress) { mExtAddress = aExtAddress; }
void SetExtPanId(const MeshCoP::ExtendedPanId &aExtPanId) { mExtPanId = aExtPanId; }
void ScheduleToRemoveAfter(uint32_t aDelay);
bool Matches(const Mac::ExtAddress &aExtAddress) const { return GetExtAddress() == aExtAddress; }
bool Matches(const Ip6::SockAddr &aSockAddr) const { return GetSockAddr() == aSockAddr; }
bool Matches(State aState) const { return mState == aState; }
bool Matches(const OtherExtPanIdMatcher &aMatcher) const { return GetExtPanId() != aMatcher.mExtPanId; }
bool Matches(const NonNeighborMatcher &aMatcher) const;
bool Matches(const ExpireChecker &aChecker) const { return IsStateRemoving() && (aChecker.mNow >= mRemoveTime); }
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
void Log(Action aAction) const;
@@ -173,7 +180,9 @@ private:
void Log(Action) const {}
#endif
Peer *mNext;
Peer *mNext;
State mState;
TimeMilli mRemoveTime;
};
//---------------------------------------------------------------------------------------------------------------------
@@ -248,7 +257,11 @@ private:
Peer *AllocatePeer(void);
Error EvictPeer(void);
void HandleTimer(void);
using PeerTimer = TimerMilliIn<PeerTable, &PeerTable::HandleTimer>;
PeerTimer mTimer;
#if !OPENTHREAD_CONFIG_TREL_USE_HEAP_ENABLE
Pool<Peer, PoolSize> mPool;
#endif
+18 -7
View File
@@ -118,7 +118,8 @@ void PeerDiscoverer::HandleDiscoveredPeerInfo(const PeerInfo &aInfo)
Peer *peer;
TxtData txtData;
TxtData::Info txtInfo;
bool isNew = false;
Peer::Action action = Peer::kUpdated;
bool shouldLog = true;
VerifyOrExit(mIsRunning);
@@ -129,7 +130,9 @@ void PeerDiscoverer::HandleDiscoveredPeerInfo(const PeerInfo &aInfo)
if (aInfo.IsRemoved())
{
Get<PeerTable>().RemoveAndFreeAllMatching(txtInfo.mExtAddress);
peer = Get<PeerTable>().FindMatching(txtInfo.mExtAddress);
VerifyOrExit(peer != nullptr);
peer->ScheduleToRemoveAfter(kRemoveDelay);
ExitNow();
}
@@ -158,18 +161,26 @@ void PeerDiscoverer::HandleDiscoveredPeerInfo(const PeerInfo &aInfo)
VerifyOrExit(peer != nullptr);
peer->SetExtAddress(txtInfo.mExtAddress);
isNew = true;
action = Peer::kAdded;
}
if (!isNew)
else if (!peer->IsStateValid())
{
VerifyOrExit((peer->GetExtPanId() != txtInfo.mExtPanId) || (peer->GetSockAddr() != aInfo.GetSockAddr()));
action = Peer::kReAdded;
}
else
{
shouldLog = (peer->GetExtPanId() != txtInfo.mExtPanId) || (peer->GetSockAddr() != aInfo.GetSockAddr());
action = Peer::kUpdated;
}
peer->SetState(Peer::kStateValid);
peer->SetExtPanId(txtInfo.mExtPanId);
peer->SetSockAddr(aInfo.GetSockAddr());
peer->Log(isNew ? Peer::kAdded : Peer::kUpdated);
if (shouldLog)
{
peer->Log(action);
}
exit:
return;
+2
View File
@@ -91,6 +91,8 @@ public:
void NotifyPeerSocketAddressDifference(const Ip6::SockAddr &aPeerSockAddr, const Ip6::SockAddr &aRxSockAddr);
private:
static constexpr uint32_t kRemoveDelay = 7 * Time::kOneSecondInMsec;
class TxtData
{
public: