mirror of
https://github.com/espressif/openthread.git
synced 2026-09-28 11:57:36 +00:00
Added `Core::AllowLinkBetween()` and `Core::UnallowLinkBetween()` helper methods to the Nexus test platform. These methods simplify establishing bidirectional links between nodes in simulation tests by handling the reciprocal `AllowList()` calls in a single step. Updated various Nexus test cases to utilize these new helpers, replacing manual bidirectional `AllowList()` calls. This change reduces verbosity and ensures consistency in how links are established in the test topology.
388 lines
12 KiB
C++
388 lines
12 KiB
C++
/*
|
||
* 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 = 10 * 1000;
|
||
|
||
/**
|
||
* Time to advance for a node to join as 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 for MLR registration, in milliseconds.
|
||
*/
|
||
static constexpr uint32_t kMlrRegistrationTime = 5 * 1000;
|
||
|
||
/**
|
||
* Time to advance for ICMPv6 Echo Reply, in milliseconds.
|
||
*/
|
||
static constexpr uint32_t kEchoReplyWaitTime = 5000;
|
||
|
||
/**
|
||
* Poll period for SED in milliseconds.
|
||
*/
|
||
static constexpr uint32_t kSedPollPeriod = 1000;
|
||
|
||
/**
|
||
* Time to allow for a Child Update Request, in milliseconds.
|
||
*/
|
||
static constexpr uint32_t kChildUpdateRequestTimeMs = 1000;
|
||
|
||
/**
|
||
* ICMPv6 Echo Request payload size.
|
||
*/
|
||
static constexpr uint16_t kEchoPayloadSize = 10;
|
||
|
||
/**
|
||
* ICMPv6 Echo Request identifier.
|
||
*/
|
||
static constexpr uint16_t kEchoIdentifier = 0x1234;
|
||
|
||
/**
|
||
* Multicast address MA2.
|
||
*/
|
||
static const char kMA2[] = "ff05::2";
|
||
|
||
/**
|
||
* Multicast address MA3.
|
||
*/
|
||
static const char kMA3[] = "ff05::3";
|
||
|
||
/**
|
||
* Multicast address MA5.
|
||
*/
|
||
static const char kMA5[] = "ff05::5";
|
||
|
||
void TestMatnTc19(void)
|
||
{
|
||
/**
|
||
* 5.10.15 MATN-TC-19: Multicast registration by MTD
|
||
*
|
||
* Purpose:
|
||
* The purpose of this test case is to verify that an MTD can register a multicast address through a Parent Thread
|
||
* Router.
|
||
*
|
||
* Spec Reference | V1.2 Section
|
||
* ---------------|-------------
|
||
* MATN-TC-19 | 5.10.15
|
||
*/
|
||
|
||
Core nexus;
|
||
Node &br1 = nexus.CreateNode();
|
||
Node &br2 = nexus.CreateNode();
|
||
Node &router = nexus.CreateNode();
|
||
Node &mtd = nexus.CreateNode();
|
||
Node &host = nexus.CreateNode();
|
||
Ip6::Address ma2;
|
||
Ip6::Address ma3;
|
||
Ip6::Address ma5;
|
||
const Ip6::Address *hostUla;
|
||
|
||
br1.SetName("BR_1");
|
||
br2.SetName("BR_2");
|
||
router.SetName("Router");
|
||
mtd.SetName("MTD");
|
||
host.SetName("Host");
|
||
|
||
SuccessOrQuit(ma2.FromString(kMA2));
|
||
SuccessOrQuit(ma3.FromString(kMA3));
|
||
SuccessOrQuit(ma5.FromString(kMA5));
|
||
|
||
nexus.AdvanceTime(0);
|
||
|
||
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
|
||
|
||
Log("Step 0: Topology formation – BR_1, BR_2, Router, MTD");
|
||
|
||
/**
|
||
* Step 0
|
||
* - Device: N/A
|
||
* - Description: Topology formation – BR_1, BR_2, Router, MTD
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
|
||
AllowLinkBetween(br1, br2);
|
||
AllowLinkBetween(br1, router);
|
||
AllowLinkBetween(br2, router);
|
||
AllowLinkBetween(router, mtd);
|
||
|
||
br1.Form();
|
||
nexus.AdvanceTime(kFormNetworkTime);
|
||
VerifyOrQuit(br1.Get<Mle::Mle>().IsLeader());
|
||
|
||
br1.Get<BorderRouter::InfraIf>().Init(1, true);
|
||
br1.Get<BorderRouter::RoutingManager>().Init();
|
||
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||
br1.Get<BackboneRouter::Local>().SetEnabled(true);
|
||
|
||
br2.Join(br1, Node::kAsFtd);
|
||
router.Join(br1, Node::kAsFtd);
|
||
nexus.AdvanceTime(kAttachToRouterTime);
|
||
|
||
VerifyOrQuit(br2.Get<Mle::Mle>().IsRouter());
|
||
VerifyOrQuit(router.Get<Mle::Mle>().IsRouter());
|
||
|
||
br2.Get<BorderRouter::InfraIf>().Init(1, true);
|
||
br2.Get<BorderRouter::RoutingManager>().Init();
|
||
SuccessOrQuit(br2.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||
br2.Get<BackboneRouter::Local>().SetEnabled(true);
|
||
|
||
SuccessOrQuit(mtd.Get<DataPollSender>().SetExternalPollPeriod(kSedPollPeriod));
|
||
mtd.Join(router, Node::kAsSed);
|
||
nexus.AdvanceTime(kAttachAsChildTime);
|
||
VerifyOrQuit(mtd.Get<Mle::Mle>().IsChild());
|
||
|
||
nexus.AdvanceTime(kStabilizationTime);
|
||
|
||
VerifyOrQuit(br1.Get<BackboneRouter::Local>().IsPrimary());
|
||
VerifyOrQuit(router.Get<BackboneRouter::Leader>().HasPrimary());
|
||
|
||
hostUla = &host.mInfraIf.FindMatchingAddress("fd00::/8");
|
||
|
||
nexus.AddTestVar("TEST_MA2", kMA2);
|
||
nexus.AddTestVar("TEST_MA3", kMA3);
|
||
nexus.AddTestVar("TEST_MA5", kMA5);
|
||
nexus.AddTestVar("HOST_BACKBONE_ULA", hostUla->ToString().AsCString());
|
||
|
||
Log("Step 1a: MTD Registers addresses MA2 & MA5 with its parent.");
|
||
|
||
/**
|
||
* Step 1a
|
||
* - Device: MTD
|
||
* - Description: Registers addresses MA2 & MA5 with its parent. (MA5 is optional for MEDs)
|
||
* - Pass Criteria:
|
||
* - For DUT = MTD:
|
||
* - The DUT MUST unicast an MLE Child Update Request command to Router, where the payload contains (amongst other
|
||
* fields):
|
||
* - Address Registration TLV: MA2
|
||
* - MA5 (Optional for MED)
|
||
*/
|
||
SuccessOrQuit(mtd.Get<Ip6::Netif>().SubscribeExternalMulticast(ma2));
|
||
SuccessOrQuit(mtd.Get<Ip6::Netif>().SubscribeExternalMulticast(ma5));
|
||
nexus.AdvanceTime(kChildUpdateRequestTimeMs);
|
||
|
||
Log("Step 1b: Router Automatically responds to the registration request.");
|
||
|
||
/**
|
||
* Step 1b
|
||
* - Device: Router
|
||
* - Description: Automatically responds to the registration request.
|
||
* - Pass Criteria:
|
||
* - For DUT = Router:
|
||
* - The DUT MUST unicast an MLE Child Update Response command to MTD, where the payload contains (amongst other
|
||
* fields):
|
||
* - Address Registration TLV: MA2
|
||
* - MA5
|
||
*/
|
||
|
||
Log("Step 1c: Router Automatically registers multicast address, MA2 at BR_1");
|
||
|
||
/**
|
||
* Step 1c
|
||
* - Device: Router
|
||
* - Description: Automatically registers multicast address, MA2 at BR_1
|
||
* - Pass Criteria:
|
||
* - For DUT = Router:
|
||
* - The DUT MUST unicast an MLR.req CoAP request to BR_1 as follows: coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr
|
||
* - Where the payload contains:
|
||
* - IPv6 Addresses TLV: MA2
|
||
*/
|
||
nexus.AdvanceTime(kMlrRegistrationTime);
|
||
|
||
Log("Step 2: MTD Registers addresses MA2 and MA3 with its parent.");
|
||
|
||
/**
|
||
* Step 2
|
||
* - Device: MTD
|
||
* - Description: Registers addresses MA2 and MA3 with its parent.
|
||
* - Pass Criteria:
|
||
* - For DUT = MTD:
|
||
* - The DUT MUST unicast an MLE Child Update Request command to Router_1, where the payload contains (amongst
|
||
* other fields):
|
||
* - Address Registration TLV: MA2 and MA3.
|
||
*/
|
||
SuccessOrQuit(mtd.Get<Ip6::Netif>().UnsubscribeExternalMulticast(ma5));
|
||
SuccessOrQuit(mtd.Get<Ip6::Netif>().SubscribeExternalMulticast(ma3));
|
||
nexus.AdvanceTime(kChildUpdateRequestTimeMs);
|
||
|
||
Log("Step 3: Router Automatically responds to the registration request.");
|
||
|
||
/**
|
||
* Step 3
|
||
* - Device: Router
|
||
* - Description: Automatically responds to the registration request.
|
||
* - Pass Criteria:
|
||
* - For DUT = Router:
|
||
* - The DUT MUST unicast an MLE Child Update Response command to MTD, where the payload contains (amongst other
|
||
* fields):
|
||
* - Address Registration TLV: MA2 and MA3.
|
||
*/
|
||
|
||
Log("Step 4: Router Wait at most PARENT_AGGREGATE_DELAY.");
|
||
|
||
/**
|
||
* Step 4
|
||
* - Device: Router
|
||
* - Description: Wait at most PARENT_AGGREGATE_DELAY.
|
||
* - Pass Criteria:
|
||
* - The next message (below) is sent not later than PARENT_AGGREGATE_DELAY seconds since step 3.
|
||
*/
|
||
|
||
Log("Step 5: Router Automatically registers multicast addresses, MA2 and MA3 at BR_1.");
|
||
|
||
/**
|
||
* Step 5
|
||
* - Device: Router
|
||
* - Description: Automatically registers multicast addresses, MA2 and MA3 at BR_1. Unicasts an MLR.req CoAP request
|
||
* to BR_1 as follows: coap://[<BR_1 RLOC or PBBR ALOC>]:MM/n/mr Where the payload contains: IPv6 Addresses TLV:
|
||
* MA3, MA2 (optional).
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
nexus.AdvanceTime(kMlrRegistrationTime);
|
||
|
||
Log("Step 6: BR_1 Automatically responds to the registration request.");
|
||
|
||
/**
|
||
* Step 6
|
||
* - Device: BR_1
|
||
* - Description: Automatically responds to the registration request. Unicasts an MLR.rsp CoAP response to Router_1
|
||
* as follows: 2.04 changed Where the payload contains: Status TLV: ST_MLR_SUCCESS.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
|
||
Log("Step 7: Host ICMPv6 Echo (ping) Request packet to multicast address, MA3, on the backbone link.");
|
||
|
||
/**
|
||
* Step 7
|
||
* - Device: Host
|
||
* - Description: Harness instructs the device to send ICMPv6 Echo (ping) Request packet to multicast address, MA3,
|
||
* on the backbone link.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
host.mInfraIf.SendEchoRequest(*hostUla, ma3, kEchoIdentifier, kEchoPayloadSize);
|
||
nexus.AdvanceTime(0);
|
||
|
||
Log("Step 8: BR_1 Automatically forwards the ping request packet to its Thread Network.");
|
||
|
||
/**
|
||
* Step 8
|
||
* - Device: BR_1
|
||
* - Description: Automatically forwards the ping request packet to its Thread Network encapsulated in an MPL
|
||
* packet.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
|
||
Log("Step 8a: Router Receives the multicast ping request packet.");
|
||
|
||
/**
|
||
* Step 8a
|
||
* - Device: Router
|
||
* - Description: Receives the multicast ping request packet and if MTD is a SED then it automatically pends it for
|
||
* delivery to MTD. If MTD is MED, it automatically forwards the packet as defined in step 10.
|
||
* - Pass Criteria:
|
||
* - None.
|
||
*/
|
||
|
||
Log("Step 9: MTD polls for the pending ping request packet.");
|
||
|
||
/**
|
||
* Step 9
|
||
* - Device: MTD
|
||
* - Description: If MTD is a SED, it wakes up and/or polls for the pending ping request packet. If MTD is a MED,
|
||
* this test step is skipped.
|
||
* - Pass Criteria:
|
||
* - For DUT = MTD (SED):
|
||
* - The DUT MUST send a MAC poll request to Router_1.
|
||
*/
|
||
nexus.AdvanceTime(kEchoReplyWaitTime);
|
||
|
||
Log("Step 10: Router Automatically forwards the ping request packet to MTD.");
|
||
|
||
/**
|
||
* Step 10
|
||
* - Device: Router
|
||
* - Description: Automatically forwards the ping request packet to MTD.
|
||
* - Pass Criteria:
|
||
* - For DUT = Router:
|
||
* - The DUT MUST forward the ICMPv6 Echo (ping) Request packet with multicast address, MA3, to MTD using
|
||
* 802.15.4 unicast.
|
||
* - The ping request packet MUST NOT be encapsulated in an MPL packet.
|
||
*/
|
||
|
||
Log("Step 11: MTD sends a unicast ICMPv6 Echo Response packet back to Host.");
|
||
|
||
/**
|
||
* Step 11
|
||
* - Device: MTD
|
||
* - Description: Receives the multicast ping request packet and sends a unicast ICMPv6 Echo (ping) Response packet
|
||
* back to Host.
|
||
* - Pass Criteria:
|
||
* - For DUT = MTD:
|
||
* - The DUT MUST unicast a ICMPv6 Echo (ping) Response packet back to Host.
|
||
*/
|
||
nexus.AdvanceTime(kEchoReplyWaitTime);
|
||
|
||
nexus.SaveTestInfo("test_1_2_MATN_TC_19.json");
|
||
}
|
||
|
||
} /* namespace Nexus */
|
||
} /* namespace ot */
|
||
|
||
int main(void)
|
||
{
|
||
ot::Nexus::TestMatnTc19();
|
||
printf("All tests passed\n");
|
||
return 0;
|
||
}
|