mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[nexus] migrate test_netdata_publisher to Nexus (#12931)
This commit migrates the functionality of tests/scripts/thread-cert/test_netdata_publisher.py to a new Nexus test tests/nexus/test_netdata_publisher.cpp. The new Nexus test covers: - DNS/SRP Anycast entries (equal and different version numbers). - DNS/SRP Unicast entries (service data and server data). - Displacement of server data unicast by anycast entries. - Publisher preference logic for DNS/SRP services. - On-mesh prefix publisher preference and replacement. - External route publisher preference and replacement. Other changes: - Add netdata_publisher to tests/nexus/CMakeLists.txt. - Add netdata_publisher to default tests in tests/nexus/run_nexus_tests.sh. - Remove the old tests/scripts/thread-cert/test_netdata_publisher.py.
This commit is contained in:
@@ -400,6 +400,7 @@ ot_nexus_test(log_override "core;nexus")
|
||||
ot_nexus_test(mac_scan "core;nexus")
|
||||
ot_nexus_test(mle_blocking_downgrade "core;nexus")
|
||||
ot_nexus_test(nat64_translator "core;nexus")
|
||||
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(srp_lease "core;nexus")
|
||||
|
||||
@@ -0,0 +1,926 @@
|
||||
/*
|
||||
* 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 <initializer_list>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "platform/nexus_core.hpp"
|
||||
#include "platform/nexus_node.hpp"
|
||||
#include "thread/network_data_leader.hpp"
|
||||
#include "thread/network_data_local.hpp"
|
||||
#include "thread/network_data_publisher.hpp"
|
||||
#include "thread/network_data_service.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Nexus {
|
||||
|
||||
static constexpr uint32_t kFormNetworkTime = 20 * 1000;
|
||||
static constexpr uint32_t kJoinNetworkTime = 10 * 1000;
|
||||
static constexpr uint32_t kNetDataUpdateTime = 55 * 1000;
|
||||
|
||||
static constexpr char kOnMeshPrefix[] = "fd00:1234::/64";
|
||||
static constexpr char kExternalRoute[] = "fd00:abce::/64";
|
||||
|
||||
static constexpr uint8_t kAnycastSeqNum = 4;
|
||||
|
||||
static const char *const kDnsSrpAddrStr = "fd00::cdef";
|
||||
static constexpr uint16_t kDnsSrpPort = 49152;
|
||||
|
||||
static constexpr uint8_t kDesiredNumAnycast = 8;
|
||||
static constexpr uint8_t kDesiredNumUnicast = 2;
|
||||
static constexpr uint8_t kDesiredNumOnMeshPrefix = 3;
|
||||
static constexpr uint8_t kDesiredNumExternalRoute = 10;
|
||||
|
||||
static constexpr uint32_t kThreadEnterpriseNumber = 44970;
|
||||
static constexpr uint8_t kAnycastServiceNum = 0x5c;
|
||||
static constexpr uint8_t kUnicastServiceNum = 0x5d;
|
||||
|
||||
static uint8_t GetNumServices(Node &aNode)
|
||||
{
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ServiceConfig serviceConfig;
|
||||
uint8_t num = 0;
|
||||
const NetworkData::Leader &leader = aNode.Get<NetworkData::Leader>();
|
||||
|
||||
while (leader.GetNext(iterator, serviceConfig) == kErrorNone)
|
||||
{
|
||||
num++;
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
static void VerifyAnycastService(const NetworkData::ServiceConfig &aService)
|
||||
{
|
||||
VerifyOrQuit(aService.mEnterpriseNumber == kThreadEnterpriseNumber);
|
||||
VerifyOrQuit(aService.mServiceDataLength >= 2);
|
||||
VerifyOrQuit(aService.mServiceData[0] == kAnycastServiceNum);
|
||||
VerifyOrQuit(aService.mServiceData[1] == kAnycastSeqNum);
|
||||
VerifyOrQuit(aService.mServerConfig.mStable);
|
||||
}
|
||||
|
||||
static void VerifyUnicastService(const NetworkData::ServiceConfig &aService)
|
||||
{
|
||||
VerifyOrQuit(aService.mEnterpriseNumber == kThreadEnterpriseNumber);
|
||||
VerifyOrQuit(aService.mServiceDataLength >= 1);
|
||||
VerifyOrQuit(aService.mServiceData[0] == kUnicastServiceNum);
|
||||
VerifyOrQuit(aService.mServerConfig.mStable);
|
||||
}
|
||||
|
||||
enum ServiceType : uint8_t
|
||||
{
|
||||
kAsAnycastService,
|
||||
kAsUnicastService,
|
||||
};
|
||||
|
||||
static void VerifyServices(Node &aNode, ServiceType aType)
|
||||
{
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ServiceConfig serviceConfig;
|
||||
const NetworkData::Leader &leader = aNode.Get<NetworkData::Leader>();
|
||||
|
||||
while (leader.GetNext(iterator, serviceConfig) == kErrorNone)
|
||||
{
|
||||
if (aType == kAsAnycastService)
|
||||
{
|
||||
VerifyAnycastService(serviceConfig);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyUnicastService(serviceConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void CheckNumOfPrefixes(Node &aNode, uint8_t aNumLow, uint8_t aNumMed, uint8_t aNumHigh)
|
||||
{
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::OnMeshPrefixConfig prefixConfig;
|
||||
const NetworkData::Leader &leader = aNode.Get<NetworkData::Leader>();
|
||||
uint8_t numTotal = 0;
|
||||
uint8_t numLow = 0;
|
||||
uint8_t numMed = 0;
|
||||
uint8_t numHigh = 0;
|
||||
|
||||
while (leader.GetNext(iterator, prefixConfig) == kErrorNone)
|
||||
{
|
||||
numTotal++;
|
||||
if (prefixConfig.mPreference == NetworkData::kRoutePreferenceLow)
|
||||
{
|
||||
numLow++;
|
||||
}
|
||||
else if (prefixConfig.mPreference == NetworkData::kRoutePreferenceMedium)
|
||||
{
|
||||
numMed++;
|
||||
}
|
||||
else if (prefixConfig.mPreference == NetworkData::kRoutePreferenceHigh)
|
||||
{
|
||||
numHigh++;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(numTotal ==
|
||||
Min<uint16_t>(static_cast<uint16_t>(aNumHigh) + aNumMed + aNumLow, kDesiredNumOnMeshPrefix));
|
||||
VerifyOrQuit(numHigh == Min(aNumHigh, kDesiredNumOnMeshPrefix));
|
||||
VerifyOrQuit(numMed ==
|
||||
Min(aNumMed, static_cast<uint8_t>(Max<int>(0, (int)kDesiredNumOnMeshPrefix - (int)aNumHigh))));
|
||||
VerifyOrQuit(numLow == Min(aNumLow, static_cast<uint8_t>(
|
||||
Max<int>(0, (int)kDesiredNumOnMeshPrefix - (int)aNumHigh - (int)numMed))));
|
||||
}
|
||||
|
||||
static void CheckNumOfRoutes(Node &aNode, uint8_t aNumLow, uint8_t aNumMed, uint8_t aNumHigh)
|
||||
{
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ExternalRouteConfig routeConfig;
|
||||
const NetworkData::Leader &leader = aNode.Get<NetworkData::Leader>();
|
||||
uint8_t numTotal = 0;
|
||||
uint8_t numLow = 0;
|
||||
uint8_t numMed = 0;
|
||||
uint8_t numHigh = 0;
|
||||
|
||||
while (leader.GetNext(iterator, routeConfig) == kErrorNone)
|
||||
{
|
||||
numTotal++;
|
||||
if (routeConfig.mPreference == NetworkData::kRoutePreferenceLow)
|
||||
{
|
||||
numLow++;
|
||||
}
|
||||
else if (routeConfig.mPreference == NetworkData::kRoutePreferenceMedium)
|
||||
{
|
||||
numMed++;
|
||||
}
|
||||
else if (routeConfig.mPreference == NetworkData::kRoutePreferenceHigh)
|
||||
{
|
||||
numHigh++;
|
||||
}
|
||||
}
|
||||
|
||||
VerifyOrQuit(numTotal ==
|
||||
Min<uint16_t>(static_cast<uint16_t>(aNumHigh) + aNumMed + aNumLow, kDesiredNumExternalRoute));
|
||||
VerifyOrQuit(numHigh == Min(aNumHigh, kDesiredNumExternalRoute));
|
||||
VerifyOrQuit(numMed ==
|
||||
Min(aNumMed, static_cast<uint8_t>(Max<int>(0, (int)kDesiredNumExternalRoute - (int)aNumHigh))));
|
||||
VerifyOrQuit(numLow == Min(aNumLow, static_cast<uint8_t>(
|
||||
Max<int>(0, (int)kDesiredNumExternalRoute - (int)aNumHigh - (int)numMed))));
|
||||
}
|
||||
|
||||
void Test_NetDataPublisher(void)
|
||||
{
|
||||
Core nexus;
|
||||
|
||||
Node &leader = nexus.CreateNode();
|
||||
Node &router1 = nexus.CreateNode();
|
||||
Node &router2 = nexus.CreateNode();
|
||||
Node &router3 = nexus.CreateNode();
|
||||
Node &router4 = nexus.CreateNode();
|
||||
Node &router5 = nexus.CreateNode();
|
||||
Node &ed1 = nexus.CreateNode();
|
||||
Node &ed2 = nexus.CreateNode();
|
||||
Node &ed3 = nexus.CreateNode();
|
||||
Node &ed4 = nexus.CreateNode();
|
||||
Node &ed5 = nexus.CreateNode();
|
||||
|
||||
leader.SetName("LEADER");
|
||||
router1.SetName("ROUTER1");
|
||||
router2.SetName("ROUTER2");
|
||||
router3.SetName("ROUTER3");
|
||||
router4.SetName("ROUTER4");
|
||||
router5.SetName("ROUTER5");
|
||||
ed1.SetName("END_DEV1");
|
||||
ed2.SetName("END_DEV2");
|
||||
ed3.SetName("END_DEV3");
|
||||
ed4.SetName("END_DEV4");
|
||||
ed5.SetName("END_DEV5");
|
||||
|
||||
Node *routers[] = {&router1, &router2, &router3, &router4, &router5};
|
||||
Node *eds[] = {&ed1, &ed2, &ed3, &ed4, &ed5};
|
||||
Node *nodes[] = {&leader, &router1, &router2, &router3, &router4, &router5, &ed1, &ed2, &ed3, &ed4, &ed5};
|
||||
|
||||
nexus.AdvanceTime(0);
|
||||
|
||||
leader.Form();
|
||||
nexus.AdvanceTime(kFormNetworkTime);
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Join(leader);
|
||||
nexus.AdvanceTime(kJoinNetworkTime);
|
||||
}
|
||||
|
||||
for (Node *ed : eds)
|
||||
{
|
||||
ed->Join(leader, Node::kAsFed);
|
||||
nexus.AdvanceTime(kJoinNetworkTime);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP anycast entries - equal version number");
|
||||
|
||||
leader.Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, 0);
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, 0);
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(1 + GetArrayLength(routers), kDesiredNumAnycast));
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
|
||||
for (Node *ed : eds)
|
||||
{
|
||||
ed->Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, 0);
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(GetArrayLength(nodes), kDesiredNumAnycast));
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
|
||||
uint8_t num = GetArrayLength(nodes);
|
||||
for (Node *node : nodes)
|
||||
{
|
||||
node->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num--;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumAnycast));
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP anycast entries - different version numbers");
|
||||
|
||||
uint8_t version = 0;
|
||||
leader.Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, version);
|
||||
num = 1;
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
version++;
|
||||
router->Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, version);
|
||||
num++;
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumAnycast));
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
|
||||
for (Node *ed : eds)
|
||||
{
|
||||
ed->Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, version);
|
||||
num++;
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumAnycast));
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
|
||||
// Check that the entry from this ED is present by checking its RLOC16
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ServiceConfig serviceConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, serviceConfig) == kErrorNone)
|
||||
{
|
||||
if (serviceConfig.mServerConfig.mRloc16 == ed->Get<Mle::Mle>().GetRloc16())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
}
|
||||
|
||||
for (Node *node : nodes)
|
||||
{
|
||||
node->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num--;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumAnycast));
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP service data unicast entries - equal version number");
|
||||
|
||||
Ip6::Address dnsSrpAddr;
|
||||
SuccessOrQuit(dnsSrpAddr.FromString(kDnsSrpAddrStr));
|
||||
|
||||
num = 0;
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(dnsSrpAddr, kDnsSrpPort, 0);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<Srp::Server>().SetEnabled(true);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
}
|
||||
|
||||
uint8_t runningCount = 0;
|
||||
uint8_t stoppedCount = 0;
|
||||
for (Node *router : routers)
|
||||
{
|
||||
if (router->Get<Srp::Server>().GetState() == Srp::Server::kStateRunning)
|
||||
{
|
||||
runningCount++;
|
||||
}
|
||||
else if (router->Get<Srp::Server>().GetState() == Srp::Server::kStateStopped)
|
||||
{
|
||||
stoppedCount++;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(runningCount == Min<uint16_t>(GetArrayLength(routers), kDesiredNumUnicast));
|
||||
VerifyOrQuit(stoppedCount ==
|
||||
static_cast<uint8_t>(Max<int>(0, (int)GetArrayLength(routers) - (int)kDesiredNumUnicast)));
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num--;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<Srp::Server>().SetEnabled(false);
|
||||
VerifyOrQuit(router->Get<Srp::Server>().GetState() == Srp::Server::kStateDisabled);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP service data unicast entries - different version numbers");
|
||||
|
||||
num = 0;
|
||||
for (uint8_t i = 0; i < GetArrayLength(routers); i++)
|
||||
{
|
||||
routers[i]->Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(dnsSrpAddr, kDnsSrpPort, num);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
|
||||
// The most recent service should win as it uses a higher version number.
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ServiceConfig serviceConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, serviceConfig) == kErrorNone)
|
||||
{
|
||||
if (serviceConfig.mServerConfig.mRloc16 == routers[i]->Get<Mle::Mle>().GetRloc16())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
}
|
||||
|
||||
for (int i = static_cast<int>(GetArrayLength(routers)) - 1; i >= 0; i--)
|
||||
{
|
||||
routers[i]->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num--;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP server data unicast entries - equal version number");
|
||||
|
||||
num = 0;
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(kDnsSrpPort, 0);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<Srp::Server>().SetEnabled(true);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
}
|
||||
runningCount = 0;
|
||||
stoppedCount = 0;
|
||||
for (Node *router : routers)
|
||||
{
|
||||
if (router->Get<Srp::Server>().GetState() == Srp::Server::kStateRunning)
|
||||
{
|
||||
runningCount++;
|
||||
}
|
||||
else if (router->Get<Srp::Server>().GetState() == Srp::Server::kStateStopped)
|
||||
{
|
||||
stoppedCount++;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(runningCount == Min<uint16_t>(GetArrayLength(routers), kDesiredNumUnicast));
|
||||
VerifyOrQuit(stoppedCount ==
|
||||
static_cast<uint8_t>(Max<int>(0, (int)GetArrayLength(routers) - (int)kDesiredNumUnicast)));
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num--;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<Srp::Server>().SetEnabled(false);
|
||||
VerifyOrQuit(router->Get<Srp::Server>().GetState() == Srp::Server::kStateDisabled);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP server data unicast entries - different version numbers");
|
||||
|
||||
num = 0;
|
||||
for (uint8_t i = 0; i < GetArrayLength(routers); i++)
|
||||
{
|
||||
routers[i]->Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(kDnsSrpPort, num);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ServiceConfig serviceConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, serviceConfig) == kErrorNone)
|
||||
{
|
||||
if (serviceConfig.mServerConfig.mRloc16 == routers[i]->Get<Mle::Mle>().GetRloc16())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
}
|
||||
|
||||
for (int i = static_cast<int>(GetArrayLength(routers)) - 1; i >= 0; i--)
|
||||
{
|
||||
routers[i]->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num--;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
num = 0;
|
||||
for (uint8_t i = 0; i < GetArrayLength(routers); i++)
|
||||
{
|
||||
routers[i]->Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(kDnsSrpPort, 20 - num);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
|
||||
// The service from first router should win as it uses the highest version number.
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ServiceConfig serviceConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, serviceConfig) == kErrorNone)
|
||||
{
|
||||
if (serviceConfig.mServerConfig.mRloc16 == routers[0]->Get<Mle::Mle>().GetRloc16())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
}
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num--;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP server data unicast vs anycast");
|
||||
|
||||
num = 0;
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(kDnsSrpPort, 0);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
}
|
||||
|
||||
leader.Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, 0);
|
||||
|
||||
// Verify that publishing an anycast entry will update the
|
||||
// limit for the server data unicast address entry and all are
|
||||
// removed quickly. We validate this by waiting for a short
|
||||
// time (5000 msec) after publishing anycast.
|
||||
nexus.AdvanceTime(5000);
|
||||
VerifyOrQuit(GetNumServices(leader) == 1);
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
|
||||
// Removing the anycast entry will cause the lower priority
|
||||
// server data unicast entries to be added again.
|
||||
leader.Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP server data unicast vs service data unicast");
|
||||
|
||||
leader.Get<NetworkData::Publisher>().PublishDnsSrpServiceUnicast(dnsSrpAddr, kDnsSrpPort, 0);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
VerifyOrQuit(GetNumServices(leader) == 1);
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
|
||||
leader.Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumUnicast));
|
||||
VerifyServices(leader, kAsUnicastService);
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
router->Get<NetworkData::Publisher>().UnpublishDnsSrpService();
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("DNS/SRP entries: Verify publisher preference when removing entries");
|
||||
|
||||
num = 0;
|
||||
Node *testRoutersNodes[] = {&leader, &router1, &router2};
|
||||
for (Node *node : testRoutersNodes)
|
||||
{
|
||||
node->Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, 0);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == num);
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
}
|
||||
for (Node *node : eds)
|
||||
{
|
||||
node->Get<NetworkData::Publisher>().PublishDnsSrpServiceAnycast(kAnycastSeqNum, 0);
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
VerifyOrQuit(GetNumServices(leader) == Min<uint16_t>(num, kDesiredNumAnycast));
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
}
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == kDesiredNumAnycast);
|
||||
|
||||
for (Node *node : {&router3, &router4, &router5})
|
||||
{
|
||||
// Manually add service to router
|
||||
NetworkData::ServiceData serviceData;
|
||||
NetworkData::ServerData serverData;
|
||||
uint8_t sData[] = {kAnycastServiceNum, kAnycastSeqNum};
|
||||
|
||||
serviceData.Init(sData, sizeof(sData));
|
||||
serverData.Init(nullptr, 0);
|
||||
|
||||
SuccessOrQuit(
|
||||
node->Get<NetworkData::Local>().AddService(kThreadEnterpriseNumber, serviceData, true, serverData));
|
||||
node->Get<NetworkData::Notifier>().HandleServerDataUpdated();
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
VerifyOrQuit(GetNumServices(leader) == kDesiredNumAnycast);
|
||||
VerifyServices(leader, kAsAnycastService);
|
||||
}
|
||||
|
||||
// Final check for all routers being present.
|
||||
{
|
||||
Node *allRouters[] = {&leader, &router1, &router2, &router3, &router4, &router5};
|
||||
for (Node *router : allRouters)
|
||||
{
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ServiceConfig serviceConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, serviceConfig) == kErrorNone)
|
||||
{
|
||||
if (serviceConfig.mServerConfig.mRloc16 == router->Get<Mle::Mle>().GetRloc16())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
}
|
||||
}
|
||||
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("On-mesh prefix");
|
||||
|
||||
Ip6::Prefix onMeshPrefix;
|
||||
SuccessOrQuit(onMeshPrefix.FromString(kOnMeshPrefix));
|
||||
|
||||
uint8_t numLow = 0;
|
||||
uint8_t numMed = 0;
|
||||
uint8_t numHigh = 0;
|
||||
|
||||
for (Node *ed : eds)
|
||||
{
|
||||
NetworkData::OnMeshPrefixConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = onMeshPrefix;
|
||||
config.mPreference = NetworkData::kRoutePreferenceLow;
|
||||
config.mSlaac = true;
|
||||
config.mOnMesh = true;
|
||||
config.mStable = true;
|
||||
config.mPreferred = true;
|
||||
SuccessOrQuit(ed->Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
numLow++;
|
||||
CheckNumOfPrefixes(leader, numLow, numMed, numHigh);
|
||||
}
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
NetworkData::OnMeshPrefixConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = onMeshPrefix;
|
||||
config.mPreference = NetworkData::kRoutePreferenceMedium;
|
||||
config.mSlaac = true;
|
||||
config.mOnMesh = true;
|
||||
config.mStable = true;
|
||||
config.mPreferred = true;
|
||||
SuccessOrQuit(
|
||||
router->Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
numMed++;
|
||||
CheckNumOfPrefixes(leader, numLow, numMed, numHigh);
|
||||
}
|
||||
|
||||
{
|
||||
NetworkData::OnMeshPrefixConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = onMeshPrefix;
|
||||
config.mPreference = NetworkData::kRoutePreferenceHigh;
|
||||
config.mSlaac = true;
|
||||
config.mOnMesh = true;
|
||||
config.mStable = true;
|
||||
config.mPreferred = true;
|
||||
SuccessOrQuit(
|
||||
leader.Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
numHigh++;
|
||||
CheckNumOfPrefixes(leader, numLow, numMed, numHigh);
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
SuccessOrQuit(router->Get<NetworkData::Publisher>().UnpublishPrefix(onMeshPrefix));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
numMed--;
|
||||
CheckNumOfPrefixes(leader, numLow, numMed, numHigh);
|
||||
}
|
||||
|
||||
SuccessOrQuit(leader.Get<NetworkData::Publisher>().UnpublishPrefix(onMeshPrefix));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
numHigh--;
|
||||
CheckNumOfPrefixes(leader, numLow, numMed, numHigh);
|
||||
|
||||
for (Node *ed : eds)
|
||||
{
|
||||
SuccessOrQuit(ed->Get<NetworkData::Publisher>().UnpublishPrefix(onMeshPrefix));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
numLow--;
|
||||
CheckNumOfPrefixes(leader, numLow, numMed, numHigh);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("Verify prefix removal preference");
|
||||
|
||||
{
|
||||
NetworkData::OnMeshPrefixConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = onMeshPrefix;
|
||||
config.mPreference = NetworkData::kRoutePreferenceMedium;
|
||||
config.mSlaac = true;
|
||||
config.mOnMesh = true;
|
||||
config.mStable = true;
|
||||
config.mPreferred = true;
|
||||
SuccessOrQuit(ed1.Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
CheckNumOfPrefixes(leader, 0, 1, 0);
|
||||
|
||||
for (Node *router : routers)
|
||||
{
|
||||
NetworkData::OnMeshPrefixConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = onMeshPrefix;
|
||||
config.mPreference = NetworkData::kRoutePreferenceMedium;
|
||||
config.mSlaac = true;
|
||||
config.mOnMesh = true;
|
||||
config.mStable = true;
|
||||
config.mPreferred = true;
|
||||
SuccessOrQuit(
|
||||
router->Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
}
|
||||
CheckNumOfPrefixes(leader, 0, 1 + GetArrayLength(routers), 0);
|
||||
|
||||
// Check ed1 is in the list
|
||||
{
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::OnMeshPrefixConfig prefixConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, prefixConfig) == kErrorNone)
|
||||
{
|
||||
if (prefixConfig.mRloc16 == ed1.Get<Mle::Mle>().GetRloc16())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
}
|
||||
|
||||
{
|
||||
NetworkData::OnMeshPrefixConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = onMeshPrefix;
|
||||
config.mPreference = NetworkData::kRoutePreferenceHigh;
|
||||
config.mSlaac = true;
|
||||
config.mOnMesh = true;
|
||||
config.mStable = true;
|
||||
config.mPreferred = true;
|
||||
SuccessOrQuit(
|
||||
leader.Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
CheckNumOfPrefixes(leader, 0, 1 + GetArrayLength(routers), 1);
|
||||
|
||||
// Publish same prefix now with `high` preference on leader.
|
||||
// Since it is `high` preference, it is added to network data
|
||||
// which leads to total number of entries to go above the desired
|
||||
// number temporarily and trigger other nodes to try to remove
|
||||
// their entry. The entries from routers should be preferred over
|
||||
// the one from `end_dev1` so that is the one we expect to be
|
||||
// removed. We check that this is the case (i.e., the entry from
|
||||
// `end_dev1` is no longer present in network data).
|
||||
//
|
||||
// Check ed1 is NO LONGER in the list
|
||||
{
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::OnMeshPrefixConfig prefixConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, prefixConfig) == kErrorNone)
|
||||
{
|
||||
if (prefixConfig.mRloc16 == ed1.Get<Mle::Mle>().GetRloc16())
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(!found);
|
||||
}
|
||||
|
||||
Log("---------------------------------------------------------------------------------------");
|
||||
Log("External route");
|
||||
|
||||
Ip6::Prefix externalRoute;
|
||||
SuccessOrQuit(externalRoute.FromString(kExternalRoute));
|
||||
|
||||
num = 0;
|
||||
for (Node *node : nodes)
|
||||
{
|
||||
NetworkData::ExternalRouteConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = externalRoute;
|
||||
config.mPreference = NetworkData::kRoutePreferenceLow;
|
||||
config.mStable = true;
|
||||
SuccessOrQuit(
|
||||
node->Get<NetworkData::Publisher>().PublishExternalRoute(config, NetworkData::Publisher::kFromUser));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
num++;
|
||||
CheckNumOfRoutes(leader, num, 0, 0);
|
||||
}
|
||||
|
||||
{
|
||||
NetworkData::ExternalRouteConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = externalRoute;
|
||||
config.mPreference = NetworkData::kRoutePreferenceHigh;
|
||||
config.mStable = true;
|
||||
SuccessOrQuit(
|
||||
leader.Get<NetworkData::Publisher>().PublishExternalRoute(config, NetworkData::Publisher::kFromUser));
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
CheckNumOfRoutes(leader, num - 1, 0, 1);
|
||||
|
||||
{
|
||||
Ip6::Prefix defaultRoute;
|
||||
SuccessOrQuit(defaultRoute.FromString("::/0"));
|
||||
NetworkData::ExternalRouteConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = defaultRoute;
|
||||
config.mPreference = NetworkData::kRoutePreferenceMedium;
|
||||
config.mStable = true;
|
||||
SuccessOrQuit(leader.Get<NetworkData::Publisher>().ReplacePublishedExternalRoute(
|
||||
externalRoute, config, NetworkData::Publisher::kFromUser));
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::ExternalRouteConfig routeConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, routeConfig) == kErrorNone)
|
||||
{
|
||||
if (AsCoreType(&routeConfig.mPrefix) == defaultRoute)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
|
||||
// Replace it back
|
||||
config.GetPrefix() = externalRoute;
|
||||
config.mPreference = NetworkData::kRoutePreferenceHigh;
|
||||
SuccessOrQuit(leader.Get<NetworkData::Publisher>().ReplacePublishedExternalRoute(
|
||||
defaultRoute, config, NetworkData::Publisher::kFromUser));
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
CheckNumOfRoutes(leader, num - 1, 0, 1);
|
||||
|
||||
{
|
||||
NetworkData::OnMeshPrefixConfig config;
|
||||
config.Clear();
|
||||
config.GetPrefix() = externalRoute;
|
||||
config.mPreference = NetworkData::kRoutePreferenceLow;
|
||||
config.mSlaac = true;
|
||||
config.mOnMesh = true;
|
||||
config.mStable = true;
|
||||
config.mPreferred = true;
|
||||
SuccessOrQuit(
|
||||
leader.Get<NetworkData::Publisher>().PublishOnMeshPrefix(config, NetworkData::Publisher::kFromUser));
|
||||
}
|
||||
nexus.AdvanceTime(kNetDataUpdateTime);
|
||||
CheckNumOfRoutes(leader, num - 1, 0, 0);
|
||||
|
||||
{
|
||||
bool found = false;
|
||||
NetworkData::Iterator iterator = NetworkData::kIteratorInit;
|
||||
NetworkData::OnMeshPrefixConfig prefixConfig;
|
||||
while (leader.Get<NetworkData::Leader>().GetNext(iterator, prefixConfig) == kErrorNone)
|
||||
{
|
||||
if (AsCoreType(&prefixConfig.mPrefix) == externalRoute)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
VerifyOrQuit(found);
|
||||
}
|
||||
|
||||
Log("All steps completed.");
|
||||
}
|
||||
|
||||
} // namespace Nexus
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::Nexus::Test_NetDataPublisher();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -1,693 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2021, 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 ipaddress
|
||||
import unittest
|
||||
|
||||
import command
|
||||
import config
|
||||
import thread_cert
|
||||
|
||||
# Test description:
|
||||
# This test verifies network data publisher behavior with DNS/SRP service entries and on-mesh prefix and external
|
||||
# route entries.
|
||||
#
|
||||
# Topology:
|
||||
#
|
||||
# 1 leader, 5 routers and 5 end-devices all connected.
|
||||
#
|
||||
|
||||
LEADER = 1
|
||||
ROUTER1 = 2
|
||||
ROUTER2 = 3
|
||||
ROUTER3 = 4
|
||||
ROUTER4 = 5
|
||||
ROUTER5 = 6
|
||||
END_DEV1 = 7
|
||||
END_DEV2 = 8
|
||||
END_DEV3 = 9
|
||||
END_DEV4 = 10
|
||||
END_DEV5 = 11
|
||||
|
||||
WAIT_TIME = 55
|
||||
|
||||
ON_MESH_PREFIX = 'fd00:1234:0:0::/64'
|
||||
ON_MESH_FLAGS = 'paso'
|
||||
|
||||
EXTERNAL_ROUTE = 'fd00:abce:0:0::/64'
|
||||
EXTERNAL_FLAGS = 's'
|
||||
|
||||
ANYCAST_SEQ_NUM = 4
|
||||
|
||||
DNSSRP_ADDRESS = 'fd00::cdef'
|
||||
DNSSRP_PORT = 49152
|
||||
|
||||
# The desired number of entries (based on related config).
|
||||
DESIRED_NUM_DNSSRP_ANYCAST = 8
|
||||
DESIRED_NUM_DNSSRP_UNICAST = 2
|
||||
DESIRED_NUM_ON_MESH_PREFIX = 3
|
||||
DESIRED_NUM_EXTERNAL_ROUTE = 10
|
||||
|
||||
THREAD_ENTERPRISE_NUMBER = 44970
|
||||
ANYCAST_SERVICE_NUM = 0x5c
|
||||
UNICAST_SERVICE_NUM = 0x5d
|
||||
|
||||
|
||||
class NetDataPublisher(thread_cert.TestCase):
|
||||
USE_MESSAGE_FACTORY = False
|
||||
SUPPORT_NCP = False
|
||||
|
||||
TOPOLOGY = {
|
||||
LEADER: {
|
||||
'name': 'LEADER',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
ROUTER1: {
|
||||
'name': 'ROUTER1',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
ROUTER2: {
|
||||
'name': 'ROUTER2',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
ROUTER3: {
|
||||
'name': 'ROUTER3',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
ROUTER4: {
|
||||
'name': 'ROUTER4',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
ROUTER5: {
|
||||
'name': 'ROUTER5',
|
||||
'mode': 'rdn',
|
||||
},
|
||||
END_DEV1: {
|
||||
'name': 'END_DEV1',
|
||||
'mode': 'rn',
|
||||
},
|
||||
END_DEV2: {
|
||||
'name': 'END_DEV2',
|
||||
'mode': 'rn',
|
||||
},
|
||||
END_DEV3: {
|
||||
'name': 'END_DEV3',
|
||||
'mode': 'rn',
|
||||
},
|
||||
END_DEV4: {
|
||||
'name': 'END_DEV4',
|
||||
'mode': 'rn',
|
||||
},
|
||||
END_DEV5: {
|
||||
'name': 'END_DEV5',
|
||||
'mode': 'rn',
|
||||
},
|
||||
}
|
||||
|
||||
def verify_anycast_service(self, service):
|
||||
# Verify the data in a single anycast `service` from `get_services()`
|
||||
# Example of `service`: ['44970', '5c04', '', 's', 'bc00']
|
||||
self.assertEqual(int(service[0]), THREAD_ENTERPRISE_NUMBER)
|
||||
# Check service data
|
||||
service_data = bytes.fromhex(service[1])
|
||||
self.assertTrue(len(service_data) >= 2)
|
||||
self.assertEqual(service_data[0], ANYCAST_SERVICE_NUM)
|
||||
self.assertEqual(service_data[1], int(ANYCAST_SEQ_NUM))
|
||||
# Verify that it stable
|
||||
self.assertEqual(service[3], 's')
|
||||
|
||||
def verify_anycast_services(self, services):
|
||||
# Verify a list of anycast `services` from `get_services()`
|
||||
for service in services:
|
||||
self.verify_anycast_service(service)
|
||||
|
||||
def verify_unicast_service(self, service):
|
||||
# Verify the data in a single unicast `service` from `get_services()`
|
||||
# Example of `service`: ['44970', '5d', 'fd000db800000000c6b0e5ee81f940e8223d', 's', '7000']
|
||||
self.assertEqual(int(service[0]), THREAD_ENTERPRISE_NUMBER)
|
||||
# Check service data
|
||||
service_data = bytes.fromhex(service[1])
|
||||
self.assertTrue(len(service_data) >= 1)
|
||||
self.assertEqual(service_data[0], UNICAST_SERVICE_NUM)
|
||||
# Verify that it stable
|
||||
self.assertEqual(service[3], 's')
|
||||
|
||||
def verify_unicast_services(self, services):
|
||||
# Verify a list of unicast `services` from `get_services()`
|
||||
for service in services:
|
||||
self.verify_unicast_service(service)
|
||||
|
||||
def check_num_of_prefixes(self, prefixes, num_low, num_med, num_high):
|
||||
# Check and validate the prefix entries in network data (from
|
||||
# `prefixes`) based on number of published prefix entries at
|
||||
# different preference levels given by `num_low`, `num_med`,
|
||||
# `num_high`. Prefixes is a list of the format
|
||||
# 'fd00:1234:0:0::/64 paos low a802'.
|
||||
self.assertEqual(len(prefixes), min(num_high + num_med + num_low, DESIRED_NUM_ON_MESH_PREFIX))
|
||||
prfs = [prefix.split(' ')[2] for prefix in prefixes]
|
||||
self.assertEqual(prfs.count('high'), min(num_high, DESIRED_NUM_ON_MESH_PREFIX))
|
||||
self.assertEqual(prfs.count('med'), min(num_med, max(0, DESIRED_NUM_ON_MESH_PREFIX - num_high)))
|
||||
self.assertEqual(prfs.count('low'), min(num_low, max(0, DESIRED_NUM_ON_MESH_PREFIX - num_high - num_med)))
|
||||
|
||||
def check_num_of_routes(self, routes, num_low, num_med, num_high):
|
||||
# Check and validate the prefix entries in network data (from
|
||||
# `routes`) based on number of published prefix entries at
|
||||
# different preference levels given by `num_low`, `num_med`,
|
||||
# `num_high`. Prefixes is a list of the format
|
||||
# 'fd00:abce:0:0::/64 s med 6c01'.
|
||||
self.assertEqual(len(routes), min(num_high + num_med + num_low, DESIRED_NUM_EXTERNAL_ROUTE))
|
||||
prfs = [route.split(' ')[2] for route in routes]
|
||||
self.assertEqual(prfs.count('high'), min(num_high, DESIRED_NUM_EXTERNAL_ROUTE))
|
||||
self.assertEqual(prfs.count('med'), min(num_med, max(0, DESIRED_NUM_EXTERNAL_ROUTE - num_high)))
|
||||
self.assertEqual(prfs.count('low'), min(num_low, max(0, DESIRED_NUM_EXTERNAL_ROUTE - num_high - num_med)))
|
||||
|
||||
def test(self):
|
||||
leader = self.nodes[LEADER]
|
||||
router1 = self.nodes[ROUTER1]
|
||||
router2 = self.nodes[ROUTER2]
|
||||
router3 = self.nodes[ROUTER3]
|
||||
router4 = self.nodes[ROUTER4]
|
||||
router5 = self.nodes[ROUTER5]
|
||||
end_dev1 = self.nodes[END_DEV1]
|
||||
end_dev2 = self.nodes[END_DEV2]
|
||||
end_dev3 = self.nodes[END_DEV3]
|
||||
end_dev4 = self.nodes[END_DEV4]
|
||||
end_dev5 = self.nodes[END_DEV5]
|
||||
|
||||
nodes = self.nodes.values()
|
||||
routers = [router1, router2, router3, router4, router5]
|
||||
end_devs = [end_dev1, end_dev2, end_dev3, end_dev4, end_dev5]
|
||||
|
||||
# Start the nodes
|
||||
|
||||
leader.start()
|
||||
self.simulator.go(config.LEADER_STARTUP_DELAY)
|
||||
self.assertEqual(leader.get_state(), 'leader')
|
||||
|
||||
for router in routers:
|
||||
router.start()
|
||||
self.simulator.go(config.ROUTER_STARTUP_DELAY)
|
||||
self.assertEqual(router.get_state(), 'router')
|
||||
|
||||
for end_dev in end_devs:
|
||||
end_dev.start()
|
||||
self.simulator.go(5)
|
||||
self.assertEqual(end_dev.get_state(), 'child')
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP anycast entries - equal version number
|
||||
|
||||
# Publish DNS/SRP anycast on leader and all routers (6 nodes).
|
||||
|
||||
leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
|
||||
for node in routers:
|
||||
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
|
||||
# Check all entries are present in the network data
|
||||
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(1 + len(routers), DESIRED_NUM_DNSSRP_ANYCAST))
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
# Publish same entry on all end-devices (5 nodes).
|
||||
|
||||
for node in end_devs:
|
||||
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
|
||||
print(node.name)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
|
||||
# Check number of entries in the network data is limited to
|
||||
# the desired number (8 entries).
|
||||
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(leader.get_services()), min(len(nodes), DESIRED_NUM_DNSSRP_ANYCAST))
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
# Unpublish the entry from nodes one by one starting from leader
|
||||
# and check that number of entries is correct in each step.
|
||||
|
||||
num = len(nodes)
|
||||
for node in nodes:
|
||||
node.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num -= 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP anycast entries - different version numbers
|
||||
|
||||
# Publish DNS/SRP anycast on leader and all routers (6 nodes).
|
||||
|
||||
version = 0
|
||||
leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version)
|
||||
num = 1
|
||||
|
||||
for node in routers:
|
||||
version += 1
|
||||
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version)
|
||||
num += 1
|
||||
|
||||
self.simulator.go(WAIT_TIME)
|
||||
|
||||
# Check all entries are present in the network data
|
||||
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
# Publish same entry with same version on all end-devices (5 nodes).
|
||||
|
||||
for node in end_devs:
|
||||
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version)
|
||||
num += 1
|
||||
print(node.name)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
# Check number of entries in the network data is limited
|
||||
# to the desired number (8 entries). All new entries use
|
||||
# higher version and should be preferred. Validate that
|
||||
# the 'services' list contains the new services.
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
|
||||
self.verify_anycast_services(services)
|
||||
node_rloc16 = node.get_addr16()
|
||||
self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services))
|
||||
|
||||
# Unpublish the entry from nodes one by one starting from leader
|
||||
# and check that number of entries is correct in each step.
|
||||
|
||||
for node in nodes:
|
||||
node.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num -= 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST))
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP service data unicast entries - equal version number
|
||||
|
||||
num = 0
|
||||
for node in routers:
|
||||
node.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
for node in routers:
|
||||
node.srp_server_set_enabled(True)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
|
||||
self.assertEqual(sum(node.srp_server_get_state() == 'running' for node in routers),
|
||||
min(len(routers), DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.assertEqual(sum(node.srp_server_get_state() == 'stopped' for node in routers),
|
||||
max(len(routers) - DESIRED_NUM_DNSSRP_UNICAST, 0))
|
||||
|
||||
for node in routers:
|
||||
node.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num -= 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
for node in routers:
|
||||
node.srp_server_set_enabled(False)
|
||||
self.assertEqual(node.srp_server_get_state(), 'disabled')
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP service data unicast entries - different version numbers
|
||||
|
||||
num = 0
|
||||
for node in routers:
|
||||
# Use `num` as version.
|
||||
node.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT, num)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
# The most recent service should win as it uses a higher version
|
||||
# number. Validate that the 'services' list contains the service
|
||||
# from this node by checking the service RLOC16.
|
||||
node_rloc16 = node.get_addr16()
|
||||
self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services))
|
||||
|
||||
for node in reversed(routers):
|
||||
node.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num -= 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP server data unicast entries - equal version number
|
||||
|
||||
num = 0
|
||||
for node in routers:
|
||||
node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
for node in routers:
|
||||
node.srp_server_set_enabled(True)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
self.assertEqual(sum(node.srp_server_get_state() == 'running' for node in routers),
|
||||
min(len(routers), DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.assertEqual(sum(node.srp_server_get_state() == 'stopped' for node in routers),
|
||||
max(len(routers) - DESIRED_NUM_DNSSRP_UNICAST, 0))
|
||||
|
||||
for node in routers:
|
||||
node.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num -= 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
for node in routers:
|
||||
node.srp_server_set_enabled(False)
|
||||
self.assertEqual(node.srp_server_get_state(), 'disabled')
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP server data unicast entries - different version numbers
|
||||
|
||||
num = 0
|
||||
for node in routers:
|
||||
node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT, num)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
# The most recent service should win as it uses a higher version
|
||||
# number. Validate that the 'services' list contains the service
|
||||
# from this node by checking the service RLOC16.
|
||||
node_rloc16 = node.get_addr16()
|
||||
self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services))
|
||||
|
||||
for node in reversed(routers):
|
||||
node.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num -= 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
# Repeat the same test steps, but start with larger version
|
||||
# numbers first.
|
||||
|
||||
num = 0
|
||||
for node in routers:
|
||||
node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT, 20 - num)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
# The service from first router should win as it uses the highest
|
||||
# version number.
|
||||
first_router_rloc16 = routers[0].get_addr16()
|
||||
self.assertTrue(any(int(service[4], 16) == first_router_rloc16 for service in services))
|
||||
|
||||
for node in routers:
|
||||
node.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num -= 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP server data unicast vs anycast
|
||||
|
||||
num = 0
|
||||
for node in routers:
|
||||
node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
# Verify that publishing an anycast entry will update the
|
||||
# limit for the server data unicast address entry and all are
|
||||
# removed quickly. We validate this by waiting for a short
|
||||
# time (15 msec) after publishing anycast.
|
||||
|
||||
leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
|
||||
self.simulator.go(15)
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), 1)
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
# Removing the anycast entry will cause the lower priority
|
||||
# server data unicast entries to be added again.
|
||||
|
||||
leader.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP server data unicast vs service data unicast
|
||||
|
||||
leader.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), 1)
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
# Removing the service data unicast entry will cause the lower
|
||||
# priority server data unicast entries to be added again.
|
||||
|
||||
leader.netdata_unpublish_dnssrp()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST))
|
||||
self.verify_unicast_services(services)
|
||||
|
||||
for node in routers:
|
||||
node.netdata_unpublish_dnssrp()
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# DNS/SRP entries: Verify publisher preference when removing
|
||||
# entries.
|
||||
#
|
||||
# Publish DNS/SRP anycast on 8 nodes: leader, router1,
|
||||
# router2, and all 5 end-devices. Afterwards, manually add
|
||||
# the same service entry in Network Data on router3, router4,
|
||||
# and router5 and at each step check that entry from one of
|
||||
# the end-devices is removed (publisher prefers
|
||||
# entries from routers over the ones from end-devices).
|
||||
|
||||
num = 0
|
||||
test_routers = [leader, router1, router2]
|
||||
for node in test_routers + end_devs:
|
||||
node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), num)
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
self.assertEqual(num, DESIRED_NUM_DNSSRP_ANYCAST)
|
||||
|
||||
service_data = '%02x%02x' % (ANYCAST_SERVICE_NUM, int(ANYCAST_SEQ_NUM))
|
||||
for node in [router3, router4, router5]:
|
||||
node.add_service(str(THREAD_ENTERPRISE_NUMBER), service_data, '00')
|
||||
node.register_netdata()
|
||||
self.simulator.go(WAIT_TIME)
|
||||
|
||||
services = leader.get_services()
|
||||
self.assertEqual(len(services), num)
|
||||
self.verify_anycast_services(services)
|
||||
|
||||
service_rlocs = [int(service[4], 16) for service in services]
|
||||
test_routers.append(node)
|
||||
|
||||
for router in test_routers:
|
||||
self.assertIn(router.get_addr16(), service_rlocs)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# On-mesh prefix
|
||||
|
||||
# Publish the same on-mesh prefix on different nodes (low
|
||||
# preference on end-devices, medium preference on routers, and
|
||||
# high on leader) one by one and then unpublish them one by one.
|
||||
# Verify that at each step the entries in the network data are
|
||||
# correct. Particularly verify that that higher preference
|
||||
# entries replace lower preference ones even when there are
|
||||
# already desired number in network data.
|
||||
|
||||
num_low = 0
|
||||
num_med = 0
|
||||
num_high = 0
|
||||
|
||||
for node in end_devs:
|
||||
node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'low')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num_low += 1
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
|
||||
|
||||
# Now add the entry as 'med' on routers and check that we see those in the list.
|
||||
for node in routers:
|
||||
node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num_med += 1
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
|
||||
|
||||
leader.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'high')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num_high += 1
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
|
||||
|
||||
for node in routers:
|
||||
node.netdata_unpublish_prefix(ON_MESH_PREFIX)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num_med -= 1
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
|
||||
|
||||
leader.netdata_unpublish_prefix(ON_MESH_PREFIX)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num_high -= 1
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
|
||||
|
||||
for node in end_devs:
|
||||
node.netdata_unpublish_prefix(ON_MESH_PREFIX)
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num_low -= 1
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, num_low, num_med, num_high)
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# Verify that when removing extra entries, non-preferred entries
|
||||
# are removed first over preferred ones. Entries from routers are
|
||||
# preferred over similar entries from end-devices.
|
||||
|
||||
# Publish prefix entry on `end_dev1` and verify that it is added.
|
||||
|
||||
end_dev1.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, 0, 1, 0)
|
||||
|
||||
# Publish same prefix on all routers (again as `med` preference).
|
||||
# Verify that we reach the desired number of prefix entries in network
|
||||
# data and that the entry from `end_dev1` is present in network data.
|
||||
|
||||
for node in routers:
|
||||
node.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'med')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, 0, 1 + len(routers), 0)
|
||||
self.assertTrue(1 + len(routers) >= DESIRED_NUM_ON_MESH_PREFIX)
|
||||
# `prefixes` is a list of format 'fd00:1234:0:0::/64 paos low a802'
|
||||
rlocs = [int(prefix.split(' ')[3], 16) for prefix in prefixes]
|
||||
self.assertTrue(rlocs.count(end_dev1.get_addr16()) == 1)
|
||||
|
||||
# Publish same prefix now with `high` preference on leader.
|
||||
# Since it is `high` preference, it is added to network data
|
||||
# which leads to total number of entries to go above the desired
|
||||
# number temporarily and trigger other nodes to try to remove
|
||||
# their entry. The entries from routers should be preferred over
|
||||
# the one from `end_dev1` so that is the one we expect to be
|
||||
# removed. We check that this is the case (i.e., the entry from
|
||||
# `end_dev1` is no longer present in network data).
|
||||
|
||||
leader.netdata_publish_prefix(ON_MESH_PREFIX, ON_MESH_FLAGS, 'high')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
prefixes = leader.get_prefixes()
|
||||
self.check_num_of_prefixes(prefixes, 0, 1 + len(routers), 1)
|
||||
rlocs = [int(prefix.split(' ')[3], 16) for prefix in prefixes]
|
||||
self.assertTrue(rlocs.count(end_dev1.get_addr16()) == 0)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# External route
|
||||
|
||||
# Publish same external route on all nodes with low preference.
|
||||
|
||||
num = 0
|
||||
for node in nodes:
|
||||
node.netdata_publish_route(EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'low')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
num += 1
|
||||
routes = leader.get_routes()
|
||||
self.check_num_of_routes(routes, num, 0, 0)
|
||||
|
||||
# Change the preference level of the existing entry on leader to high.
|
||||
|
||||
leader.netdata_publish_route(EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'high')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
routes = leader.get_routes()
|
||||
self.check_num_of_routes(routes, num - 1, 0, 1)
|
||||
|
||||
# Replace the published route on leader with '::/0'.
|
||||
leader.netdata_publish_replace(EXTERNAL_ROUTE, '::/0', EXTERNAL_FLAGS, 'med')
|
||||
self.simulator.go(1)
|
||||
routes = leader.get_routes()
|
||||
self.assertEqual([route.split(' ')[0] == '::/0' for route in routes].count(True), 1)
|
||||
|
||||
# Replace it back to the original route.
|
||||
leader.netdata_publish_replace('::/0', EXTERNAL_ROUTE, EXTERNAL_FLAGS, 'high')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
routes = leader.get_routes()
|
||||
self.assertEqual([route.split(' ')[0] == '::/0' for route in routes].count(True), 0)
|
||||
self.check_num_of_routes(routes, num - 1, 0, 1)
|
||||
|
||||
# Publish the same prefix on leader as an on-mesh prefix. Make
|
||||
# sure it is removed from external routes and now seen in the
|
||||
# prefix list.
|
||||
|
||||
leader.netdata_publish_prefix(EXTERNAL_ROUTE, ON_MESH_FLAGS, 'low')
|
||||
self.simulator.go(WAIT_TIME)
|
||||
routes = leader.get_routes()
|
||||
self.check_num_of_routes(routes, num - 1, 0, 0)
|
||||
|
||||
prefixes = leader.get_prefixes()
|
||||
print(prefixes)
|
||||
self.assertIn(EXTERNAL_ROUTE, [prefix.split()[0] for prefix in prefixes])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user