From 39b982c8d6eccae96fa7921c81a970162d774c30 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Mon, 20 Apr 2026 21:26:02 -0700 Subject: [PATCH] [nexus] migrate ipv6 fragmentation test (#12932) This commit migrates the `test_ipv6_fragmentation.py` cert test to the Nexus simulation framework. To support this migration, the Nexus core configuration was updated to enable IPv6 fragmentation (`OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE`). The new Nexus test `test_ipv6_fragmentation.cpp` covers the validation of IPv6 fragmentation and reassembly. It sends large ICMPv6 Echo Requests exceeding the 1280-byte MTU between a Leader and a Router: - 1952 bytes payload from Leader to Router - 1831 bytes payload from Router to Leader The original Python test script is removed as its functionality is now fully covered by the new Nexus test. --- tests/nexus/CMakeLists.txt | 1 + tests/nexus/openthread-core-nexus-config.h | 1 + tests/nexus/test_ipv6_fragmentation.cpp | 103 ++++++++++++++++++ .../thread-cert/test_ipv6_fragmentation.py | 84 -------------- 4 files changed, 105 insertions(+), 84 deletions(-) create mode 100644 tests/nexus/test_ipv6_fragmentation.cpp delete mode 100755 tests/scripts/thread-cert/test_ipv6_fragmentation.py diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index 6723420e0..db37f9c28 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -394,6 +394,7 @@ ot_nexus_test(discover_scan "core;nexus") ot_nexus_test(dns_client_config_auto_start "core;nexus") ot_nexus_test(dtls "core;nexus") 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(log_override "core;nexus") diff --git a/tests/nexus/openthread-core-nexus-config.h b/tests/nexus/openthread-core-nexus-config.h index 6aa87472a..c842e6367 100644 --- a/tests/nexus/openthread-core-nexus-config.h +++ b/tests/nexus/openthread-core-nexus-config.h @@ -81,6 +81,7 @@ #define OPENTHREAD_CONFIG_IP6_MAX_EXT_MCAST_ADDRS 80 #define OPENTHREAD_CONFIG_MAX_MULTICAST_LISTENERS 80 #define OPENTHREAD_CONFIG_IP6_MAX_EXT_UCAST_ADDRS 8 +#define OPENTHREAD_CONFIG_IP6_FRAGMENTATION_ENABLE 1 #define OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE 1 #define OPENTHREAD_CONFIG_IP6_SLAAC_NUM_ADDRESSES 4 #define OPENTHREAD_CONFIG_JAM_DETECTION_ENABLE 1 diff --git a/tests/nexus/test_ipv6_fragmentation.cpp b/tests/nexus/test_ipv6_fragmentation.cpp new file mode 100644 index 000000000..60ab51626 --- /dev/null +++ b/tests/nexus/test_ipv6_fragmentation.cpp @@ -0,0 +1,103 @@ +/* + * 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 + +#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 wait for ICMPv6 Echo response, in milliseconds. */ +static constexpr uint32_t kEchoTimeout = 10 * 1000; + +void TestIPv6Fragmentation(void) +{ + /** + * Test IPv6 Fragmentation + * + * Topology: + * - Leader + * - Router + * + * Description: + * The purpose of this test case is to validate IPv6 fragmentation and reassembly. + * Large ICMPv6 Echo Requests (exceeding 1280 bytes MTU) are sent between nodes. + */ + + Core nexus; + + Node &leader = nexus.CreateNode(); + Node &router = nexus.CreateNode(); + + leader.SetName("LEADER"); + router.SetName("ROUTER"); + + SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote)); + + Log("Step 1: Form network"); + + AllowLinkBetween(leader, router); + + leader.Form(); + nexus.AdvanceTime(kFormNetworkTime); + VerifyOrQuit(leader.Get().IsLeader()); + + router.Join(leader); + nexus.AdvanceTime(kAttachToRouterTime); + VerifyOrQuit(router.Get().IsRouter()); + + Log("Step 2: Large Echo Request from Leader to Router (1952 bytes payload)"); + // 1952 bytes payload + 8 bytes ICMP header + 40 bytes IPv6 header = 2000 bytes. + // This exceeds the 1280 bytes MTU and triggers IPv6 fragmentation. + nexus.SendAndVerifyEchoRequest(leader, router.Get().GetMeshLocalEid(), 1952, 64, kEchoTimeout); + + Log("Step 3: Large Echo Request from Router to Leader (1831 bytes payload)"); + // 1831 bytes payload + 8 bytes ICMP header + 40 bytes IPv6 header = 1879 bytes. + // This exceeds the 1280 bytes MTU and triggers IPv6 fragmentation. + nexus.SendAndVerifyEchoRequest(router, leader.Get().GetMeshLocalEid(), 1831, 64, kEchoTimeout); + + nexus.SaveTestInfo("test_ipv6_fragmentation.json"); +} + +} // namespace Nexus +} // namespace ot + +int main(void) +{ + ot::Nexus::TestIPv6Fragmentation(); + printf("All tests passed\n"); + return 0; +} diff --git a/tests/scripts/thread-cert/test_ipv6_fragmentation.py b/tests/scripts/thread-cert/test_ipv6_fragmentation.py deleted file mode 100755 index 46739d697..000000000 --- a/tests/scripts/thread-cert/test_ipv6_fragmentation.py +++ /dev/null @@ -1,84 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (c) 2019, 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 unittest - -import common -import config -import thread_cert - -LEADER = 1 -ROUTER = 2 - - -class TestIPv6Fragmentation(thread_cert.TestCase): - SUPPORT_NCP = False - - TOPOLOGY = { - LEADER: { - 'mode': 'rdn', - 'panid': 0xcafe, - 'allowlist': [ROUTER] - }, - ROUTER: { - 'mode': 'rdn', - 'panid': 0xcafe, - 'allowlist': [LEADER] - }, - } - - def test(self): - self.nodes[LEADER].start() - self.simulator.go(config.LEADER_STARTUP_DELAY) - self.assertEqual(self.nodes[LEADER].get_state(), 'leader') - - self.nodes[ROUTER].start() - self.simulator.go(config.ROUTER_STARTUP_DELAY) - self.assertEqual(self.nodes[ROUTER].get_state(), 'router') - - mleid_leader = self.nodes[LEADER].get_ip6_address(config.ADDRESS_TYPE.ML_EID) - mleid_router = self.nodes[ROUTER].get_ip6_address(config.ADDRESS_TYPE.ML_EID) - - self.nodes[LEADER].udp_start("::", common.UDP_TEST_PORT) - self.nodes[ROUTER].udp_start("::", common.UDP_TEST_PORT) - - self.nodes[LEADER].udp_send(1952, mleid_router, common.UDP_TEST_PORT) - self.simulator.go(5) - self.nodes[ROUTER].udp_check_rx(1952) - - self.nodes[ROUTER].udp_send(1831, mleid_leader, common.UDP_TEST_PORT) - self.simulator.go(5) - self.nodes[LEADER].udp_check_rx(1831) - - self.nodes[ROUTER].udp_stop() - self.nodes[LEADER].udp_stop() - - -if __name__ == '__main__': - unittest.main()