diff --git a/tests/nexus/CMakeLists.txt b/tests/nexus/CMakeLists.txt index 1c3b43850..b9d78ff75 100644 --- a/tests/nexus/CMakeLists.txt +++ b/tests/nexus/CMakeLists.txt @@ -215,6 +215,7 @@ ot_nexus_test(1_1_9_2_16 "cert;nexus") ot_nexus_test(1_1_9_2_17 "cert;nexus") ot_nexus_test(1_1_9_2_18 "cert;nexus") ot_nexus_test(1_1_9_2_19 "cert;nexus") +ot_nexus_test(1_2_LP_5_2_1 "cert;nexus") ot_nexus_test(1_2_LP_5_3_1 "cert;nexus") ot_nexus_test(1_2_LP_5_3_2 "cert;nexus") ot_nexus_test(1_2_LP_5_3_3 "cert;nexus") diff --git a/tests/nexus/run_nexus_tests.sh b/tests/nexus/run_nexus_tests.sh index 9dcef51cd..cb07432a3 100755 --- a/tests/nexus/run_nexus_tests.sh +++ b/tests/nexus/run_nexus_tests.sh @@ -150,6 +150,7 @@ DEFAULT_TESTS=( "1_1_9_2_17" "1_1_9_2_18" "1_1_9_2_19" + "1_2_LP_5_2_1" "1_2_LP_5_3_1" "1_2_LP_5_3_2" "1_2_LP_5_3_3" diff --git a/tests/nexus/test_1_2_LP_5_2_1.cpp b/tests/nexus/test_1_2_LP_5_2_1.cpp new file mode 100644 index 000000000..8dfea698e --- /dev/null +++ b/tests/nexus/test_1_2_LP_5_2_1.cpp @@ -0,0 +1,306 @@ +/* + * 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" + +#include "mac/data_poll_sender.hpp" +#include "thread/child_table.hpp" +#include "thread/mesh_forwarder.hpp" + +namespace ot { +namespace Nexus { + +/** + * Time to advance for a node to form a network and become leader. + */ +static constexpr uint32_t kFormNetworkTime = 13 * 1000; + +/** + * Time to advance for a node to join as a child. + */ +static constexpr uint32_t kAttachToChildTime = 10 * 1000; + +/** + * Time to advance for a node to join as a router. + */ +static constexpr uint32_t kAttachToRouterTime = 200 * 1000; + +/** + * ICMPv6 Echo Request payload size. + */ +static constexpr uint16_t kEchoPayloadSize = 10; + +/** + * ICMPv6 Echo Request identifier. + */ +static constexpr uint16_t kEchoIdentifier = 0x1234; + +/** + * Data poll period in milliseconds. + */ +static constexpr uint32_t kPollPeriod = 1000; + +/** + * Very long data poll period in milliseconds (effectively disabling periodic polling). + */ +static constexpr uint32_t kLongPollPeriod = 3600 * 1000; + +/** + * Short wait time to advance nexus time, in milliseconds. + */ +static constexpr uint32_t kShortWaitTime = 100; + +/** + * Wait time for ICMPv6 Echo Reply, in milliseconds. + */ +static constexpr uint32_t kEchoReplyWaitTime = 500; + +/** + * Wait time to ensure a data poll has occurred, in milliseconds. + */ +static constexpr uint32_t kPollWaitTime = 2000; + +void Test1_2_LP_5_2_1(void) +{ + /** + * 5.2.1 Enhanced Frame Pending with Thread V1.2 End Device & V1.1 End Device + * + * 5.2.1.1 Topology + * - SED_1: is Thread 1.1 SED. + * - SED_2: is Thread 1.2 SED with Enhanced Frame Pending (EFP) support; polling via 802.15.4 MAC Data Requests is + * disabled. + * - SED_3: is Thread 1.2 SED with Enhanced Frame Pending (EFP) support; polling via 802.15.4 MAC Data Requests is + * enabled. + * - Router_1: is a Thread Router. + * - DUT: is Thread Leader. + * + * 5.2.1.2 Purpose & Description + * This test case verifies that the DUT correctly manages the Frame Pending bit in acknowledgments to MAC Data and + * Data Request frames for Thread V1.2 and V1.1 sleepy end devices. + * + * Spec Reference | V1.2 Section + * ------------------------|-------------- + * Enhanced Frame Pending | 3.2.6.2 + */ + + Core nexus; + + Node &dut = nexus.CreateNode(); + Node &router1 = nexus.CreateNode(); + Node &sed1 = nexus.CreateNode(); + Node &sed2 = nexus.CreateNode(); + Node &sed3 = nexus.CreateNode(); + + dut.SetName("LEADER"); + router1.SetName("ROUTER_1"); + sed1.SetName("SED_1"); + sed2.SetName("SED_2"); + sed3.SetName("SED_3"); + + /** + * - Use AllowList to specify links between nodes. There is a link between the following node pairs: + * - Leader (DUT) and Router 1 + * - Leader (DUT) and SED 1 + * - Leader (DUT) and SED 2 + * - Leader (DUT) and SED 3 + */ + dut.AllowList(router1); + router1.AllowList(dut); + + dut.AllowList(sed1); + sed1.AllowList(dut); + + dut.AllowList(sed2); + sed2.AllowList(dut); + + dut.AllowList(sed3); + sed3.AllowList(dut); + + nexus.AdvanceTime(0); + + Instance::SetLogLevel(kLogLevelNote); + + /** + * Step 1: All Devices + * - Topology formation. + */ + Log("Step 1: Topology formation"); + dut.Form(); + nexus.AdvanceTime(kFormNetworkTime); + + router1.Join(dut, Node::kAsFtd); + nexus.AdvanceTime(kAttachToRouterTime); + + sed1.Join(dut, Node::kAsSed); + sed2.Join(dut, Node::kAsSed); + sed3.Join(dut, Node::kAsSed); + nexus.AdvanceTime(kAttachToChildTime); + + /** + * - Manually set SED_1 version to 1.1 in Leader's child table to strictly follow the test spec. + */ + { + Child *child = dut.Get().FindChild(sed1.Get().GetExtAddress(), Child::kInStateValid); + VerifyOrQuit(child != nullptr); + child->SetVersion(kThreadVersion1p1); + } + + /** + * - SED_1 – enable polling via 802.15.4 MAC Data Requests. + * - SED_2 – disable polling via 802.15.4 MAC Data Requests. + * - SED_3 – enable polling via 802.15.4 MAC Data Requests. + */ + SuccessOrQuit(sed1.Get().SetExternalPollPeriod(kPollPeriod)); + SuccessOrQuit(sed2.Get().SetExternalPollPeriod(kLongPollPeriod)); + SuccessOrQuit(sed3.Get().SetExternalPollPeriod(kPollPeriod)); + + /** + * Step 2: SED_2 + * - Harness instructs the device to send an empty MAC Data frame to the DUT (Leader). + * - Pass Criteria: DUT MUST send an acknowledgment with Frame Pending bit set to 0. + */ + Log("Step 2: SED_2 sends empty MAC Data frame to Leader"); + SuccessOrQuit(sed2.Get().SendEmptyMessage()); + nexus.AdvanceTime(kShortWaitTime); + + /** + * Step 3: Router_1 + * - Harness instructs the device to send an ICMPv6 Echo Request to SED_2. + * - Pass Criteria: N/A. + */ + Log("Step 3: Router_1 sends Echo Request to SED_2"); + router1.SendEchoRequest(sed2.Get().GetMeshLocalEid(), kEchoIdentifier, kEchoPayloadSize); + nexus.AdvanceTime(kShortWaitTime); + + /** + * Step 4: SED_2 + * - Harness instructs the device to send an empty MAC Data frame to the DUT (Leader). + * - Pass Criteria: DUT MUST send an acknowledgment with Frame Pending bit set to 1. + */ + Log("Step 4: SED_2 sends empty MAC Data frame to Leader"); + SuccessOrQuit(sed2.Get().SendEmptyMessage()); + nexus.AdvanceTime(kShortWaitTime); + + /** + * Step 5: SED_2 + * - Harness instructs the device to send an 802.15.4 Data Request message to the DUT (Leader). + * - Pass Criteria: N/A. + */ + Log("Step 5: SED_2 sends Data Request to Leader"); + SuccessOrQuit(sed2.Get().SendDataPoll()); + nexus.AdvanceTime(kShortWaitTime); + + /** + * Step 6: DUT + * - DUT sends an acknowledgment with Frame Pending bit set to 1. + * - Pass Criteria: N/A. + */ + Log("Step 6: DUT sends acknowledgment with Frame Pending bit set to 1"); + // Handled by Step 5 execution and verification. + + /** + * Step 7: DUT + * - Forward the ICMPv6 Echo Request to SED_2. + * - Pass Criteria: N/A. + */ + Log("Step 7: DUT forwards Echo Request to SED_2"); + // Handled by Step 5 execution and verification. + + /** + * Step 8: SED_2 + * - Acknowledges the ICMPv6 Echo Request frame. + * - Pass Criteria: N/A. + */ + Log("Step 8: SED_2 acknowledges Echo Request"); + // Handled by Step 5 execution and verification. + + /** + * Step 9: SED_2 + * - Automatically replies with an ICMPv6 Echo Reply to Router_1. + * - Pass Criteria: N/A. + */ + Log("Step 9: SED_2 sends Echo Reply to Router_1"); + nexus.AdvanceTime(kEchoReplyWaitTime); + + /** + * Step 10: DUT + * - DUT MUST send an acknowledgment with Frame Pending bit set to 0 to SED_2. + * - Pass Criteria: N/A. + */ + Log("Step 10: DUT sends acknowledgment with Frame Pending bit set to 0 to SED_2"); + // Handled by Step 9 execution and verification. + + /** + * Step 11: Router_1 + * - Harness instructs the device to send an ICMPv6 Echo Request to SED_3. + * - Pass Criteria: N/A. + */ + Log("Step 11: Router_1 sends Echo Request to SED_3"); + router1.SendEchoRequest(sed3.Get().GetMeshLocalEid(), kEchoIdentifier, kEchoPayloadSize); + nexus.AdvanceTime(kPollWaitTime); // Wait for poll + + /** + * Step 12: SED_3 + * - Automatically replies with an ICMPv6 Echo Reply to Router_1. + * - Pass Criteria: Router_1 MUST receive the Echo Reply. + */ + Log("Step 12: SED_3 sends Echo Reply to Router_1"); + nexus.AdvanceTime(kPollWaitTime); + + /** + * Step 13: Router_1 + * - Harness instructs the device to send an ICMPv6 Echo Request to SED_1. + * - Pass Criteria: N/A. + */ + Log("Step 13: Router_1 sends Echo Request to SED_1"); + router1.SendEchoRequest(sed1.Get().GetMeshLocalEid(), kEchoIdentifier, kEchoPayloadSize); + nexus.AdvanceTime(kPollWaitTime); // Wait for poll + + /** + * Step 14: SED_1 + * - Automatically replies with an ICMPv6 Echo Reply to Router_1. + * - Pass Criteria: Router_1 MUST receive the Echo Reply. + */ + Log("Step 14: SED_1 sends Echo Reply to Router_1"); + nexus.AdvanceTime(kPollWaitTime); + + nexus.SaveTestInfo("test_1_2_LP_5_2_1.json"); +} + +} // namespace Nexus +} // namespace ot + +int main(void) +{ + ot::Nexus::Test1_2_LP_5_2_1(); + printf("All tests passed\n"); + return 0; +} diff --git a/tests/nexus/verify_1_2_LP_5_2_1.py b/tests/nexus/verify_1_2_LP_5_2_1.py new file mode 100644 index 000000000..47f888843 --- /dev/null +++ b/tests/nexus/verify_1_2_LP_5_2_1.py @@ -0,0 +1,226 @@ +#!/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 + + +def verify(pv): + # 5.2.1 Enhanced Frame Pending with Thread V1.2 End Device & V1.1 End Device + # + # 5.2.1.1 Topology + # - SED_1: is Thread 1.1 SED. + # - SED_2: is Thread 1.2 SED with Enhanced Frame Pending (EFP) support; polling via 802.15.4 MAC Data Requests is + # disabled. + # - SED_3: is Thread 1.2 SED with Enhanced Frame Pending (EFP) support; polling via 802.15.4 MAC Data Requests is + # enabled. + # - Router_1: is a Thread Router. + # - DUT: is Thread Leader. + # + # 5.2.1.2 Purpose & Description + # This test case verifies that the DUT correctly manages the Frame Pending bit in acknowledgments to MAC Data and + # Data Request frames for Thread V1.2 and V1.1 sleepy end devices. + # + # Spec Reference | V1.2 Section + # ------------------------|-------------- + # Enhanced Frame Pending | 3.2.6.2 + + FRAME_PENDING_SET = 1 + FRAME_PENDING_CLEAR = 0 + + pkts = pv.pkts + pv.summary.show() + + LEADER = pv.vars['LEADER'] + ROUTER_1 = pv.vars['ROUTER_1'] + SED_1 = pv.vars['SED_1'] + SED_2 = pv.vars['SED_2'] + SED_3 = pv.vars['SED_3'] + + LEADER_RLOC16 = pv.vars['LEADER_RLOC16'] + ROUTER_1_RLOC16 = pv.vars['ROUTER_1_RLOC16'] + SED_1_RLOC16 = pv.vars['SED_1_RLOC16'] + SED_2_RLOC16 = pv.vars['SED_2_RLOC16'] + SED_3_RLOC16 = pv.vars['SED_3_RLOC16'] + + def is_from(p, addr, rloc16): + return p.wpan.src64 == addr or p.wpan.src16 == rloc16 + + def is_to(p, addr, rloc16): + return p.wpan.dst16 == rloc16 or p.wpan.dst64 == addr + + def _verify_ping_echo_for_sed(sed, sed_rloc16): + """Helper to verify ping echo from ROUTER_1 to a SED.""" + _echo_req = pkts.filter_ping_request().\ + filter(lambda p: is_from(p, ROUTER_1, ROUTER_1_RLOC16)).\ + filter(lambda p: is_to(p, LEADER, LEADER_RLOC16)).\ + must_next() + + pkts.filter_ping_reply(identifier=_echo_req.icmpv6.echo.identifier).\ + filter(lambda p: is_from(p, sed, sed_rloc16)).\ + filter(lambda p: is_to(p, LEADER, LEADER_RLOC16)).\ + must_next() + pkts.filter_ping_reply(identifier=_echo_req.icmpv6.echo.identifier).\ + filter(lambda p: is_from(p, LEADER, LEADER_RLOC16)).\ + filter(lambda p: is_to(p, ROUTER_1, ROUTER_1_RLOC16)).\ + must_next() + + # Step 1: All Devices + # - Topology formation. + print("Step 1: Topology formation") + + # Step 2: SED_2 + # - Harness instructs the device to send an empty MAC Data frame to the DUT (Leader). + # - Pass Criteria: DUT MUST send an acknowledgment with Frame Pending bit set to 0. + print("Step 2: SED_2 sends empty MAC Data frame to Leader") + _pkt = pkts.filter_wpan_data().\ + filter(lambda p: is_from(p, SED_2, SED_2_RLOC16)).\ + filter(lambda p: is_to(p, LEADER, LEADER_RLOC16)).\ + filter(lambda p: 'ipv6' not in p.layer_names).\ + must_next() + + pkts.filter_wpan_ack().\ + filter_wpan_seq(_pkt.wpan.seq_no).\ + must_next().\ + must_verify(lambda p: p.wpan.pending == FRAME_PENDING_CLEAR) + + # Step 3: Router_1 + # - Harness instructs the device to send an ICMPv6 Echo Request to SED_2. + # - Pass Criteria: N/A. + print("Step 3: Router_1 sends Echo Request to SED_2") + _echo_req = pkts.filter_ping_request().\ + filter(lambda p: is_from(p, ROUTER_1, ROUTER_1_RLOC16)).\ + filter(lambda p: is_to(p, LEADER, LEADER_RLOC16)).\ + must_next() + + # Step 4: SED_2 + # - Harness instructs the device to send an empty MAC Data frame to the DUT (Leader). + # - Pass Criteria: DUT MUST send an acknowledgment with Frame Pending bit set to 1. + print("Step 4: SED_2 sends empty MAC Data frame to Leader") + _pkt = pkts.filter_wpan_data().\ + filter(lambda p: is_from(p, SED_2, SED_2_RLOC16)).\ + filter(lambda p: is_to(p, LEADER, LEADER_RLOC16)).\ + filter(lambda p: 'ipv6' not in p.layer_names).\ + must_next() + + pkts.filter_wpan_ack().\ + filter_wpan_seq(_pkt.wpan.seq_no).\ + must_next().\ + must_verify(lambda p: p.wpan.pending == FRAME_PENDING_SET) + + # Step 5: SED_2 + # - Harness instructs the device to send an 802.15.4 Data Request message to the DUT (Leader). + # - Pass Criteria: N/A. + print("Step 5: SED_2 sends Data Request to Leader") + _pkt = pkts.filter_wpan_cmd(consts.WPAN_DATA_REQUEST).\ + filter(lambda p: is_from(p, SED_2, SED_2_RLOC16)).\ + filter(lambda p: is_to(p, LEADER, LEADER_RLOC16)).\ + must_next() + + # Step 6: DUT + # - DUT sends an acknowledgment with Frame Pending bit set to 1. + # - Pass Criteria: N/A. + print("Step 6: DUT sends acknowledgment with Frame Pending bit set to 1") + pkts.filter_wpan_ack().\ + filter_wpan_seq(_pkt.wpan.seq_no).\ + must_next().\ + must_verify(lambda p: p.wpan.pending == FRAME_PENDING_SET) + + # Step 7: DUT + # Step 7: DUT forwards Echo Request to SED_2 + # - Pass Criteria: N/A. + print("Step 7: DUT forwards Echo Request to SED_2") + _pkt = pkts.filter_ping_request(identifier=_echo_req.icmpv6.echo.identifier).\ + filter(lambda p: is_from(p, LEADER, LEADER_RLOC16)).\ + filter(lambda p: is_to(p, SED_2, SED_2_RLOC16)).\ + must_next() + + # Step 8: SED_2 + # - Acknowledges the ICMPv6 Echo Request frame. + # - Pass Criteria: SED_2 MUST send 802.15.4 ACK to the DUT. + print("Step 8: SED_2 acknowledges Echo Request") + pkts.filter_wpan_ack().\ + filter_wpan_seq(_pkt.wpan.seq_no).\ + must_next() + + # Step 9: SED_2 + # Step 9: SED_2 sends Echo Reply to Router_1 + # - Pass Criteria: Router_1 MUST receive the ICMPv6 Echo Reply. + print("Step 9: SED_2 sends Echo Reply to Router_1") + _reply1 = pkts.filter_ping_reply(identifier=_echo_req.icmpv6.echo.identifier).\ + filter(lambda p: is_from(p, SED_2, SED_2_RLOC16)).\ + filter(lambda p: is_to(p, LEADER, LEADER_RLOC16)).\ + must_next() + + # Step 10: DUT sends acknowledgment with Frame Pending bit set to 0 to SED_2 + # - Pass Criteria: The DUT MUST transmit a 802.15.4 ACK to SED_2 with the Frame Pending bit set to 0. + print("Step 10: DUT sends acknowledgment with Frame Pending bit set to 0 to SED_2") + pkts.filter_wpan_ack().\ + filter_wpan_seq(_reply1.wpan.seq_no).\ + must_next().\ + must_verify(lambda p: p.wpan.pending == FRAME_PENDING_CLEAR) + + # Continue Step 9 verification: verify the forwarded Echo Reply to Router_1 + pkts.filter_ping_reply(identifier=_echo_req.icmpv6.echo.identifier).\ + filter(lambda p: is_from(p, LEADER, LEADER_RLOC16)).\ + filter(lambda p: is_to(p, ROUTER_1, ROUTER_1_RLOC16)).\ + must_next() + + # Step 11: Router_1 + # - Harness instructs the device to send an ICMPv6 Echo Request to SED_3. + # - Pass Criteria: N/A. + print("Step 11: Router_1 sends Echo Request to SED_3") + + # Step 12: SED_3 + # - Automatically replies with an ICMPv6 Echo Reply to Router_1. + # - Pass Criteria: Router_1 MUST receive the Echo Reply. + print("Step 12: SED_3 sends Echo Reply to Router_1") + _verify_ping_echo_for_sed(SED_3, SED_3_RLOC16) + + # Step 13: Router_1 + # - Harness instructs the device to send an ICMPv6 Echo Request to SED_1. + # - Pass Criteria: N/A. + print("Step 13: Router_1 sends Echo Request to SED_1") + + # Step 14: SED_1 + # - Automatically replies with an ICMPv6 Echo Reply to Router_1. + # - Pass Criteria: Router_1 MUST receive the Echo Reply. + print("Step 14: SED_1 sends Echo Reply to Router_1") + _verify_ping_echo_for_sed(SED_1, SED_1_RLOC16) + + +if __name__ == '__main__': + verify_utils.run_main(verify)