[nexus] migrate router and leader reboot tests to Nexus (#12970)

This commit migrates the following tests from thread-cert to Nexus:
- test_router_reboot_multiple_link_request.py
- test_leader_reboot_multiple_link_request.py

New Nexus tests cover:
- Router rebooting and sending multiple Link Requests when isolated.
- Leader rebooting and sending multiple Link Requests when isolated.

The original Python cert tests are removed as they are now fully
covered by the Nexus framework.
This commit is contained in:
Jonathan Hui
2026-04-27 11:00:17 -07:00
committed by GitHub
parent b72272fcb1
commit e74aebb2bd
8 changed files with 437 additions and 331 deletions
+2
View File
@@ -399,6 +399,7 @@ ot_nexus_test(form_join "core;nexus")
ot_nexus_test(ipv6_fragmentation "core;nexus")
ot_nexus_test(ipv6_source_selection "core;nexus")
ot_nexus_test(key_rotation_guard_time "core;nexus")
ot_nexus_test(leader_reboot_multiple_link_request "core;nexus")
ot_nexus_test(log_override "core;nexus")
ot_nexus_test(mac_scan "core;nexus")
ot_nexus_test(mle_blocking_downgrade "core;nexus")
@@ -408,6 +409,7 @@ ot_nexus_test(netdata_publisher "core;nexus")
ot_nexus_test(reed_address_solicit_rejected "core;nexus")
ot_nexus_test(router_downgrade_on_sec_policy_change "core;nexus")
ot_nexus_test(router_reattach "core;nexus")
ot_nexus_test(router_reboot_multiple_link_request "core;nexus")
ot_nexus_test(srp_auto_start "core;nexus")
ot_nexus_test(srp_client_change_lease "core;nexus")
ot_nexus_test(srp_client_remove_host "core;nexus")
+2
View File
@@ -235,6 +235,8 @@ DEFAULT_TESTS=(
"1_4_CS_TC_3"
"srp_client_change_lease"
"inform_previous_parent_on_reattach"
"leader_reboot_multiple_link_request"
"router_reboot_multiple_link_request"
)
# Use provided arguments or the default test list
@@ -0,0 +1,120 @@
/*
* Copyright (c) 2026, 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 "platform/nexus_core.hpp"
#include "platform/nexus_node.hpp"
namespace ot {
namespace Nexus {
/**
* Time to advance for a node to form a network and become leader, in milliseconds.
*/
static constexpr uint32_t kFormNetworkTime = 13 * 1000;
/**
* Time to advance for a node to join as a child and upgrade to a router, in milliseconds.
*/
static constexpr uint32_t kAttachToRouterTime = 200 * 1000;
/**
* Time to advance for the network to stabilize, in milliseconds.
*/
static constexpr uint32_t kStabilizationTime = 10 * 1000;
/**
* Time to advance after Leader reset to allow it to send all link requests.
*/
static constexpr uint32_t kResetRestoringTime = 10 * 1000;
void TestLeaderRebootMultipleLinkRequest(void)
{
/**
* Test Leader Reboot Multiple Link Request
*
* Topology
* - Leader
* - Router
*
* Purpose & Description
* The purpose of this test case is to show that when the Leader is rebooted, it sends
* MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
*/
Core nexus;
Node &leader = nexus.CreateNode();
Node &router = nexus.CreateNode();
leader.SetName("LEADER");
router.SetName("ROUTER");
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo));
Log("Step 1: Form topology");
AllowLinkBetween(leader, router);
leader.Form();
nexus.AdvanceTime(kFormNetworkTime);
VerifyOrQuit(leader.Get<Mle::Mle>().IsLeader());
router.Join(leader);
nexus.AdvanceTime(kAttachToRouterTime);
VerifyOrQuit(router.Get<Mle::Mle>().IsRouter());
nexus.AdvanceTime(kStabilizationTime);
Log("Step 2: Reset Leader and isolate it from Router");
leader.Reset();
// Isolate Leader from Router so it doesn't receive Link Accept
UnallowLinkBetween(leader, router);
Log("Step 3: Start Leader and wait for it to send multiple Link Requests");
leader.Get<ThreadNetif>().Up();
SuccessOrQuit(leader.Get<Mle::Mle>().Start());
nexus.AdvanceTime(kResetRestoringTime);
nexus.SaveTestInfo("test_leader_reboot_multiple_link_request.json", &leader);
}
} // namespace Nexus
} // namespace ot
int main(void)
{
ot::Nexus::TestLeaderRebootMultipleLinkRequest();
printf("All tests passed\n");
return 0;
}
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2026, 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 "platform/nexus_core.hpp"
#include "platform/nexus_node.hpp"
namespace ot {
namespace Nexus {
/**
* Time to advance for a node to form a network and become leader, in milliseconds.
*/
static constexpr uint32_t kFormNetworkTime = 13 * 1000;
/**
* Time to advance for a node to join as a child and upgrade to a router, in milliseconds.
*/
static constexpr uint32_t kAttachToRouterTime = 200 * 1000;
/**
* Time to advance for a node to join as a child, in milliseconds.
*/
static constexpr uint32_t kAttachAsChildTime = 10 * 1000;
/**
* Time to advance for the network to stabilize, in milliseconds.
*/
static constexpr uint32_t kStabilizationTime = 10 * 1000;
/**
* Time to advance after Router reset to allow it to send all link requests.
*
* Router transitions must account for a potential jitter of up to 2 minutes (120 seconds).
*/
static constexpr uint32_t kResetRestoringTime = 120 * 1000;
void TestRouterRebootMultipleLinkRequest(void)
{
/**
* Test Router Reboot Multiple Link Request
*
* Topology
* - Leader
* - Router
* - MED (attached to Router)
*
* Purpose & Description
* The purpose of this test case is to show that when a router is rebooted, it sends
* MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
*/
Core nexus;
Node &leader = nexus.CreateNode();
Node &router = nexus.CreateNode();
Node &med = nexus.CreateNode();
leader.SetName("LEADER");
router.SetName("ROUTER");
med.SetName("MED");
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelInfo));
Log("Step 1: Form topology");
AllowLinkBetween(leader, router);
AllowLinkBetween(router, med);
leader.Form();
nexus.AdvanceTime(kFormNetworkTime);
VerifyOrQuit(leader.Get<Mle::Mle>().IsLeader());
router.Join(leader);
nexus.AdvanceTime(kAttachToRouterTime);
VerifyOrQuit(router.Get<Mle::Mle>().IsRouter());
med.Join(router, Node::kAsMed);
nexus.AdvanceTime(kAttachAsChildTime);
VerifyOrQuit(med.Get<Mle::Mle>().IsChild());
VerifyOrQuit(med.Get<Mle::Mle>().GetParent().GetExtAddress() == router.Get<Mac::Mac>().GetExtAddress());
nexus.AdvanceTime(kStabilizationTime);
Log("Step 2: Reset Router and isolate it from Leader");
router.Reset();
// Isolate Router from Leader so it doesn't receive Link Accept
UnallowLinkBetween(leader, router);
Log("Step 3: Start Router and wait for it to send multiple Link Requests");
router.Get<ThreadNetif>().Up();
SuccessOrQuit(router.Get<Mle::Mle>().Start());
nexus.AdvanceTime(kResetRestoringTime);
nexus.SaveTestInfo("test_router_reboot_multiple_link_request.json", &leader);
}
} // namespace Nexus
} // namespace ot
int main(void)
{
ot::Nexus::TestRouterRebootMultipleLinkRequest();
printf("All tests passed\n");
return 0;
}
@@ -0,0 +1,87 @@
#!/usr/bin/env python3
#
# Copyright (c) 2026, 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.
#
import sys
import os
# Add the current directory to sys.path to find verify_utils
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(CUR_DIR)
import verify_utils
from pktverify import consts
from pktverify.null_field import nullField
def verify(pv):
# Test Leader Reboot Multiple Link Request
#
# Topology
# - Leader
# - Router
#
# Purpose & Description
# The purpose of this test case is to show that when the Leader is rebooted, it sends
# MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
# Step 1: Form topology
# - Verify topology is formed correctly.
pv.verify_attached('ROUTER', 'LEADER')
# Step 2: Reset Leader and isolate it from Router
# - The Leader MUST send MLE_MAX_RESTORING_TRANSMISSION_COUNT multicast Link Request
# since it doesn't receive Link Accept from Router.
# The value of MLE_MAX_RESTORING_TRANSMISSION_COUNT is 4 by default.
MLE_MAX_RESTORING_TRANSMISSION_COUNT = 4
for i in range(MLE_MAX_RESTORING_TRANSMISSION_COUNT):
pkts.filter_wpan_src64(LEADER).\
filter_LLARMA().\
filter_mle_cmd(consts.MLE_LINK_REQUEST).\
filter(lambda p: {
consts.CHALLENGE_TLV,
consts.VERSION_TLV,
consts.TLV_REQUEST_TLV,
consts.ADDRESS16_TLV,
consts.ROUTE64_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr16 is nullField and\
p.mle.tlv.route64.id_mask is nullField).\
must_next()
if __name__ == '__main__':
verify_utils.run_main(verify)
@@ -0,0 +1,90 @@
#!/usr/bin/env python3
#
# Copyright (c) 2026, 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.
#
import sys
import os
# Add the current directory to sys.path to find verify_utils
CUR_DIR = os.path.dirname(os.path.abspath(__file__))
sys.path.append(CUR_DIR)
import verify_utils
from pktverify import consts
from pktverify.null_field import nullField
def verify(pv):
# Test Router Reboot Multiple Link Request
#
# Topology
# - Leader
# - Router
# - MED (attached to Router)
#
# Purpose & Description
# The purpose of this test case is to show that when a router is rebooted, it sends
# MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
MED = pv.vars['MED']
# Step 1: Form topology
# - Verify topology is formed correctly.
pv.verify_attached('ROUTER', 'LEADER')
pv.verify_attached('MED', 'ROUTER', 'MTD')
# Step 2: Reset Router and isolate it from Leader
# - The router MUST send MLE_MAX_RESTORING_TRANSMISSION_COUNT multicast Link Request
# since it doesn't receive Link Accept from Leader.
# The value of MLE_MAX_RESTORING_TRANSMISSION_COUNT is 4 by default.
MLE_MAX_RESTORING_TRANSMISSION_COUNT = 4
for i in range(MLE_MAX_RESTORING_TRANSMISSION_COUNT):
pkts.filter_wpan_src64(ROUTER).\
filter_LLARMA().\
filter_mle_cmd(consts.MLE_LINK_REQUEST).\
filter(lambda p: {
consts.CHALLENGE_TLV,
consts.VERSION_TLV,
consts.TLV_REQUEST_TLV,
consts.ADDRESS16_TLV,
consts.ROUTE64_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr16 is nullField and\
p.mle.tlv.route64.id_mask is nullField).\
must_next()
if __name__ == '__main__':
verify_utils.run_main(verify)
@@ -1,155 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (c) 2023, 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.
#
import copy
import unittest
import command
import config
import mle
import thread_cert
from pktverify.consts import MLE_PARENT_REQUEST, MLE_LINK_REQUEST, MLE_LINK_ACCEPT, MLE_LINK_ACCEPT_AND_REQUEST, SOURCE_ADDRESS_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, TLV_REQUEST_TLV, VERSION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
DUT_LEADER = 1
DUT_ROUTER1 = 2
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to show that when the Leader is rebooted, it sends MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
#
# Test Topology:
# -------------
# Leader
# |
# Router
#
# DUT Types:
# ----------
# Leader
# Router
class Test_LeaderRebootMultipleLinkRequest(thread_cert.TestCase):
#USE_MESSAGE_FACTORY = False
TOPOLOGY = {
DUT_LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [DUT_ROUTER1]
},
DUT_ROUTER1: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [DUT_LEADER]
},
}
def _setUpLeader(self):
self.nodes[DUT_LEADER].add_allowlist(self.nodes[DUT_ROUTER1].get_addr64())
self.nodes[DUT_LEADER].enable_allowlist()
def test(self):
self.nodes[DUT_LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER1].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_ROUTER1].get_state(), 'router')
leader_rloc = self.nodes[DUT_LEADER].get_ip6_address(config.ADDRESS_TYPE.RLOC)
leader_rloc16 = self.nodes[DUT_LEADER].get_addr16()
self.nodes[DUT_LEADER].reset()
self.assertFalse(self.nodes[DUT_ROUTER1].ping(leader_rloc))
self._setUpLeader()
# Router1 will not reply to leader's link request
self.nodes[DUT_ROUTER1].clear_allowlist()
self.nodes[DUT_LEADER].start()
self.simulator.go(config.LEADER_RESET_DELAY)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
# Verify topology is formed correctly.
pv.verify_attached('ROUTER', 'LEADER')
# The DUT MUST send properly formatted MLE Advertisements with
# an IP Hop Limit of 255 to the Link-Local All Nodes multicast
# address (FF02::1).
# The following TLVs MUST be present in the MLE Advertisements:
# - Leader Data TLV
# - Route64 TLV
# - Source Address TLV
with pkts.save_index():
pkts.filter_wpan_src64(LEADER).\
filter_mle_advertisement('Leader').\
must_next()
pkts.filter_wpan_src64(ROUTER).\
filter_mle_advertisement('Router').\
must_next()
pkts.filter_ping_request().\
filter_wpan_src64(ROUTER).\
must_next()
# The Leader MUST send MLE_MAX_RESTORING_TRANSMISSION_COUNT multicast Link Request
# The following TLVs MUST be present in the Link Request:
# - Challenge TLV
# - Version TLV
# - TLV Request TLV: Address16 TLV, Route64 TLV
for i in range(0, config.MLE_MAX_RESTORING_TRANSMISSION_COUNT):
pkts.filter_wpan_src64(LEADER).\
filter_LLARMA().\
filter_mle_cmd(MLE_LINK_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
VERSION_TLV,
TLV_REQUEST_TLV,
ADDRESS16_TLV,
ROUTE64_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr16 is nullField and\
p.mle.tlv.route64.id_mask is nullField
).\
must_next()
if __name__ == '__main__':
unittest.main()
@@ -1,176 +0,0 @@
#!/usr/bin/env python3
#
# Copyright (c) 2023, 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.
#
import copy
import unittest
import command
import config
import mle
import thread_cert
from pktverify.consts import MLE_PARENT_REQUEST, MLE_LINK_REQUEST, MLE_LINK_ACCEPT, MLE_LINK_ACCEPT_AND_REQUEST, SOURCE_ADDRESS_TLV, CHALLENGE_TLV, RESPONSE_TLV, LINK_LAYER_FRAME_COUNTER_TLV, ROUTE64_TLV, ADDRESS16_TLV, LEADER_DATA_TLV, TLV_REQUEST_TLV, VERSION_TLV
from pktverify.packet_verifier import PacketVerifier
from pktverify.null_field import nullField
LEADER = 1
DUT_ROUTER = 2
MED1 = 3
MED2 = 4
MED3 = 5
MED4 = 6
MED5 = 7
MED6 = 8
# Test Purpose and Description:
# -----------------------------
# The purpose of this test case is to show that when a router is rebooted, it sends MLE_MAX_RESTORING_TRANSMISSION_COUNT MLE link request packets if no response is received.
#
# Test Topology:
# -------------
# Leader
# |
# Router ------------------------+
# | | | | | |
# MED1 MED2 MED3 MED4 MED5 MED6
#
# DUT Types:
# ----------
# Router
class Test_LeaderRebootMultipleLinkRequest(thread_cert.TestCase):
#USE_MESSAGE_FACTORY = False
TOPOLOGY = {
LEADER: {
'name': 'LEADER',
'mode': 'rdn',
'allowlist': [DUT_ROUTER]
},
DUT_ROUTER: {
'name': 'ROUTER',
'mode': 'rdn',
'allowlist': [LEADER, MED1, MED2, MED3, MED4, MED5, MED6]
},
MED1: {
'name': 'MED1',
'mode': 'rn',
'allowlist': [DUT_ROUTER]
},
MED2: {
'name': 'MED2',
'mode': 'rn',
'allowlist': [DUT_ROUTER]
},
MED3: {
'name': 'MED3',
'mode': 'rn',
'allowlist': [DUT_ROUTER]
},
MED4: {
'name': 'MED4',
'mode': 'rn',
'allowlist': [DUT_ROUTER]
},
MED5: {
'name': 'MED5',
'mode': 'rn',
'allowlist': [DUT_ROUTER]
},
MED6: {
'name': 'MED6',
'mode': 'rn',
'allowlist': [DUT_ROUTER]
},
}
def test(self):
self.nodes[LEADER].start()
self.simulator.go(config.LEADER_STARTUP_DELAY)
self.assertEqual(self.nodes[LEADER].get_state(), 'leader')
self.nodes[DUT_ROUTER].start()
self.simulator.go(config.ROUTER_STARTUP_DELAY)
self.assertEqual(self.nodes[DUT_ROUTER].get_state(), 'router')
for medid in range(MED1, MED6 + 1):
self.nodes[medid].start()
self.simulator.go(config.ED_STARTUP_DELAY)
self.assertEqual(self.nodes[medid].get_state(), 'child')
self.simulator.go(config.MAX_ADVERTISEMENT_INTERVAL)
self.nodes[DUT_ROUTER].reset()
# Leader will not reply to router's link request
self.nodes[LEADER].clear_allowlist()
self.nodes[DUT_ROUTER].start()
self.simulator.go(config.LEADER_RESET_DELAY)
def verify(self, pv):
pkts = pv.pkts
pv.summary.show()
LEADER = pv.vars['LEADER']
ROUTER = pv.vars['ROUTER']
# Verify topology is formed correctly.
pv.verify_attached('ROUTER', 'LEADER')
for i in range(1, 7):
pv.verify_attached('MED%d' % i, 'ROUTER', 'MTD')
pkts.filter_wpan_src64(ROUTER).\
filter_mle_advertisement('Router').\
must_next()
# The router MUST send MLE_MAX_RESTORING_TRANSMISSION_COUNT multicast Link Request
# The following TLVs MUST be present in the Link Request:
# - Challenge TLV
# - Version TLV
# - TLV Request TLV: Address16 TLV, Route64 TLV
for i in range(0, config.MLE_MAX_RESTORING_TRANSMISSION_COUNT):
pkts.filter_wpan_src64(ROUTER).\
filter_LLARMA().\
filter_mle_cmd(MLE_LINK_REQUEST).\
filter(lambda p: {
CHALLENGE_TLV,
VERSION_TLV,
TLV_REQUEST_TLV,
ADDRESS16_TLV,
ROUTE64_TLV
} <= set(p.mle.tlv.type) and\
p.mle.tlv.addr16 is nullField and\
p.mle.tlv.route64.id_mask is nullField
).\
must_next()
if __name__ == '__main__':
unittest.main()