mirror of
https://github.com/espressif/openthread.git
synced 2026-09-07 01:30:11 +00:00
[nexus] add mechanism to emulate node reset (#11662)
This commit adds a new mechanism to emulate a node reset on `Nexus::Node`. This is realized by resetting all platform components while ensuring the non-volatile `mSettings` remains unchanged, then reinitializing the `ot::Instance` by invoking its constructor. This is used to add a new `test_full_network_reset` test, which emulates a full simultaneous reset of all nodes in a large network, tracking how long it takes for the network to stabilize after the reset event.
This commit is contained in:
@@ -114,5 +114,6 @@ endmacro()
|
||||
ot_nexus_test(border_agent)
|
||||
ot_nexus_test(dtls)
|
||||
ot_nexus_test(form_join)
|
||||
ot_nexus_test(full_network_reset)
|
||||
ot_nexus_test(large_network)
|
||||
ot_nexus_test(trel)
|
||||
|
||||
@@ -36,11 +36,8 @@ namespace Nexus {
|
||||
|
||||
struct Alarm
|
||||
{
|
||||
Alarm(void)
|
||||
: mScheduled(false)
|
||||
{
|
||||
}
|
||||
|
||||
Alarm(void) { Reset(); }
|
||||
void Reset(void) { mScheduled = false; }
|
||||
bool ShouldTrigger(Time aNow) const { return mScheduled && (aNow >= mAlarmTime); }
|
||||
|
||||
bool mScheduled;
|
||||
|
||||
@@ -71,6 +71,12 @@ Mdns::Mdns(void)
|
||||
SuccessOrQuit(mIfAddresses.PushBack(address));
|
||||
}
|
||||
|
||||
void Mdns::Reset(void)
|
||||
{
|
||||
mEnabled = false;
|
||||
mPendingTxList.Free();
|
||||
}
|
||||
|
||||
Error Mdns::SetListeningEnabled(Instance &aInstance, bool aEnable, uint32_t aInfraIfIndex)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
};
|
||||
|
||||
Mdns(void);
|
||||
void Reset(void);
|
||||
Error SetListeningEnabled(Instance &aInstance, bool aEnable, uint32_t aInfraIfIndex);
|
||||
void SendMulticast(Message &aMessage, uint32_t aInfraIfIndex);
|
||||
void SendUnicast(Message &aMessage, const AddressInfo &aAddress);
|
||||
|
||||
@@ -32,6 +32,26 @@
|
||||
namespace ot {
|
||||
namespace Nexus {
|
||||
|
||||
void Node::Reset(void)
|
||||
{
|
||||
Instance *instance = &GetInstance();
|
||||
uint32_t id = GetId();
|
||||
|
||||
mRadio.Reset();
|
||||
mAlarm.Reset();
|
||||
mMdns.Reset();
|
||||
mPendingTasklet = false;
|
||||
#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE
|
||||
mTrel.Reset();
|
||||
#endif
|
||||
|
||||
instance->~Instance();
|
||||
|
||||
instance = new (instance) Instance();
|
||||
instance->SetId(id);
|
||||
instance->AfterInit();
|
||||
}
|
||||
|
||||
void Node::Form(void)
|
||||
{
|
||||
MeshCoP::Dataset::Info datasetInfo;
|
||||
|
||||
@@ -74,6 +74,7 @@ public:
|
||||
kAsSed,
|
||||
};
|
||||
|
||||
void Reset(void);
|
||||
void Form(void);
|
||||
void Join(Node &aNode, JoinMode aJoinMode = kAsFtd);
|
||||
void AllowList(Node &aNode);
|
||||
|
||||
@@ -256,6 +256,15 @@ Radio::Radio(void)
|
||||
{
|
||||
}
|
||||
|
||||
void Radio::Reset(void)
|
||||
{
|
||||
mState = kStateDisabled;
|
||||
mPromiscuous = false;
|
||||
mSrcMatchEnabled = false;
|
||||
mSrcMatchShortEntries.Clear();
|
||||
mSrcMatchExtEntries.Clear();
|
||||
}
|
||||
|
||||
bool Radio::CanReceiveOnChannel(uint8_t aChannel) const
|
||||
{
|
||||
bool canRx = false;
|
||||
|
||||
@@ -59,6 +59,7 @@ struct Radio
|
||||
};
|
||||
|
||||
Radio(void);
|
||||
void Reset(void);
|
||||
bool CanReceiveOnChannel(uint8_t aChannel) const;
|
||||
bool Matches(const Mac::Address &aAddress, Mac::PanId aPanId) const;
|
||||
bool HasFramePendingFor(const Mac::Address &aAddress) const;
|
||||
|
||||
@@ -80,6 +80,13 @@ Trel::Trel(void)
|
||||
ClearAllBytes(mCounters);
|
||||
}
|
||||
|
||||
void Trel::Reset(void)
|
||||
{
|
||||
mEnabled = false;
|
||||
ClearAllBytes(mCounters);
|
||||
mPendingTxList.Free();
|
||||
}
|
||||
|
||||
void Trel::Enable(uint16_t &aUdpPort)
|
||||
{
|
||||
mEnabled = true;
|
||||
|
||||
@@ -43,6 +43,7 @@ struct Trel
|
||||
typedef otPlatTrelCounters Counters;
|
||||
|
||||
Trel(void);
|
||||
void Reset(void);
|
||||
void Enable(uint16_t &aUdpPort);
|
||||
void Disable(void);
|
||||
void Send(const uint8_t *aUdpPayload, uint16_t aUdpPayloadLen, const Ip6::SockAddr &aDestSockAddr);
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright (c) 2025, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform/nexus_core.hpp"
|
||||
#include "platform/nexus_node.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Nexus {
|
||||
|
||||
static constexpr uint16_t kNumberOfRoles = (Mle::kRoleLeader + 1);
|
||||
|
||||
typedef uint16_t RoleStats[kNumberOfRoles];
|
||||
|
||||
static void CalculateRoleStats(Core &aNexus, RoleStats &aRoleStats)
|
||||
{
|
||||
ClearAllBytes(aRoleStats);
|
||||
|
||||
for (Node &node : aNexus.GetNodes())
|
||||
{
|
||||
aRoleStats[node.Get<Mle::Mle>().GetRole()]++;
|
||||
}
|
||||
}
|
||||
|
||||
static bool CheckRoleStats(const RoleStats &aRoleStats)
|
||||
{
|
||||
return (aRoleStats[Mle::kRoleLeader] == 1) && (aRoleStats[Mle::kRoleDetached] == 0) &&
|
||||
(aRoleStats[Mle::kRoleDisabled] == 0);
|
||||
}
|
||||
|
||||
void Test(void)
|
||||
{
|
||||
static constexpr uint16_t kNumNodes = 200;
|
||||
|
||||
// All times in msec
|
||||
static constexpr uint32_t kMaxWaitTime = 20 * Time::kOneMinuteInMsec;
|
||||
static constexpr uint32_t kStatCollectionInterval = 500;
|
||||
static constexpr uint32_t kExtraSimulTimeAfterPass = 5 * Time::kOneSecondInMsec;
|
||||
|
||||
Core nexus;
|
||||
Node *leader;
|
||||
RoleStats roleStats;
|
||||
TimeMilli resetTime;
|
||||
|
||||
for (uint16_t i = 0; i < kNumNodes; i++)
|
||||
{
|
||||
nexus.CreateNode();
|
||||
}
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
Log("Starting %u nodes staggered", kNumNodes);
|
||||
|
||||
leader = nexus.GetNodes().GetHead();
|
||||
leader->Form();
|
||||
|
||||
for (Node &node : nexus.GetNodes())
|
||||
{
|
||||
if (&node == leader)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
node.Join(*leader);
|
||||
nexus.AdvanceTime(Time::kOneSecondInMsec);
|
||||
}
|
||||
|
||||
for (uint32_t step = 0; step < kMaxWaitTime / kStatCollectionInterval; step++)
|
||||
{
|
||||
if ((step % 20) == 0)
|
||||
{
|
||||
Log("+----------+----------+----------+----------+----------+");
|
||||
Log("| Leader | Router | Child | Detached | Disabled |");
|
||||
Log("+----------+----------+----------+----------+----------+");
|
||||
}
|
||||
|
||||
CalculateRoleStats(nexus, roleStats);
|
||||
|
||||
Log("| %8u | %8u | %8u | %8u | %8u |", roleStats[Mle::kRoleLeader], roleStats[Mle::kRoleRouter],
|
||||
roleStats[Mle::kRoleChild], roleStats[Mle::kRoleDetached], roleStats[Mle::kRoleDisabled]);
|
||||
|
||||
nexus.AdvanceTime(kStatCollectionInterval);
|
||||
|
||||
if (CheckRoleStats(roleStats))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(CheckRoleStats(roleStats));
|
||||
|
||||
Log("=========================================================");
|
||||
Log("All nodes are now part of the same partition");
|
||||
Log("Resetting all the nodes in the network");
|
||||
Log("=========================================================");
|
||||
|
||||
resetTime = nexus.GetNow();
|
||||
|
||||
for (Node &node : nexus.GetNodes())
|
||||
{
|
||||
node.Reset();
|
||||
}
|
||||
|
||||
for (Node &node : nexus.GetNodes())
|
||||
{
|
||||
node.Get<ThreadNetif>().Up();
|
||||
SuccessOrQuit(node.Get<Mle::Mle>().Start());
|
||||
}
|
||||
|
||||
for (uint32_t step = 0; step < kMaxWaitTime / kStatCollectionInterval; step++)
|
||||
{
|
||||
if ((step % 20) == 0)
|
||||
{
|
||||
Log("+----------+----------+----------+----------+----------+");
|
||||
Log("| Leader | Router | Child | Detached | Disabled |");
|
||||
Log("+----------+----------+----------+----------+----------+");
|
||||
}
|
||||
|
||||
CalculateRoleStats(nexus, roleStats);
|
||||
|
||||
Log("| %8u | %8u | %8u | %8u | %8u |", roleStats[Mle::kRoleLeader], roleStats[Mle::kRoleRouter],
|
||||
roleStats[Mle::kRoleChild], roleStats[Mle::kRoleDetached], roleStats[Mle::kRoleDisabled]);
|
||||
|
||||
nexus.AdvanceTime(kStatCollectionInterval);
|
||||
|
||||
if (CheckRoleStats(roleStats))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Log("=========================================================");
|
||||
Log("All nodes are restored");
|
||||
Log("Network stabilized after %u sec", (nexus.GetNow() - resetTime) / Time::kOneSecondInMsec);
|
||||
Log("=========================================================");
|
||||
|
||||
for (uint32_t step = 0; step < kExtraSimulTimeAfterPass / kStatCollectionInterval; step++)
|
||||
{
|
||||
if ((step % 20) == 0)
|
||||
{
|
||||
Log("+----------+----------+----------+----------+----------+");
|
||||
Log("| Leader | Router | Child | Detached | Disabled |");
|
||||
Log("+----------+----------+----------+----------+----------+");
|
||||
}
|
||||
|
||||
CalculateRoleStats(nexus, roleStats);
|
||||
|
||||
Log("| %8u | %8u | %8u | %8u | %8u |", roleStats[Mle::kRoleLeader], roleStats[Mle::kRoleRouter],
|
||||
roleStats[Mle::kRoleChild], roleStats[Mle::kRoleDetached], roleStats[Mle::kRoleDisabled]);
|
||||
|
||||
nexus.AdvanceTime(kStatCollectionInterval);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::Nexus::Test();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user