mirror of
https://github.com/espressif/openthread.git
synced 2026-09-28 03:47:38 +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.
940 lines
36 KiB
C++
940 lines
36 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 = 20 * 1000;
|
||
|
||
/**
|
||
* Time to advance for a node to join as a child and upgrade to a router, in milliseconds.
|
||
*/
|
||
static constexpr uint32_t kJoinNetworkTime = 300 * 1000;
|
||
|
||
/**
|
||
* Time to advance for the BR to perform automatic actions (RA, Network Data), in milliseconds.
|
||
*/
|
||
static constexpr uint32_t kBrActionTime = 100 * 1000;
|
||
|
||
/**
|
||
* Longer time to advance for network stabilization and address configuration.
|
||
*/
|
||
static constexpr uint32_t kLongActionTime = 500 * 1000;
|
||
|
||
/**
|
||
* Time to advance for the ping response, in milliseconds.
|
||
*/
|
||
static constexpr uint32_t kPingResponseTime = 100 * 1000;
|
||
|
||
/**
|
||
* Default Hop Limit for Echo Request.
|
||
*/
|
||
static constexpr uint8_t kDefaultHopLimit = 64;
|
||
|
||
/**
|
||
* Infrastructure interface index.
|
||
*/
|
||
static constexpr uint32_t kInfraIfIndex = 1;
|
||
|
||
/**
|
||
* Echo Request identifier.
|
||
*/
|
||
static constexpr uint16_t kEchoIdentifier = 0x1234;
|
||
|
||
/**
|
||
* Echo Request payload size.
|
||
*/
|
||
static constexpr uint16_t kEchoPayloadSize = 10;
|
||
|
||
/**
|
||
* Max number of seconds to wait for a condition.
|
||
*/
|
||
static constexpr uint32_t kMaxWaitTime = 120;
|
||
|
||
/**
|
||
* OMR prefix 3 string (numerically very low to be "winning").
|
||
*/
|
||
static constexpr char kOmr3PrefixStr[] = "fd00:3::/64";
|
||
|
||
/**
|
||
* OMR prefix 4 string (numerically very high to be "losing" if same preference).
|
||
*/
|
||
static constexpr char kOmr4PrefixStr[] = "fdff:4::/64";
|
||
|
||
/**
|
||
* Infrastructure GUA address string for Eth_1.
|
||
*/
|
||
static constexpr char kEth1GuaAddrStr[] = "2001:db8:1::1";
|
||
|
||
/**
|
||
* Infrastructure GUA prefix string.
|
||
*/
|
||
static constexpr char kGua1PrefixStr[] = "2001:db8:1::/64";
|
||
|
||
static void DumpNetworkData(Node &aNode)
|
||
{
|
||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||
NetworkData::OnMeshPrefixConfig prefixConfig;
|
||
NetworkData::ExternalRouteConfig routeConfig;
|
||
|
||
Log("Network Data for %s (Version: %d):", aNode.GetName(),
|
||
aNode.Get<NetworkData::Leader>().GetVersion(NetworkData::kFullSet));
|
||
while (aNode.Get<NetworkData::Leader>().GetNext(iterator, prefixConfig) == kErrorNone)
|
||
{
|
||
Log(" Prefix: %s (pref:%d, preferred:%s)", prefixConfig.GetPrefix().ToString().AsCString(),
|
||
prefixConfig.mPreference, ToYesNo(prefixConfig.mPreferred));
|
||
}
|
||
|
||
iterator = NetworkData::kIteratorInit;
|
||
while (aNode.Get<NetworkData::Leader>().GetNext(iterator, routeConfig) == kErrorNone)
|
||
{
|
||
Log(" Route: %s (pref:%d)", routeConfig.GetPrefix().ToString().AsCString(), routeConfig.mPreference);
|
||
}
|
||
}
|
||
|
||
static bool HasNetDataPrefix(Node &aNode, const Ip6::Prefix &aPrefix)
|
||
{
|
||
return aNode.Get<NetworkData::Leader>().ContainsOmrPrefix(aPrefix);
|
||
}
|
||
|
||
static bool HasNetDataRoute(Node &aNode, const char *aPrefixStr)
|
||
{
|
||
bool hasRoute = false;
|
||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||
NetworkData::ExternalRouteConfig routeConfig;
|
||
Ip6::Prefix target;
|
||
|
||
SuccessOrQuit(target.FromString(aPrefixStr));
|
||
|
||
while (aNode.Get<NetworkData::Leader>().GetNext(iterator, routeConfig) == kErrorNone)
|
||
{
|
||
if (AsCoreType(&routeConfig.mPrefix) == target)
|
||
{
|
||
hasRoute = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
return hasRoute;
|
||
}
|
||
|
||
static void WaitForPrefix(Core &aNexus, Node &aNode, const Ip6::Prefix &aPrefix, bool aPresent)
|
||
{
|
||
for (uint32_t i = 0; i < kMaxWaitTime; i++)
|
||
{
|
||
if (HasNetDataPrefix(aNode, aPrefix) == aPresent)
|
||
{
|
||
break;
|
||
}
|
||
aNexus.AdvanceTime(1000);
|
||
}
|
||
VerifyOrQuit(HasNetDataPrefix(aNode, aPrefix) == aPresent);
|
||
}
|
||
|
||
static void WaitForRoute(Core &aNexus, Node &aNode, const char *aPrefixStr, bool aPresent)
|
||
{
|
||
for (uint32_t i = 0; i < kMaxWaitTime; i++)
|
||
{
|
||
if (HasNetDataRoute(aNode, aPrefixStr) == aPresent)
|
||
{
|
||
break;
|
||
}
|
||
aNexus.AdvanceTime(1000);
|
||
}
|
||
VerifyOrQuit(HasNetDataRoute(aNode, aPrefixStr) == aPresent);
|
||
}
|
||
|
||
static void PublishOmrPrefix(Node &aNode,
|
||
const Ip6::Prefix &aPrefix,
|
||
NetworkData::RoutePreference aPreference,
|
||
bool aIsPreferred)
|
||
{
|
||
NetworkData::OnMeshPrefixConfig config;
|
||
config.Clear();
|
||
config.GetPrefix() = aPrefix;
|
||
config.mPreference = aPreference;
|
||
config.mSlaac = true;
|
||
config.mOnMesh = true;
|
||
config.mStable = true;
|
||
config.mPreferred = aIsPreferred;
|
||
SuccessOrQuit(aNode.Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||
}
|
||
|
||
void Test_1_3_DBR_TC_8(void)
|
||
{
|
||
/**
|
||
* 1.8. [1.3] [CERT] Reachability - Multiple BRs - Single Thread / Single IPv6 Infrastructure - OMR prefix selection
|
||
*
|
||
* 1.8.1. Purpose
|
||
* - To test the following:
|
||
* - Maintain bi-directional reachability between Thread devices and infrastructure devices during prefix changes
|
||
* - DUT BR should observe proper OMR prefix selection when testbed-BR advertises various other prefixes:
|
||
* - Testbed advertises a winning prefix with equal preference, DUT should withdraw or deprecate its OMR prefix
|
||
* - Testbed advertises a numerically higher, non-winning prefix with equal preference, DUT should not change
|
||
* behavior.
|
||
* - Testbed advertises a numerically higher prefix with higher preference, i.e. winning OMR prefix, DUT should
|
||
* withdraw its OMR prefix.
|
||
* - Testbed withdraws winning OMR prefix, DUT should advertise its prefix with 'Low' preference again
|
||
* - Testbed OMR prefix becomes deprecated, DUT should advertise its prefix with 'Low' preference again
|
||
*
|
||
* 1.8.2. Topology
|
||
* - Eth_1 - Adjacent Infrastructure Link Reference Device
|
||
* - BR_1 (DUT) - Border Router
|
||
* - BR_2 - Border Router Reference Device and Leader
|
||
* - ED_1 - Thread Reference Device (End Device) attached to BR_1
|
||
*
|
||
* Spec Reference | V1.1 Section | V1.3.0 Section
|
||
* -----------------|--------------|---------------
|
||
* Reachability | N/A | 1.3
|
||
*/
|
||
|
||
Core nexus;
|
||
|
||
Node ð1 = nexus.CreateNode();
|
||
Node &br1 = nexus.CreateNode();
|
||
Node &br2 = nexus.CreateNode();
|
||
Node &ed1 = nexus.CreateNode();
|
||
|
||
eth1.SetName("Eth_1");
|
||
br1.SetName("BR_1");
|
||
br2.SetName("BR_2");
|
||
ed1.SetName("ED_1");
|
||
|
||
nexus.AdvanceTime(0);
|
||
|
||
SuccessOrQuit(Instance::SetGlobalLogLevel(kLogLevelNote));
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 0
|
||
* - Device: Eth_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness configures Ethernet link with an on-link IPv6 GUA prefix GUA_1. Eth_1 is configured to multicast ND
|
||
* RAs.
|
||
* - Automatically configures a global address “Eth_1 GUA”.
|
||
* - Pass Criteria
|
||
* - N/A
|
||
*/
|
||
Log("Step 0: Eth_1 configured with GUA_1.");
|
||
|
||
Ip6::Address eth1Gua;
|
||
SuccessOrQuit(eth1Gua.FromString(kEth1GuaAddrStr));
|
||
eth1.mInfraIf.AddAddress(eth1Gua);
|
||
|
||
Ip6::Prefix gua1;
|
||
SuccessOrQuit(gua1.FromString(kGua1PrefixStr));
|
||
eth1.mInfraIf.StartRouterAdvertisement(gua1);
|
||
|
||
nexus.AddTestVar("ETH_1_GUA_ADDR", kEth1GuaAddrStr);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 1
|
||
* - Device: Eth_1, BR_2, ED_1, ED_2
|
||
* - Description (DBR-1.8):
|
||
* - Enable; BR_2 automatically configures an OMR prefix for the mesh, OMR_1. Harness records the value of OMR_1
|
||
* and saves it for verification use.
|
||
* - Note: the OT command ‘br omrprefix’ should provide the prefix from BR_2.
|
||
* - Form topology. Wait for BR_2 to:
|
||
* - Become Leader
|
||
* - Register as border router in Thread Network Data with its OMR prefix OMR_1
|
||
* - Send multicast ND RAs on AIL
|
||
* - Automatically advertise a route to GUA_1 in the Thread Network Data, using a Prefix TLV:
|
||
* - Prefix = ::/0
|
||
* - Domain ID = <self-selected value>
|
||
* - Has Route sub-TLV
|
||
* - Pass Criteria
|
||
* - N/A
|
||
*/
|
||
Log("Step 1: BR_2 becomes Leader and registers OMR_1.");
|
||
|
||
AllowLinkBetween(br1, br2);
|
||
AllowLinkBetween(br1, ed1);
|
||
|
||
br2.Form();
|
||
nexus.AdvanceTime(kFormNetworkTime);
|
||
|
||
br2.Get<BorderRouter::InfraIf>().Init(kInfraIfIndex, true);
|
||
br2.Get<BorderRouter::RoutingManager>().Init();
|
||
SuccessOrQuit(br2.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
WaitForRoute(nexus, br2, "::/0", true);
|
||
|
||
Ip6::Prefix omr1;
|
||
SuccessOrQuit(br2.Get<BorderRouter::RoutingManager>().GetOmrPrefix(omr1));
|
||
nexus.AddTestVar("OMR_1_PREFIX", omr1.ToString().AsCString());
|
||
Log("OMR_1_PREFIX: %s", omr1.ToString().AsCString());
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 2
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8): Enable: switch on.
|
||
* - Pass Criteria
|
||
* - N/A
|
||
*/
|
||
Log("Step 2: Enable BR_1 (DUT).");
|
||
|
||
br1.Join(br2);
|
||
nexus.AdvanceTime(kJoinNetworkTime);
|
||
|
||
br1.Get<BorderRouter::InfraIf>().Init(kInfraIfIndex, true);
|
||
br1.Get<BorderRouter::RoutingManager>().Init();
|
||
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().SetEnabled(true));
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 3
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically registers itself as a border router in the Thread Network Data.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST register a route to GUA_1 in the Thread Network Data as follows:
|
||
* - Prefix TLV: Prefix = ::/0
|
||
* - Domain ID = <same value as that of BR_2 in step 1>
|
||
* - Has Route sub-TLV
|
||
* - R_preference = 00 (medium) or 11 (low)
|
||
* - DUT MUST NOT register an OMR prefix (e.g. OMR_1, or other) in Thread Network Data.
|
||
*/
|
||
Log("Step 3: BR_1 (DUT) registers route to GUA_1.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 4
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically announces the route to OMR_1 on the AIL.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST multicast ND RAs on the infrastructure link:
|
||
* - IPv6 destination MUST be ff02::1
|
||
* - MUST NOT contain a Prefix Information Option (PIO) with a ULA prefix.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_1.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low)
|
||
*/
|
||
Log("Step 4: BR_1 (DUT) announces OMR_1 on AIL.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 5
|
||
* - Device: BR_2
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs device to remove the existing OMR prefix (OMR_1) being advertised and send out new network
|
||
* data without any prefix.
|
||
* - Note: for 1.3.x cert, this could be implemented by 'br disable' or 'netdata unpublish <OMR_1>' on BR_2.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 5: BR_2 removes OMR_1.");
|
||
|
||
SuccessOrQuit(br2.Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
||
WaitForPrefix(nexus, br2, omr1, false);
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 6
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically chooses a new OMR prefix OMR_2 and includes it in the Network Data.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST register a new OMR prefix (OMR_2) in the Thread Network Data using Prefix TLV as follows:
|
||
* - Prefix = OMR_2
|
||
* - Border Router sub-TLV
|
||
* - P_preference = 11 (Low)
|
||
* - P_default = true
|
||
* - P_stable = true
|
||
* - P_on_mesh = true
|
||
* - P_preferred = true
|
||
* - P_slaac = true
|
||
* - P_dhcp = false
|
||
* - P_dp = false
|
||
* - OMR_2 MUST be 64 bits long and start with 0xFD.
|
||
* - OMR_2 MUST differ from OMR_1.
|
||
* - Also MUST contain a Prefix TLV as follows:
|
||
* - Prefix = ::/0
|
||
* - Domain ID <same value as BR_2 Domain ID>
|
||
* - Has Route TLV
|
||
* - R_preference = 00 (medium) or 11 (low)
|
||
* - Note: one possible way to check this is to verify the contents of the SVR_DATA.ntf message sent by DUT to
|
||
* Leader.
|
||
*/
|
||
Log("Step 6: BR_1 (DUT) chooses OMR_2 and registers in Network Data.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
|
||
Ip6::Prefix omr2;
|
||
SuccessOrQuit(br1.Get<BorderRouter::RoutingManager>().GetOmrPrefix(omr2));
|
||
VerifyOrQuit(omr2 != omr1);
|
||
nexus.AddTestVar("OMR_2_PREFIX", omr2.ToString().AsCString());
|
||
Log("OMR_2_PREFIX: %s", omr2.ToString().AsCString());
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 7
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically multicasts ND RAs on Adjacent Infrastructure Link.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST multicast ND RAs on the infrastructure link:
|
||
* - IPv6 destination MUST be ff02::1
|
||
* - MUST NOT contain a Prefix Information Option (PIO) with a ULA prefix.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_2.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low).
|
||
* - MUST NOT contain a Route Information Option (RIO) with OMR_1.
|
||
*/
|
||
Log("Step 7: BR_1 (DUT) multicasts ND RA with OMR_2, no OMR_1.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 8
|
||
* - Device: Eth_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to ED_1 via either one of BR_1 or BR_2.
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_2)
|
||
* - Pass Criteria:
|
||
* - Eth_1 receives an ICMPv6 Echo Reply from ED_1.
|
||
* - IPv6 Source: ED_1 OMR (using prefix OMR_2)
|
||
* - IPv6 Destination: Eth_1 GUA
|
||
*/
|
||
Log("Step 8: Eth_1 pings ED_1 OMR_2.");
|
||
|
||
ed1.Join(br1, Node::kAsFed);
|
||
nexus.AdvanceTime(kJoinNetworkTime);
|
||
const Ip6::Address &ed1Omr2 = ed1.FindMatchingAddress(omr2.ToString().AsCString());
|
||
nexus.AddTestVar("ED_1_OMR_2_ADDR", ed1Omr2.ToString().AsCString());
|
||
|
||
eth1.mInfraIf.SendEchoRequest(eth1Gua, ed1Omr2, kEchoIdentifier, kEchoPayloadSize);
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 9
|
||
* - Device: ED_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to Eth_1.
|
||
* - IPv6 Source: ED_1 OMR address (using prefix OMR_2)
|
||
* - IPv6 Destination: Eth_1 GUA
|
||
* - Pass Criteria:
|
||
* - ED_1 receives an ICMPv6 Echo Reply from Eth_1.
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_2)
|
||
*/
|
||
Log("Step 9: ED_1 OMR_2 pings Eth_1 GUA.");
|
||
|
||
ed1.SendEchoRequest(eth1Gua, kEchoIdentifier, kEchoPayloadSize, kDefaultHopLimit, &ed1Omr2);
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 10
|
||
* - Device: BR_2
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs BR_2 to add an OMR prefix OMR_3 numerically lower than OMR_2, but with same preference
|
||
* "Low".
|
||
* - Note: can use OT command 'netdata publish prefix' for this.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 10: BR_2 adds OMR_3.");
|
||
|
||
Ip6::Prefix omr3;
|
||
SuccessOrQuit(omr3.FromString(kOmr3PrefixStr));
|
||
|
||
PublishOmrPrefix(br2, omr3, NetworkData::kRoutePreferenceLow, true);
|
||
|
||
nexus.AdvanceTime(kLongActionTime);
|
||
|
||
WaitForPrefix(nexus, br2, omr3, true);
|
||
DumpNetworkData(br2);
|
||
|
||
nexus.AddTestVar("OMR_3_PREFIX", kOmr3PrefixStr);
|
||
Log("OMR_3_PREFIX: %s", kOmr3PrefixStr);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 11
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically withdraws its own OMR prefix OMR_2 from the Thread Network Data.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST register new Network Data:
|
||
* - MUST NOT contain any of the OMR prefixes OMR_1, OMR_2, or OMR_3 in a Prefix TLV.
|
||
* - MUST contain a Prefix TLV:
|
||
* - Prefix = ::/0
|
||
* - Domain ID <same value as BR_2 Domain ID>
|
||
* - Has Route TLV
|
||
* - R_preference = 00 (medium) or 11 (low)
|
||
*/
|
||
Log("Step 11: BR_1 (DUT) withdraws OMR_2 from Network Data.");
|
||
|
||
WaitForPrefix(nexus, br2, omr2, false);
|
||
nexus.AdvanceTime(kLongActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 12
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically multicasts ND RAs on Adjacent Infrastructure Link including OMR_2/OMR_3.
|
||
* - Note: the reason that OMR_2 is still included initially, is that OMR_2 has been created by BR_1 originally
|
||
* and as seen by BR_1, it stays in a deprecated state for at most OMR_ADDR_DEPRECATION_TIME
|
||
* - Pass Criteria:
|
||
* - The DUT MUST multicast ND RAs on the infrastructure link:
|
||
* - IPv6 destination MUST be ff02::1
|
||
* - MUST NOT contain a Prefix Information Option (PIO) with a ULA prefix.
|
||
* - MUST NOT contain a Route Information Option (RIO) with OMR_1.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_2.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low)
|
||
* - MUST contain a Route Information Option (RIO) with OMR_3.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low)
|
||
*/
|
||
Log("Step 12: BR_1 (DUT) multicasts ND RA with OMR_2 and OMR_3.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br1);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 13
|
||
* - Device: Eth_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to ED_1 via BR_1 or BR_2.
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_3)
|
||
* - Pass Criteria:
|
||
* - Eth_1 receives an ICMPv6 Echo Reply from ED_1.
|
||
* - IPv6 Source: ED_1 OMR (using prefix OMR_3)
|
||
* - IPv6 Destination: Eth_1 GUA
|
||
*/
|
||
Log("Step 13: Eth_1 pings ED_1 OMR_3.");
|
||
|
||
const Ip6::Address &ed1Omr3 = ed1.FindMatchingAddress(kOmr3PrefixStr);
|
||
nexus.AddTestVar("ED_1_OMR_3_ADDR", ed1Omr3.ToString().AsCString());
|
||
|
||
eth1.mInfraIf.SendEchoRequest(eth1Gua, ed1Omr3, kEchoIdentifier, kEchoPayloadSize);
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 14
|
||
* - Device: ED_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to Eth_1.
|
||
* - IPv6 Source: ED_1 OMR address (using prefix OMR_3)
|
||
* - IPv6 Destination: Eth_1 GUA
|
||
* - Pass Criteria:
|
||
* - ED_1 receives an ICMPv6 Echo Reply from Eth_1.
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_3)
|
||
*/
|
||
Log("Step 14: ED_1 OMR_3 pings Eth_1 GUA.");
|
||
|
||
ed1.SendEchoRequest(eth1Gua, kEchoIdentifier, kEchoPayloadSize, kDefaultHopLimit, &ed1Omr3);
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 15
|
||
* - Device: BR_2
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs device to remove existing OMR prefix (OMR_3) that is being advertised and sends out new
|
||
* network data without the prefix OMR_3.
|
||
* - Note: can use OT command 'netdata unpublish <prefix>' for this.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 15: BR_2 removes OMR_3.");
|
||
|
||
SuccessOrQuit(br2.Get<NetworkData::Publisher>().UnpublishPrefix(omr3));
|
||
WaitForPrefix(nexus, br2, omr3, false);
|
||
|
||
nexus.AdvanceTime(kLongActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 16
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically starts advertising its own OMR prefix OMR_2 again.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST register its OMR prefix OMR_2 in the Thread Network Data. Flags in the Border Router sub-TLV
|
||
* MUST be:
|
||
* - P_preference = 11 (Low)
|
||
* - P_default = true
|
||
* - P_stable = true
|
||
* - P_on_mesh = true
|
||
* - P_preferred = true
|
||
* - P_slaac = true
|
||
* - P_dhcp = false
|
||
* - P_dp = false
|
||
* - OMR_2 MUST be 64 bits long and start with 0xFD.
|
||
* - OMR_2 MUST be equal to the OMR_2 values as used in previous test steps.
|
||
*/
|
||
Log("Step 16: BR_1 (DUT) re-registers OMR_2.");
|
||
|
||
WaitForPrefix(nexus, br2, omr2, true);
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 17
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically multicasts ND RAs on Adjacent Infrastructure Link with OMR_2.
|
||
* - Note: the reason that OMR_3 is not advertised, is that OMR_3 was withdrawn and was not originally created by
|
||
* BR_1. So BR_1 has no responsibility to advertise this deprecated prefix.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST multicast ND RAs on the infrastructure link:
|
||
* - IPv6 destination MUST be ff02::1
|
||
* - MUST NOT contain a Prefix Information Option (PIO) with a ULA prefix.
|
||
* - MUST NOT contain a Route Information Option (RIO) with OMR_1.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_2.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low)
|
||
* - MUST NOT contain a Route Information Option (RIO) with OMR_3.
|
||
*/
|
||
Log("Step 17: BR_1 (DUT) multicasts ND RA with OMR_2, no OMR_3.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 18
|
||
* - Device: BR_2
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to add new OMR prefix (OMR_4) numerically higher than OMR_2, but with same
|
||
* preference "Low".
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 18: BR_2 adds OMR_4.");
|
||
|
||
Ip6::Prefix omr4;
|
||
SuccessOrQuit(omr4.FromString(kOmr4PrefixStr));
|
||
|
||
PublishOmrPrefix(br2, omr4, NetworkData::kRoutePreferenceLow, true);
|
||
|
||
WaitForPrefix(nexus, br2, omr4, true);
|
||
|
||
nexus.AdvanceTime(kLongActionTime);
|
||
nexus.AddTestVar("OMR_4_PREFIX", kOmr4PrefixStr);
|
||
Log("OMR_4_PREFIX: %s", kOmr4PrefixStr);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 19
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - No change in behavior for advertising its OMR prefix, OMR_2.
|
||
* - Automatically starts advertising a route for the new OMR_4 prefix.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST NOT send a Network Data update with any one of the following prefixes in a Prefix TLV:
|
||
* - OMR_1, OMR_2, OMR_3, OMR_4
|
||
* - The DUT MUST multicast ND RAs on the infrastructure link:
|
||
* - IPv6 destination MUST be ff02::1
|
||
* - MUST NOT contain a Prefix Information Option (PIO) with a ULA prefix.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_2.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low).
|
||
* - MUST contain a Route Information Option (RIO) with OMR_4.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low).
|
||
* - MUST NOT contain RIO with any one of OMR_1, OMR_3.
|
||
*/
|
||
Log("Step 19: BR_1 (DUT) continues OMR_2, adds OMR_4 on AIL.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 20
|
||
* - Device: BR_2
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to update the numerically higher OMR_4 with a higher preference value 00
|
||
* ('Medium').
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 20: BR_2 updates OMR_4 to Medium pref.");
|
||
|
||
PublishOmrPrefix(br2, omr4, NetworkData::kRoutePreferenceMedium, true);
|
||
|
||
nexus.AdvanceTime(kLongActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 21
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8): Automatically withdraws its current OMR prefix OMR_2.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST send a Network Data update. In the new network data:
|
||
* - the following prefixes MUST NOT be present in a Prefix TLV: OMR_1, OMR_2, OMR_3
|
||
* - The DUT MUST multicast ND RAs on the infrastructure link:
|
||
* - IPv6 destination MUST be ff02::1
|
||
* - MUST NOT contain a Prefix Information Option (PIO) with a ULA prefix.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_2:
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low).
|
||
* - MUST contain a Route Information Option (RIO) with OMR_4:
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low).
|
||
* - MUST NOT contain a Route Information Option (RIO) with OMR_1 or OMR_3.
|
||
*/
|
||
Log("Step 21: BR_1 (DUT) withdraws OMR_2.");
|
||
|
||
WaitForPrefix(nexus, br2, omr2, false);
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 22
|
||
* - Device: BR_2
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to update the prefix OMR_4 to a deprecated state by setting P_preferred =
|
||
* 'false'.
|
||
* - Note: can use OT command 'netdata publish prefix' for this where the flags do not contain the 'p' (Preferred)
|
||
* flag.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 22: BR_2 deprecates OMR_4.");
|
||
|
||
PublishOmrPrefix(br2, omr4, NetworkData::kRoutePreferenceMedium, false);
|
||
|
||
nexus.AdvanceTime(kLongActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 23
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8): Automatically starts advertising its own OMR prefix OMR_2 again.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST register its OMR prefix OMR_2 in the Thread Network Data. Flags in the Border Router sub-TLV
|
||
* MUST be:
|
||
* - P_preference = 11 (Low)
|
||
* - P_default = true
|
||
* - P_stable = true
|
||
* - P_on_mesh = true
|
||
* - P_preferred = true
|
||
* - P_slaac = true
|
||
* - P_dhcp = false
|
||
* - P_dp = false
|
||
* - OMR_2 MUST be 64 bits long and start with 0xFD.
|
||
* - OMR_2 MUST be equal to the OMR_2 values as used in previous test steps.
|
||
*/
|
||
Log("Step 23: BR_1 (DUT) re-registers OMR_2.");
|
||
|
||
WaitForPrefix(nexus, br2, omr2, true);
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 24
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically multicasts ND RAs on Adjacent Infrastructure Link.
|
||
* - Note: even though OMR_4 is deprecated, it is still valid so it is advertised on the AIL in a RIO.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST multicast ND RAs on the infrastructure link:
|
||
* - IPv6 destination MUST be ff02::1
|
||
* - MUST NOT contain a Prefix Information Option (PIO) with a ULA prefix.
|
||
* - MUST NOT contain a Route Information Option (RIO) with OMR_1.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_2.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low)
|
||
* - MUST NOT contain a Route Information Option (RIO) with OMR_3.
|
||
* - MUST contain a Route Information Option (RIO) with OMR_4.
|
||
* - "Prf" bits MUST be 00 (medium) or 11 (low)
|
||
*/
|
||
Log("Step 24: BR_1 (DUT) multicasts ND RA with OMR_2 and OMR_4.");
|
||
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 25
|
||
* - Device: Eth_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to ED_1 via BR_1.
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_2)
|
||
* - Pass Criteria:
|
||
* - Eth_1 receives an ICMPv6 Echo Reply from ED_1.
|
||
* - IPv6 Source: ED_1 OMR (using prefix OMR_2)
|
||
* - IPv6 Destination: Eth_1 GUA
|
||
*/
|
||
Log("Step 25: Eth_1 pings ED_1 OMR_2.");
|
||
|
||
eth1.mInfraIf.SendEchoRequest(eth1Gua, ed1Omr2, kEchoIdentifier, kEchoPayloadSize);
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 26
|
||
* - Device: ED_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to Eth_1.
|
||
* - IPv6 Source: ED_1 OMR address (using prefix OMR_2)
|
||
* - IPv6 Destination: Eth_1 GUA
|
||
* - Pass Criteria:
|
||
* - ED_1 receives an ICMPv6 Echo Reply from Eth_1.
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_2)
|
||
*/
|
||
Log("Step 26: ED_1 OMR_2 pings Eth_1 GUA.");
|
||
|
||
ed1.SendEchoRequest(eth1Gua, kEchoIdentifier, kEchoPayloadSize, kDefaultHopLimit, &ed1Omr2);
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 27
|
||
* - Device: BR_2
|
||
* - Description (DBR-1.8):
|
||
* - Harness disables the BR function of the device. Or if that is not possible, switch it off.
|
||
* - Note: disabling BR may use 'br disable' CLI command.
|
||
* - Note: in case of switching off BR_2, the OMR prefix OMR_4 that was advertised by BR_2 remains active for some
|
||
* time. The Leader timeout of Leader BR_2 does not happen yet during the below steps of this test.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 27: BR_2 disabled.");
|
||
|
||
SuccessOrQuit(br2.Get<BorderRouter::RoutingManager>().SetEnabled(false));
|
||
nexus.AdvanceTime(kBrActionTime);
|
||
DumpNetworkData(br2);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 28
|
||
* - Device: Eth_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to ED_1 via BR_1.
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_2)
|
||
* - Pass Criteria:
|
||
* - Eth_1 receives an ICMPv6 Echo Reply from ED_1.
|
||
* - IPv6 Source: ED_1 OMR (using prefix OMR_2)
|
||
* - IPv6 Destination: Eth_1 GUA
|
||
*/
|
||
Log("Step 28: Eth_1 pings ED_1 OMR_2.");
|
||
|
||
eth1.mInfraIf.SendEchoRequest(eth1Gua, ed1Omr2, kEchoIdentifier, kEchoPayloadSize);
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 29
|
||
* - Device: ED_1
|
||
* - Description (DBR-1.8):
|
||
* - Harness instructs the device to send an ICMPv6 Echo Request to Eth_1.
|
||
* - IPv6 Source: ED_1 OMR address (using prefix OMR_4)
|
||
* - IPv6 Destination: Eth_1 GUA.
|
||
* - Note: ED_1 is forced here to use a source address based on prefix OMR_4, even though that prefix is
|
||
* deprecated. In OT CLI this can most likely be achieved using the command:
|
||
* - ping -I <ED_1-OMR_4-address> <Eth_1-GUA>
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 29: ED_1 pings Eth_1 using OMR_4.");
|
||
|
||
const Ip6::Address &ed1Omr4 = ed1.FindMatchingAddress(kOmr4PrefixStr);
|
||
nexus.AddTestVar("ED_1_OMR_4_ADDR", ed1Omr4.ToString().AsCString());
|
||
ed1.SendEchoRequest(eth1Gua, kEchoIdentifier, kEchoPayloadSize, kDefaultHopLimit, &ed1Omr4);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 30
|
||
* - Device: Eth_1
|
||
* - Description (DBR-1.8):
|
||
* - Automatically replies to the ICMPv6 Echo Request with Echo Reply, that is sent to BR_1.
|
||
* - Pass Criteria:
|
||
* - N/A
|
||
*/
|
||
Log("Step 30: Eth_1 replies to OMR_4.");
|
||
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
Log("---------------------------------------------------------------------------------------");
|
||
/**
|
||
* Step 31
|
||
* - Device: BR_1 (DUT)
|
||
* - Description (DBR-1.8):
|
||
* - Automatically attempts to deliver the Echo Reply to a node on the mesh.
|
||
* - Pass Criteria:
|
||
* - The DUT MUST attempt to deliver the packet to a node on the mesh, either:
|
||
* - 1. BR_1 sends a multicast Address Query for ED_1 OMR_4 based address into the mesh;
|
||
* - 2. or ED_1 receives the Echo Reply from Eth_1 as follows:
|
||
* - IPv6 Source: Eth_1 GUA
|
||
* - IPv6 Destination: ED_1 OMR address (using prefix OMR_4)
|
||
*/
|
||
Log("Step 31: BR_1 delivers Echo Reply for OMR_4.");
|
||
|
||
nexus.AdvanceTime(kPingResponseTime);
|
||
|
||
nexus.SaveTestInfo("test_1_3_DBR_TC_8.json");
|
||
}
|
||
|
||
} // namespace Nexus
|
||
} // namespace ot
|
||
|
||
int main(void)
|
||
{
|
||
ot::Nexus::Test_1_3_DBR_TC_8();
|
||
printf("All tests passed\n");
|
||
return 0;
|
||
}
|