mirror of
https://github.com/espressif/openthread.git
synced 2026-08-23 02:39:52 +00:00
[routing-manager] indicate peer BRs in discovered infra-if routers (#10448)
This commit updates the public API `otBorderRoutingGetNextRouterEntry` and `otBorderRoutingRouterEntry` structure to indicate whether a discovered router on an infrastructure link is likely a peer Thread Border Router (BR) connected to the same Thread mesh. The related CLI commands are also updated. Additionally, this commit adds new tests to validate the discovery and tracking of peer BRs.
This commit is contained in:
@@ -94,6 +94,11 @@ typedef struct otBorderRoutingPrefixTableIterator
|
||||
/**
|
||||
* Represents a discovered router on the infrastructure link.
|
||||
*
|
||||
* The `mIsPeerBr` field requires `OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE`. Routing Manager
|
||||
* determines whether the router is a peer BR (connected to the same Thread mesh network) by comparing its advertised
|
||||
* PIO/RIO prefixes with the entries in the Thread Network Data. While this method is generally effective, it may not
|
||||
* be 100% accurate in all scenarios, so the `mIsPeerBr` flag should be used with caution.
|
||||
*
|
||||
*/
|
||||
typedef struct otBorderRoutingRouterEntry
|
||||
{
|
||||
@@ -105,6 +110,7 @@ typedef struct otBorderRoutingRouterEntry
|
||||
bool mStubRouterFlag : 1; ///< The router's Stub Router flag.
|
||||
bool mIsLocalDevice : 1; ///< This router is the local device (this BR).
|
||||
bool mIsReachable : 1; ///< This router is reachable.
|
||||
bool mIsPeerBr : 1; ///< This router is (likely) a peer BR.
|
||||
} otBorderRoutingRouterEntry;
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (426)
|
||||
#define OPENTHREAD_API_VERSION (427)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -355,6 +355,7 @@ Info per router:
|
||||
- Reachability flag: A router is marked as unreachable if it fails to respond to multiple Neighbor Solicitation probes.
|
||||
- Age: Duration interval since this router was first discovered. It is formatted as `{hh}:{mm}:{ss}` for hours, minutes, seconds, if the duration is less than 24 hours. If the duration is 24 hours or more, the format is `{dd}d.{hh}:{mm}:{ss}` for days, hours, minutes, seconds.
|
||||
- `(this BR)` is appended when the router is the local device itself.
|
||||
- `(peer BR)` is appended when the router is likely a peer BR connected to the same Thread mesh. This requires `OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE`.
|
||||
|
||||
```bash
|
||||
> br routers
|
||||
|
||||
@@ -536,6 +536,8 @@ exit:
|
||||
* minutes, seconds, if the duration is less than 24 hours. If the duration is 24 hours or more, the format is
|
||||
* `{dd}d.{hh}:{mm}:{ss}` for days, hours, minutes, seconds.
|
||||
* - `(this BR)` is appended when the router is the local device itself.
|
||||
* - `(peer BR)` is appended when the router is likely a peer BR connected to the same Thread mesh. This requires
|
||||
* `OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE`.
|
||||
* @sa otBorderRoutingGetNextRouterEntry
|
||||
*/
|
||||
template <> otError Br::Process<Cmd("routers")>(Arg aArgs[])
|
||||
@@ -576,6 +578,13 @@ void Br::OutputRouterInfo(const otBorderRoutingRouterEntry &aEntry, RouterOutput
|
||||
{
|
||||
OutputFormat(" (this BR)");
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
if (aEntry.mIsPeerBr)
|
||||
{
|
||||
OutputFormat(" (peer BR)");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
OutputNewLine();
|
||||
|
||||
@@ -1916,6 +1916,17 @@ bool RoutingManager::RxRaTracker::Router::Matches(const EmptyChecker &aChecker)
|
||||
return !hasFlags && mOnLinkPrefixes.IsEmpty() && mRoutePrefixes.IsEmpty();
|
||||
}
|
||||
|
||||
bool RoutingManager::RxRaTracker::Router::IsPeerBr(void) const
|
||||
{
|
||||
// Determines whether the router is a peer BR (connected to the
|
||||
// same Thread mesh network). It must have at least one entry
|
||||
// (on-link or route) and all entries should be marked to be
|
||||
// disregarded. While this model is generally effective to detect
|
||||
// peer BRs, it may not be 100% accurate in all scenarios.
|
||||
|
||||
return mAllEntriesDisregarded && !(mOnLinkPrefixes.IsEmpty() && mRoutePrefixes.IsEmpty());
|
||||
}
|
||||
|
||||
void RoutingManager::RxRaTracker::Router::CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow, uint32_t aUptime) const
|
||||
{
|
||||
aEntry.mAddress = mAddress;
|
||||
@@ -1926,6 +1937,7 @@ void RoutingManager::RxRaTracker::Router::CopyInfoTo(RouterEntry &aEntry, TimeMi
|
||||
aEntry.mStubRouterFlag = mStubRouterFlag;
|
||||
aEntry.mIsLocalDevice = mIsLocalDevice;
|
||||
aEntry.mIsReachable = IsReachable();
|
||||
aEntry.mIsPeerBr = IsPeerBr();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -841,6 +841,7 @@ private:
|
||||
void DetermineReachabilityTimeout(void);
|
||||
bool Matches(const Ip6::Address &aAddress) const { return aAddress == mAddress; }
|
||||
bool Matches(const EmptyChecker &aChecker);
|
||||
bool IsPeerBr(void) const;
|
||||
void CopyInfoTo(RouterEntry &aEntry, TimeMilli aNow, uint32_t aUptime) const;
|
||||
|
||||
using OnLinkPrefixList = OwningList<Entry<OnLinkPrefix>>;
|
||||
|
||||
@@ -97,11 +97,16 @@ verify(br2_local_onlink != br2_favored_onlink)
|
||||
|
||||
verify(br1_favored_onlink == br2_favored_onlink)
|
||||
|
||||
br1_routers = br1.br_get_routers()
|
||||
br2_routers = br2.br_get_routers()
|
||||
# Check that the two BRs discover and track each other (not as peer BR since
|
||||
# connected to different networks).
|
||||
|
||||
verify(len(br1_routers) > 0)
|
||||
verify(len(br2_routers) > 0)
|
||||
for br in [br1, br1]:
|
||||
routers = br.br_get_routers()
|
||||
verify(len(routers) > 0)
|
||||
for router in routers:
|
||||
verify('reachable:yes' in router)
|
||||
verify('Stub:1' in router)
|
||||
verify(not router.endswith('(peer BR)'))
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Copyright (c) 2024, 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.
|
||||
|
||||
from cli import verify
|
||||
from cli import verify_within
|
||||
import cli
|
||||
import time
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test description:
|
||||
#
|
||||
# Check tracking of peer BR (connected to same Thread mesh).
|
||||
#
|
||||
# ______________
|
||||
# / \
|
||||
# br1 --- br2 --- br3
|
||||
#
|
||||
|
||||
test_name = __file__[:-3] if __file__.endswith('.py') else __file__
|
||||
print('-' * 120)
|
||||
print('Starting \'{}\''.format(test_name))
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Creating `cli.Nodes` instances
|
||||
|
||||
speedup = 60
|
||||
cli.Node.set_time_speedup_factor(speedup)
|
||||
|
||||
br1 = cli.Node()
|
||||
br2 = cli.Node()
|
||||
br3 = cli.Node()
|
||||
|
||||
IF_INDEX = 1
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Form topology
|
||||
|
||||
br1.form("peer-brs")
|
||||
br2.join(br1)
|
||||
br3.join(br2)
|
||||
|
||||
verify(br1.get_state() == 'leader')
|
||||
verify(br2.get_state() == 'router')
|
||||
verify(br3.get_state() == 'router')
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test implementation
|
||||
|
||||
# Start first border router `br1`
|
||||
|
||||
br1.srp_server_set_addr_mode('unicast')
|
||||
br1.srp_server_auto_enable()
|
||||
|
||||
br1.br_init(IF_INDEX, 1)
|
||||
br1.br_enable()
|
||||
|
||||
time.sleep(1)
|
||||
verify(br1.br_get_state() == 'running')
|
||||
|
||||
br1_local_omr = br1.br_get_local_omrprefix()
|
||||
br1_favored_omr = br1.br_get_favored_omrprefix().split()[0]
|
||||
verify(br1_local_omr == br1_favored_omr)
|
||||
|
||||
br1_local_onlink = br1.br_get_local_onlinkprefix()
|
||||
br1_favored_onlink = br1.br_get_favored_onlinkprefix().split()[0]
|
||||
verify(br1_local_onlink == br1_favored_onlink)
|
||||
|
||||
# Start `br2` and `br3` together
|
||||
|
||||
br2.br_init(IF_INDEX, 1)
|
||||
br2.br_enable()
|
||||
|
||||
br3.br_init(IF_INDEX, 1)
|
||||
br3.br_enable()
|
||||
|
||||
time.sleep(1)
|
||||
verify(br2.br_get_state() == 'running')
|
||||
verify(br3.br_get_state() == 'running')
|
||||
|
||||
# Validate that all BRs discovered the other ones as peer BR
|
||||
|
||||
for br in [br1, br2, br3]:
|
||||
routers = br.br_get_routers()
|
||||
verify(len(routers) == 2)
|
||||
for router in routers:
|
||||
verify(router.endswith('(peer BR)'))
|
||||
|
||||
# -----------------------------------------------------------------------------------------------------------------------
|
||||
# Test finished
|
||||
|
||||
cli.Node.finalize_all_nodes()
|
||||
|
||||
print('\'{}\' passed.'.format(test_name))
|
||||
Reference in New Issue
Block a user