[netdata] add feature for BR to request router role upgrade (#7597)

This commit adds a new mechanism to allow border routers to request
router role upgrade.

A border router which provides IP connectivity (either adding an
external route prefix or an on-mesh prefix with default route flag)
and is acting as a REED is eligible to request a router role upgrade
by sending an "Address Solicit" request to leader with status reason
`BorderRouterRequest`. This reason is used when the number of active
routers in the Thread mesh is above the threshold, and only if the
number of existing eligible BRs (determined from the network data)
that are acting as router is less than two. This mechanism  allows up
to two eligible border routers to request router role upgrade when
the number of routers is already above the threshold.

This commit also adds a new test-case `test_br_upgrade_router_role`
which validates the behavior of the new mechanism.
This commit is contained in:
Abtin Keshavarzian 2022-06-22 11:45:30 -07:00 committed by GitHub
parent 4164a5029d
commit 64e837861f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 452 additions and 20 deletions

View File

@ -94,6 +94,13 @@ void TimeTicker::HandleTimer(void)
Get<AddressResolver>().HandleTimeTick();
}
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
if (mReceivers & Mask(kNetworkDataNotifier))
{
Get<NetworkData::Notifier>().HandleTimeTick();
}
#endif
#if OPENTHREAD_CONFIG_CHILD_SUPERVISION_ENABLE
if (mReceivers & Mask(kChildSupervisor))
{

View File

@ -71,6 +71,7 @@ public:
kIp6FragmentReassembler, ///< `Ip6::Ip6` (handling of fragmented messages)
kDuaManager, ///< `DuaManager`
kMlrManager, ///< `MlrManager`
kNetworkDataNotifier, ///< `NetworkData::Notifier`
kNumReceivers, ///< Number of receivers.
};

View File

@ -55,6 +55,32 @@
#define OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 0
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
*
* Define to 1 to enable mechanism on a Border Router which provides IP connectivity to request router role upgrade.
*
* This config is applicable on an `OPENTHREAD_FTD` build and when `OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE` is also
* enabled.
*
* A Border Router is considered to provide external IP connectivity if at least one of the below conditions hold:
*
* - It has added at least one external route entry.
* - It has added at least one prefix entry with default-route and on-mesh flags set.
* - It has added at least one domain prefix (domain and on-mesh flags set).
*
* A Border Router which provides IP connectivity and is acting as a REED is eligible to request a router role upgrade
* by sending an "Address Solicit" request to leader with status reason `BorderRouterRequest`. This reason is used when
* the number of active routers in the Thread mesh is above the threshold, and only if the number of existing eligible
* BRs (determined from the Thread Network Data) that are acting as router is less than two. This mechanism allows up
* to two eligible Border Routers to request router role upgrade when the number of routers is already above the
* threshold.
*
*/
#ifndef OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
#define OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE 1
#endif
/**
* @def OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
*

View File

@ -1453,7 +1453,11 @@ Error MleRouter::HandleAdvertisement(RxInfo &aRxInfo)
if (routerCount > mRouterDowngradeThreshold && mRouterSelectionJitterTimeout == 0 &&
HasMinDowngradeNeighborRouters() && HasSmallNumberOfChildren() &&
HasOneNeighborWithComparableConnectivity(route, routerId))
HasOneNeighborWithComparableConnectivity(route, routerId)
#if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
&& !Get<NetworkData::Notifier>().IsEligibleForRouterRoleUpgradeAsBorderRouter()
#endif
)
{
mRouterSelectionJitterTimeout = 1 + Random::NonCrypto::GetUint8InRange(0, mRouterSelectionJitter);
}
@ -3920,7 +3924,7 @@ void MleRouter::HandleAddressSolicit(Coap::Message &aMessage, const Ip6::Message
case ThreadStatusTlv::kParentPartitionChange:
break;
case ThreadStatusTlv::kBorderRouterRequst:
case ThreadStatusTlv::kBorderRouterRequest:
if ((mRouterTable.GetActiveRouterCount() >= mRouterUpgradeThreshold) &&
(Get<NetworkData::Leader>().CountBorderRouters(NetworkData::kRouterRoleOnly) >=
kRouterUpgradeBorderRouterRequestThreshold))

View File

@ -585,7 +585,7 @@ private:
static constexpr uint16_t kUnsolicitedDataResponseJitter = 500; // Max delay for unsol Data Response (in msec).
// Threshold to accept a router upgrade request with reason
// `kBorderRouterRequst` (number of BRs acting as router in
// `kBorderRouterRequest` (number of BRs acting as router in
// Network Data).
static constexpr uint8_t kRouterUpgradeBorderRouterRequestThreshold = 2;

View File

@ -162,6 +162,13 @@ constexpr uint8_t kRouterSelectionJitter = 120; ///< (in sec)
constexpr uint8_t kRouterDowngradeThreshold = 23;
constexpr uint8_t kRouterUpgradeThreshold = 16;
/**
* Threshold to accept a router upgrade request with reason `kBorderRouterRequest` (number of BRs acting as router in
* Network Data).
*
*/
constexpr uint8_t kRouterUpgradeBorderRouterRequestThreshold = 2;
constexpr uint32_t kMaxLeaderToRouterTimeout = 90; ///< (in sec)
constexpr uint32_t kReedAdvertiseInterval = 570; ///< (in sec)
constexpr uint32_t kReedAdvertiseJitter = 60; ///< (in sec)

View File

@ -814,5 +814,34 @@ uint8_t NetworkData::CountBorderRouters(RoleFilter aRoleFilter) const
return rlocsLength;
}
bool NetworkData::ContainsBorderRouterWithRloc(uint16_t aRloc16) const
{
bool contains = false;
Iterator iterator = kIteratorInit;
ExternalRouteConfig route;
OnMeshPrefixConfig prefix;
while (GetNextExternalRoute(iterator, route) == kErrorNone)
{
if (route.mRloc16 == aRloc16)
{
ExitNow(contains = true);
}
}
iterator = kIteratorInit;
while (GetNextOnMeshPrefix(iterator, prefix) == kErrorNone)
{
if ((prefix.mRloc16 == aRloc16) && prefix.mOnMesh && (prefix.mDefaultRoute || prefix.mDp))
{
ExitNow(contains = true);
}
}
exit:
return contains;
}
} // namespace NetworkData
} // namespace ot

View File

@ -325,9 +325,9 @@ public:
Error GetNextServer(Iterator &aIterator, uint16_t &aRloc16) const;
/**
* This method finds and returns the list of RLOCs of border routers providing external IPv6 connectivity.
* This method finds and returns the list of RLOCs of border routers providing external IP connectivity.
*
* A border router is considered to provide external IPv6 connectivity if it has added at least one external route
* A border router is considered to provide external IP connectivity if it has added at least one external route
* entry, or an on-mesh prefix with default-route and on-mesh flags set.
*
* This method should be used when the RLOC16s are present in the Network Data (when the Network Data contains the
@ -346,10 +346,13 @@ public:
Error FindBorderRouters(RoleFilter aRoleFilter, uint16_t aRlocs[], uint8_t &aRlocsLength) const;
/**
* This method counts the number of border routers providing external IPv6 connectivity.
* This method counts the number of border routers providing external IP connectivity.
*
* A border router is considered to provide external IPv6 connectivity if it has added at least one external route
* entry, or an on-mesh prefix with default-route and on-mesh flags set.
* A border router is considered to provide external IP connectivity if at least one of the below conditions hold
*
* - It has added at least one external route entry.
* - It has added at least one prefix entry with default-route and on-mesh flags set.
* - It has added at least one domain prefix (domain and on-mesh flags set).
*
* This method should be used when the RLOC16s are present in the Network Data (when the Network Data contains the
* full set and not the stable subset).
@ -361,6 +364,27 @@ public:
*/
uint8_t CountBorderRouters(RoleFilter aRoleFilter) const;
/**
* This method indicates whether the network data contains a border providing external IP connectivity with a given
* RLOC16.
*
* A border router is considered to provide external IP connectivity if at least one of the below conditions hold
*
* - It has added at least one external route entry.
* - It has added at least one prefix entry with default-route and on-mesh flags set.
* - It has added at least one domain prefix (domain and on-mesh flags set).
*
* This method should be used when the RLOC16s are present in the Network Data (when the Network Data contains the
* full set and not the stable subset).
*
* @param[in] aRloc16 The RLOC16 to check.
*
* @returns TRUE If the network data contains a border router with @p aRloc16 providing IP connectivity.
* @returns FALSE If the network data does not contain a border router with @p aRloc16 providing IP connectivity.
*
*/
bool ContainsBorderRouterWithRloc(uint16_t aRloc16) const;
protected:
/**
* This enumeration defines Service Data match mode.

View File

@ -38,23 +38,35 @@
#include "common/code_utils.hpp"
#include "common/instance.hpp"
#include "common/locator_getters.hpp"
#include "common/log.hpp"
#include "thread/network_data_leader.hpp"
#include "thread/network_data_local.hpp"
namespace ot {
namespace NetworkData {
RegisterLogModule("NetworkData");
Notifier::Notifier(Instance &aInstance)
: InstanceLocator(aInstance)
, mTimer(aInstance, HandleTimer)
, mSynchronizeDataTask(aInstance, HandleSynchronizeDataTask)
, mNextDelay(0)
, mWaitingForResponse(false)
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
, mDidRequestRouterRoleUpgrade(false)
, mRouterRoleUpgradeTimeout(0)
#endif
{
}
void Notifier::HandleServerDataUpdated(void)
{
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
mDidRequestRouterRoleUpgrade = false;
ScheduleRouterRoleUpgradeIfEligible();
#endif
mNextDelay = 0;
mSynchronizeDataTask.Post();
}
@ -113,6 +125,18 @@ void Notifier::HandleNotifierEvents(Events aEvents)
mNextDelay = 0;
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
if (aEvents.Contains(kEventThreadPartitionIdChanged))
{
mDidRequestRouterRoleUpgrade = false;
}
if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadNetdataChanged | kEventThreadPartitionIdChanged))
{
ScheduleRouterRoleUpgradeIfEligible();
}
#endif
if (aEvents.ContainsAny(kEventThreadNetdataChanged | kEventThreadRoleChanged | kEventThreadChildRemoved))
{
SynchronizeServerData();
@ -158,6 +182,90 @@ void Notifier::HandleCoapResponse(Error aResult)
}
}
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
bool Notifier::IsEligibleForRouterRoleUpgradeAsBorderRouter(void) const
{
bool isEligible = false;
uint16_t rloc16 = Get<Mle::Mle>().GetRloc16();
uint8_t activeRouterCount;
VerifyOrExit(Get<Mle::MleRouter>().IsRouterEligible());
// RouterUpgradeThreshold can be explicitly set to zero in some of
// cert tests to disallow device to become router.
VerifyOrExit(Get<Mle::MleRouter>().GetRouterUpgradeThreshold() != 0);
// Check that we are a border router providing IP connectivity and already
// in the leader's network data and therefore eligible to request router
// role upgrade with `kBorderRouterRequest` status.
VerifyOrExit(Get<Local>().ContainsBorderRouterWithRloc(rloc16) &&
Get<Leader>().ContainsBorderRouterWithRloc(rloc16));
activeRouterCount = Get<RouterTable>().GetActiveRouterCount();
VerifyOrExit((activeRouterCount >= Get<Mle::MleRouter>().GetRouterUpgradeThreshold()) &&
(activeRouterCount < Mle::kMaxRouters));
VerifyOrExit(Get<Leader>().CountBorderRouters(kRouterRoleOnly) < Mle::kRouterUpgradeBorderRouterRequestThreshold);
isEligible = true;
exit:
return isEligible;
}
void Notifier::ScheduleRouterRoleUpgradeIfEligible(void)
{
// We allow device to request router role upgrade using status
// reason `kBorderRouterRequest` once while its local network data
// remains unchanged. This ensures if the leader is running an
// older version of Thread stack which does not support
// `kBorderRouterRequest` reason, we do not keep trying (on no
// response). The boolean `mDidRequestRouterRoleUpgrade` tracks
// this. It is set to `false` when local network data gets changed
// or when partition ID gets changed (indicating a potential
// leader change).
VerifyOrExit(!mDidRequestRouterRoleUpgrade);
VerifyOrExit(Get<Mle::MleRouter>().IsChild());
VerifyOrExit(IsEligibleForRouterRoleUpgradeAsBorderRouter() && (mRouterRoleUpgradeTimeout == 0));
mRouterRoleUpgradeTimeout = Random::NonCrypto::GetUint8InRange(1, kRouterRoleUpgradeMaxTimeout + 1);
Get<TimeTicker>().RegisterReceiver(TimeTicker::kNetworkDataNotifier);
exit:
return;
}
void Notifier::HandleTimeTick(void)
{
VerifyOrExit(mRouterRoleUpgradeTimeout > 0);
mRouterRoleUpgradeTimeout--;
if (mRouterRoleUpgradeTimeout == 0)
{
Get<TimeTicker>().UnregisterReceiver(TimeTicker::kNetworkDataNotifier);
// Check that we are still eligible for requesting router role
// upgrade (note that state can change since the last time we
// checked and registered to receive time ticks).
if (Get<Mle::MleRouter>().IsChild() && IsEligibleForRouterRoleUpgradeAsBorderRouter())
{
LogInfo("Requesting router role as BR");
mDidRequestRouterRoleUpgrade = true;
IgnoreError(Get<Mle::MleRouter>().BecomeRouter(ThreadStatusTlv::kBorderRouterRequest));
}
}
exit:
return;
}
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE &&
// OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
} // namespace NetworkData
} // namespace ot

View File

@ -43,6 +43,7 @@
#include "common/non_copyable.hpp"
#include "common/notifier.hpp"
#include "common/tasklet.hpp"
#include "common/time_ticker.hpp"
namespace ot {
namespace NetworkData {
@ -54,6 +55,7 @@ namespace NetworkData {
class Notifier : public InstanceLocator, private NonCopyable
{
friend class ot::Notifier;
friend class ot::TimeTicker;
public:
/**
@ -74,10 +76,33 @@ public:
*/
void HandleServerDataUpdated(void);
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
/**
* This method indicates whether the device as border router is eligible for router role upgrade request using the
* status reason `kBorderRouterRequest`.
*
* This method checks whether device is providing IP connectivity and that there are fewer than two border routers
* in network data acting as router. Device is considered to provide external IP connectivity if at least one of
* the below conditions hold:
*
* - It has added at least one external route entry.
* - It has added at least one prefix entry with default-route and on-mesh flags set.
* - It has added at least one domain prefix (domain and on-mesh flags set).
*
* This method does not check the current role of device.
*
* @retval TRUE Device is eligible to request router role upgrade as a border router.
* @retval FALSE Device is not eligible to request router role upgrade as a border router.
*
*/
bool IsEligibleForRouterRoleUpgradeAsBorderRouter(void) const;
#endif
private:
static constexpr uint32_t kDelayNoBufs = 1000; // in msec
static constexpr uint32_t kDelayRemoveStaleChildren = 5000; // in msec
static constexpr uint32_t kDelaySynchronizeServerData = 300000; // in msec
static constexpr uint32_t kDelayNoBufs = 1000; // in msec
static constexpr uint32_t kDelayRemoveStaleChildren = 5000; // in msec
static constexpr uint32_t kDelaySynchronizeServerData = 300000; // in msec
static constexpr uint8_t kRouterRoleUpgradeMaxTimeout = 10; // in sec
void HandleNotifierEvents(Events aEvents);
@ -93,11 +118,20 @@ private:
static void HandleSynchronizeDataTask(Tasklet &aTasklet);
void SynchronizeServerData(void);
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
void ScheduleRouterRoleUpgradeIfEligible(void);
void HandleTimeTick(void);
#endif
TimerMilli mTimer;
Tasklet mSynchronizeDataTask;
uint32_t mNextDelay;
bool mWaitingForResponse;
bool mWaitingForResponse : 1;
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE && OPENTHREAD_CONFIG_BORDER_ROUTER_REQUEST_ROUTER_ROLE
bool mDidRequestRouterRoleUpgrade : 1;
uint8_t mRouterRoleUpgradeTimeout;
#endif
};
} // namespace NetworkData

View File

@ -166,7 +166,7 @@ public:
kTooFewRouters = 2, ///< Address Solicit due to too few routers.
kHaveChildIdRequest = 3, ///< Address Solicit due to child ID request.
kParentPartitionChange = 4, ///< Address Solicit due to parent partition change
kBorderRouterRequst = 5, ///< Address Solicit from Border Router request.
kBorderRouterRequest = 5, ///< Address Solicit from Border Router request.
kUnrecognizedStatus = 6, ///< The requested status is unrecognized or not meaningful in a request.
};

View File

@ -153,6 +153,7 @@ EXTRA_DIST = \
sniffer_transport.py \
test_anycast.py \
test_anycast_locator.py \
test_br_upgrade_router_role.py \
test_coap.py \
test_coap_block.py \
test_coap_observe.py \
@ -232,6 +233,7 @@ check_PROGRAMS = \
check_SCRIPTS = \
test_anycast.py \
test_anycast_locator.py \
test_br_upgrade_router_role.py \
test_coap.py \
test_coap_block.py \
test_coap_observe.py \

View File

@ -0,0 +1,157 @@
#!/usr/bin/env python3
#
# Copyright (c) 2022, 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 thread_cert
# Test description:
#
# This test verifies behavior of Border Routers (which provide IP connectivity) requesting router role within Thread
# mesh.
# Topology:
#
# 5 FTD nodes, all connected.
#
# Topology is expected to change during execution of test.
#
LEADER = 1
ROUTER = 2
BR1 = 3
BR2 = 4
BR3 = 5
class BrUpgradeRouterRole(thread_cert.TestCase):
USE_MESSAGE_FACTORY = False
SUPPORT_NCP = False
TOPOLOGY = {
LEADER: {
'name': 'leader',
'mode': 'rdn',
},
ROUTER: {
'name': 'reader',
'mode': 'rdn',
},
BR1: {
'name': 'br-1',
'mode': 'rdn',
},
BR2: {
'name': 'br-2',
'mode': 'rdn',
},
BR3: {
'name': 'br-3',
'mode': 'rdn',
},
}
def test(self):
leader = self.nodes[LEADER]
router = self.nodes[ROUTER]
br1 = self.nodes[BR1]
br2 = self.nodes[BR2]
br3 = self.nodes[BR3]
#-------------------------------------------------------------------------------------
# Set the router upgrade threshold to 2 on all nodes.
for node in [leader, router, br1, br2, br3]:
node.set_router_upgrade_threshold(2)
#-------------------------------------------------------------------------------------
# Start the leader and router.
leader.start()
self.simulator.go(10)
self.assertEqual(leader.get_state(), 'leader')
router.start()
self.simulator.go(125)
self.assertEqual(router.get_state(), 'router')
#-------------------------------------------------------------------------------------
# Start all three BRs, we expect all to stay as child since there are already two
# routers in the Thread mesh.
br1.start()
br2.start()
br3.start()
self.simulator.go(125)
self.assertEqual(br1.get_state(), 'child')
self.assertEqual(br2.get_state(), 'child')
self.assertEqual(br3.get_state(), 'child')
#-------------------------------------------------------------------------------------
# Add an external route on `br1`, it should now try to become a router requesting
# with status BorderRouterRequest. Verify that leader allows it to become router.
br1.add_route('2001:dead:beef:cafe::/64', stable=True)
br1.register_netdata()
self.simulator.go(15)
self.assertEqual(br1.get_state(), 'router')
#-------------------------------------------------------------------------------------
# Add a prefix with default route on `br2`, it should also become a router.
br2.add_prefix('2001:dead:beef:2222::/64', 'paros')
br2.register_netdata()
self.simulator.go(15)
self.assertEqual(br2.get_state(), 'router')
#-------------------------------------------------------------------------------------
# Add an external route on `br3`, it should not become a router since we already have
# two that requested router role upgrade as border router reason.
br3.add_route('2001:dead:beef:cafe::/64', stable=True)
br3.register_netdata()
self.simulator.go(120)
self.assertEqual(br3.get_state(), 'child')
#-------------------------------------------------------------------------------------
# Remove the external route on `br1`. This should now trigger `br3` to request a
# router role upgrade since number of BRs acting as router in network data is now
# below the threshold of two.
br1.remove_route('2001:dead:beef:cafe::/64')
br1.register_netdata()
self.simulator.go(15)
self.assertEqual(br1.get_state(), 'router')
self.assertEqual(br3.get_state(), 'router')
if __name__ == '__main__':
unittest.main()

View File

@ -149,7 +149,8 @@ void TestNetworkDataIterator(void)
},
};
const uint16_t kRlocs[] = {0xc800, 0x5400};
const uint16_t kRlocs[] = {0xc800, 0x5400};
const uint16_t kNonExistingRlocs[] = {0xc700, 0x0000, 0x5401};
NetworkData netData(*instance, kNetworkData, sizeof(kNetworkData));
@ -179,6 +180,16 @@ void TestNetworkDataIterator(void)
SuccessOrQuit(netData.FindBorderRouters(kChildRoleOnly, rlocs, rlocsLength));
VerifyOrQuit(rlocsLength == 0);
VerifyOrQuit(netData.CountBorderRouters(kChildRoleOnly) == 0);
for (uint16_t rloc16 : kRlocs)
{
VerifyOrQuit(netData.ContainsBorderRouterWithRloc(rloc16));
}
for (uint16_t rloc16 : kNonExistingRlocs)
{
VerifyOrQuit(!netData.ContainsBorderRouterWithRloc(rloc16));
}
}
{
@ -252,9 +263,10 @@ void TestNetworkDataIterator(void)
},
};
const uint16_t kRlocsAnyRole[] = {0x1000, 0x5400, 0x0401};
const uint16_t kRlocsRouterRole[] = {0x1000, 0x5400};
const uint16_t kRlocsChildRole[] = {0x0401};
const uint16_t kRlocsAnyRole[] = {0x1000, 0x5400, 0x0401};
const uint16_t kRlocsRouterRole[] = {0x1000, 0x5400};
const uint16_t kRlocsChildRole[] = {0x0401};
const uint16_t kNonExistingRlocs[] = {0x6000, 0x0000, 0x0402};
NetworkData netData(*instance, kNetworkData, sizeof(kNetworkData));
@ -297,6 +309,16 @@ void TestNetworkDataIterator(void)
rlocsLength = GetArrayLength(kRlocsAnyRole);
SuccessOrQuit(netData.FindBorderRouters(kAnyRole, rlocs, rlocsLength));
VerifyRlocsArray(rlocs, rlocsLength, kRlocsAnyRole);
for (uint16_t rloc16 : kRlocsAnyRole)
{
VerifyOrQuit(netData.ContainsBorderRouterWithRloc(rloc16));
}
for (uint16_t rloc16 : kNonExistingRlocs)
{
VerifyOrQuit(!netData.ContainsBorderRouterWithRloc(rloc16));
}
}
{
@ -410,9 +432,10 @@ void TestNetworkDataIterator(void)
},
};
const uint16_t kRlocsAnyRole[] = {0xec00, 0x2801, 0x2800};
const uint16_t kRlocsRouterRole[] = {0xec00, 0x2800};
const uint16_t kRlocsChildRole[] = {0x2801};
const uint16_t kRlocsAnyRole[] = {0xec00, 0x2801, 0x2800};
const uint16_t kRlocsRouterRole[] = {0xec00, 0x2800};
const uint16_t kRlocsChildRole[] = {0x2801};
const uint16_t kNonExistingRlocs[] = {0x6000, 0x0000, 0x2806, 0x4c00};
NetworkData netData(*instance, kNetworkData, sizeof(kNetworkData));
@ -451,6 +474,16 @@ void TestNetworkDataIterator(void)
SuccessOrQuit(netData.FindBorderRouters(kChildRoleOnly, rlocs, rlocsLength));
VerifyRlocsArray(rlocs, rlocsLength, kRlocsChildRole);
VerifyOrQuit(netData.CountBorderRouters(kChildRoleOnly) == GetArrayLength(kRlocsChildRole));
for (uint16_t rloc16 : kRlocsAnyRole)
{
VerifyOrQuit(netData.ContainsBorderRouterWithRloc(rloc16));
}
for (uint16_t rloc16 : kNonExistingRlocs)
{
VerifyOrQuit(!netData.ContainsBorderRouterWithRloc(rloc16));
}
}
testFreeInstance(instance);