Skip to content

Commit 0f66392

Browse files
authored
[nexus] migrate on-mesh prefix test to nexus (openthread#12963)
This commit migrates 'test_on_mesh_prefix.py' from the thread-cert functional tests to the Nexus simulation framework. The new Nexus test 'test_on_mesh_prefix.cpp' covers: - Propagation of stable and non-stable on-mesh prefixes. - Different Network Data request behavior for MEDs and SEDs. - MEDs receiving both stable and non-stable prefixes. - SEDs receiving only stable prefixes. - IPv6 address configuration (SLAAC) for all prefixes. - Reachability verification via ICMPv6 Echo Request/Response. Migrating to Nexus provides faster execution and improves the reliability of the functional test suite.
1 parent bbb8e7a commit 0f66392

3 files changed

Lines changed: 200 additions & 137 deletions

File tree

tests/nexus/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,7 @@ ot_nexus_test(mle_blocking_downgrade "core;nexus")
406406
ot_nexus_test(mle_msg_key_seq_jump "core;nexus")
407407
ot_nexus_test(nat64_translator "core;nexus")
408408
ot_nexus_test(netdata_publisher "core;nexus")
409+
ot_nexus_test(on_mesh_prefix "core;nexus")
409410
ot_nexus_test(reed_address_solicit_rejected "core;nexus")
410411
ot_nexus_test(reset "core;nexus")
411412
ot_nexus_test(router_downgrade_on_sec_policy_change "core;nexus")
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* Copyright (c) 2026, The OpenThread Authors.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
* 1. Redistributions of source code must retain the above copyright
8+
* notice, this list of conditions and the following disclaimer.
9+
* 2. Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
* 3. Neither the name of the copyright holder nor the
13+
* names of its contributors may be used to endorse or promote products
14+
* derived from this software without specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
*/
28+
29+
#include <stdio.h>
30+
31+
#include "mac/data_poll_sender.hpp"
32+
#include "platform/nexus_core.hpp"
33+
#include "platform/nexus_node.hpp"
34+
35+
namespace ot {
36+
namespace Nexus {
37+
38+
/**
39+
* Time to advance for a node to form a network and become leader, in milliseconds.
40+
*/
41+
static constexpr uint32_t kFormNetworkTime = 13 * 1000;
42+
43+
/**
44+
* Time to advance for a node to join as a child and upgrade to a router, in milliseconds.
45+
*/
46+
static constexpr uint32_t kAttachToRouterTime = 200 * 1000;
47+
48+
/**
49+
* Time to advance for the network to stabilize after routers have attached.
50+
*/
51+
static constexpr uint32_t kStabilizationTime = 130 * 1000;
52+
53+
static bool HasAddressWithPrefix(Node &aNode, const char *aPrefixString)
54+
{
55+
Ip6::Prefix prefix;
56+
bool found = false;
57+
58+
SuccessOrQuit(prefix.FromString(aPrefixString));
59+
60+
for (const Ip6::Netif::UnicastAddress &addr : aNode.Get<ThreadNetif>().GetUnicastAddresses())
61+
{
62+
if (addr.GetAddress().MatchesPrefix(prefix))
63+
{
64+
found = true;
65+
break;
66+
}
67+
}
68+
69+
return found;
70+
}
71+
72+
void TestOnMeshPrefix(void)
73+
{
74+
/**
75+
* Test On-Mesh Prefix functionality.
76+
*
77+
* Topology:
78+
* LEADER <-> ROUTER <-> MED
79+
* \ <-> SED
80+
*/
81+
82+
Core nexus;
83+
84+
Node &leader = nexus.CreateNode();
85+
Node &router = nexus.CreateNode();
86+
Node &med = nexus.CreateNode();
87+
Node &sed = nexus.CreateNode();
88+
89+
leader.SetName("LEADER");
90+
router.SetName("ROUTER");
91+
med.SetName("MED");
92+
sed.SetName("SED");
93+
94+
const char *kPrefix1 = "2001:2:0:1::/64";
95+
const char *kPrefix2 = "2001:2:0:2::/64";
96+
const char *kPrefix3 = "2002:2:0:3::/64";
97+
98+
AllowLinkBetween(leader, router);
99+
AllowLinkBetween(router, med);
100+
AllowLinkBetween(router, sed);
101+
102+
nexus.AdvanceTime(0);
103+
104+
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
105+
106+
Log("Step 1: Form network and attach nodes");
107+
leader.Form();
108+
nexus.AdvanceTime(kFormNetworkTime);
109+
VerifyOrQuit(leader.Get<Mle::Mle>().IsLeader());
110+
111+
router.Join(leader, Node::kAsFtd);
112+
med.Join(router, Node::kAsMed);
113+
sed.Join(router, Node::kAsSed);
114+
115+
SuccessOrQuit(med.Get<DataPollSender>().SetExternalPollPeriod(1000));
116+
SuccessOrQuit(sed.Get<DataPollSender>().SetExternalPollPeriod(1000));
117+
118+
nexus.AdvanceTime(kAttachToRouterTime);
119+
120+
VerifyOrQuit(router.Get<Mle::Mle>().IsRouter());
121+
VerifyOrQuit(med.Get<Mle::Mle>().IsChild());
122+
VerifyOrQuit(sed.Get<Mle::Mle>().IsChild());
123+
124+
Log("Step 2: Add prefixes on ROUTER");
125+
// Prefix 1: 'paros' -> Preferred, SLAAC, Router, On-Mesh, Stable
126+
{
127+
NetworkData::OnMeshPrefixConfig config;
128+
config.Clear();
129+
SuccessOrQuit(config.GetPrefix().FromString(kPrefix1));
130+
config.mPreferred = true;
131+
config.mSlaac = true;
132+
config.mOnMesh = true;
133+
config.mStable = true;
134+
SuccessOrQuit(router.Get<NetworkData::Local>().AddOnMeshPrefix(config));
135+
}
136+
137+
// Prefix 2: 'paro' -> Preferred, SLAAC, Router, On-Mesh, NOT Stable
138+
{
139+
NetworkData::OnMeshPrefixConfig config;
140+
config.Clear();
141+
SuccessOrQuit(config.GetPrefix().FromString(kPrefix2));
142+
config.mPreferred = true;
143+
config.mSlaac = true;
144+
config.mOnMesh = true;
145+
config.mStable = false;
146+
SuccessOrQuit(router.Get<NetworkData::Local>().AddOnMeshPrefix(config));
147+
}
148+
149+
router.Get<NetworkData::Notifier>().HandleServerDataUpdated();
150+
nexus.AdvanceTime(kStabilizationTime);
151+
152+
Log("Step 3: Verify addresses on MED and SED");
153+
// MED should have both
154+
VerifyOrQuit(HasAddressWithPrefix(med, kPrefix1));
155+
VerifyOrQuit(HasAddressWithPrefix(med, kPrefix2));
156+
157+
// SED should have only Prefix 1 (stable)
158+
VerifyOrQuit(HasAddressWithPrefix(sed, kPrefix1));
159+
VerifyOrQuit(!HasAddressWithPrefix(sed, kPrefix2));
160+
161+
Log("Step 4: Verify pings from LEADER");
162+
nexus.SendAndVerifyEchoRequest(leader, med.FindMatchingAddress(kPrefix1));
163+
nexus.SendAndVerifyEchoRequest(leader, med.FindMatchingAddress(kPrefix2));
164+
nexus.SendAndVerifyEchoRequest(leader, sed.FindMatchingAddress(kPrefix1));
165+
166+
Log("Step 5: Add prefix 3 (NOT On-Mesh)");
167+
// Prefix 3: 'pars' -> Preferred, SLAAC, Router, Stable, NOT On-Mesh
168+
{
169+
NetworkData::OnMeshPrefixConfig config;
170+
config.Clear();
171+
SuccessOrQuit(config.GetPrefix().FromString(kPrefix3));
172+
config.mPreferred = true;
173+
config.mSlaac = true;
174+
config.mOnMesh = false;
175+
config.mStable = true;
176+
SuccessOrQuit(router.Get<NetworkData::Local>().AddOnMeshPrefix(config));
177+
}
178+
179+
router.Get<NetworkData::Notifier>().HandleServerDataUpdated();
180+
nexus.AdvanceTime(kStabilizationTime);
181+
182+
Log("Step 6: Verify address with Prefix 3 exists on MED and SED");
183+
VerifyOrQuit(HasAddressWithPrefix(med, kPrefix3));
184+
VerifyOrQuit(HasAddressWithPrefix(sed, kPrefix3));
185+
186+
nexus.SaveTestInfo("test_on_mesh_prefix.json");
187+
188+
Log("Test passed");
189+
}
190+
191+
} // namespace Nexus
192+
} // namespace ot
193+
194+
int main(void)
195+
{
196+
ot::Nexus::TestOnMeshPrefix();
197+
printf("All tests passed\n");
198+
return 0;
199+
}

tests/scripts/thread-cert/test_on_mesh_prefix.py

Lines changed: 0 additions & 137 deletions
This file was deleted.

0 commit comments

Comments
 (0)