mirror of
https://github.com/espressif/openthread.git
synced 2026-09-07 01:30:11 +00:00
[routing-manager] track and expose addresses used on infra-if (#11891)
This commit introduces a mechanism within the `RoutingManager` to track the IPv6 addresses used by the Border Router itself on the infrastructure interface, particularly when sending Router Advertisements. This provides visibility for debugging and monitoring purposes. A new data structure, `otBorderRoutingIfAddrEntry`, is added to represent an address and the time elapsed since it was last used as the source of an RA. The tracked addresses can be retrieved using the new public API `otBorderRoutingGetNextIfAddrEntry` or CLI command `br ifaddrs`.
This commit is contained in:
@@ -154,6 +154,15 @@ typedef struct otBorderRoutingPeerBorderRouterEntry
|
||||
uint32_t mAge; ///< Seconds since the BR appeared in the Network Data.
|
||||
} otBorderRoutingPeerBorderRouterEntry;
|
||||
|
||||
/**
|
||||
* Represents an infra-if IPv6 address entry (an address used by this BR itself on the AIL).
|
||||
*/
|
||||
typedef struct otBorderRoutingIfAddrEntry
|
||||
{
|
||||
otIp6Address mAddress; ///< The IPv6 address.
|
||||
uint32_t mSecSinceLastUse; ///< Seconds since the last RA was sent from this BR using this address.
|
||||
} otBorderRoutingIfAddrEntry;
|
||||
|
||||
/**
|
||||
* Represents a group of data of platform-generated RA messages processed.
|
||||
*/
|
||||
@@ -696,7 +705,7 @@ void otBorderRoutingSetMultiAilCallback(otInstance *aInstanc
|
||||
*
|
||||
* @retval OT_ERROR_NONE Iterated to the next address entry, @p aEntry and @p aIterator are updated.
|
||||
* @retval OT_ERROR_NOT_FOUND No more entries in the table.
|
||||
* @retval OT_ERROR_INVALID_ARSG The iterator is invalid (used to iterate over other entry types, e.g. prefix).
|
||||
* @retval OT_ERROR_INVALID_ARGS The iterator is invalid (used to iterate over other entry types, e.g. prefix).
|
||||
*/
|
||||
otError otBorderRoutingGetNextRdnssAddrEntry(otInstance *aInstance,
|
||||
otBorderRoutingPrefixTableIterator *aIterator,
|
||||
@@ -737,6 +746,23 @@ void otBorderRoutingSetRdnssAddrCallback(otInstance *aInsta
|
||||
otBorderRoutingRdnssAddrCallback aCallback,
|
||||
void *aContext);
|
||||
|
||||
/**
|
||||
* Iterates over the infrastructure interface address entries.
|
||||
*
|
||||
* These are addresses used by the BR itself, for example, when sending Router Advertisements.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
* @param[in,out] aIterator A pointer to the iterator.
|
||||
* @param[out] aEntry A pointer to the entry to populate.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Iterated to the next address entry, @p aEntry and @p aIterator are updated.
|
||||
* @retval OT_ERROR_NOT_FOUND No more entries in the table.
|
||||
* @retval OT_ERROR_INVALID_ARGS The iterator is invalid (used to iterate over other entry types, e.g., prefix).
|
||||
*/
|
||||
otError otBorderRoutingGetNextIfAddrEntry(otInstance *aInstance,
|
||||
otBorderRoutingPrefixTableIterator *aIterator,
|
||||
otBorderRoutingIfAddrEntry *aEntry);
|
||||
|
||||
/**
|
||||
* Enables / Disables DHCPv6 Prefix Delegation.
|
||||
*
|
||||
|
||||
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (532)
|
||||
#define OPENTHREAD_API_VERSION (533)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -8,6 +8,7 @@ Usage : `br [command] ...`
|
||||
- [disable](#disable)
|
||||
- [enable](#enable)
|
||||
- [help](#help)
|
||||
- [ifaddrs](#ifaddrs)
|
||||
- [init](#init)
|
||||
- [nat64prefix](#nat64prefix)
|
||||
- [omrprefix](#omrprefix)
|
||||
@@ -60,6 +61,22 @@ Initializes the Border Routing Manager on given infrastructure interface.
|
||||
Done
|
||||
```
|
||||
|
||||
### ifaddrs
|
||||
|
||||
Usage: `br ifaddrs`
|
||||
|
||||
Get the infrastructure interface addresses. These are addresses used by the BR itself, for example, when sending Router Advertisements.
|
||||
|
||||
Info per entry:
|
||||
|
||||
- IPv6 address.
|
||||
- Seconds since the last RA was sent from this BR using this address.
|
||||
|
||||
```bash
|
||||
> br ifaddrs
|
||||
fe80::896:228b:4ae0:8609, sec-since-use:15
|
||||
```
|
||||
|
||||
### infraif
|
||||
|
||||
Usage: `br infraif`
|
||||
|
||||
+39
-1
@@ -767,6 +767,43 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @cli br ifaddrs
|
||||
* @code
|
||||
* br ifaddrs
|
||||
* fe80::896:228b:4ae0:8609, sec-since-use:15
|
||||
* Done
|
||||
* @endcode
|
||||
* @par
|
||||
* Get the infrastructure interface addresses. These are addresses used by the BR itself, for example, when sending
|
||||
* Router Advertisements.
|
||||
* Info per entry:
|
||||
* - IPv6 address
|
||||
* - Seconds since the last RA was sent from this BR using this address.
|
||||
* @sa otBorderRoutingGetNextIfAddrEntry
|
||||
*/
|
||||
template <> otError Br::Process<Cmd("ifaddrs")>(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
otBorderRoutingPrefixTableIterator iterator;
|
||||
otBorderRoutingIfAddrEntry entry;
|
||||
|
||||
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
|
||||
|
||||
otBorderRoutingPrefixTableInitIterator(GetInstancePtr(), &iterator);
|
||||
|
||||
while (otBorderRoutingGetNextIfAddrEntry(GetInstancePtr(), &iterator, &entry) == OT_ERROR_NONE)
|
||||
{
|
||||
char string[OT_IP6_ADDRESS_STRING_SIZE];
|
||||
|
||||
otIp6AddressToString(&entry.mAddress, string, sizeof(string));
|
||||
OutputLine("%s, sec-since-use:%lu", string, ToUlong(entry.mSecSinceLastUse));
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
|
||||
|
||||
const char *Br::Dhcp6PdStateToString(otBorderRoutingDhcp6PdState aState)
|
||||
@@ -1114,7 +1151,8 @@ otError Br::Process(Arg aArgs[])
|
||||
#if OPENTHREAD_CONFIG_IP6_BR_COUNTERS_ENABLE
|
||||
CmdEntry("counters"),
|
||||
#endif
|
||||
CmdEntry("disable"), CmdEntry("enable"), CmdEntry("infraif"), CmdEntry("init"),
|
||||
CmdEntry("disable"), CmdEntry("enable"), CmdEntry("ifaddrs"), CmdEntry("infraif"),
|
||||
CmdEntry("init"),
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
CmdEntry("multiail"),
|
||||
#endif
|
||||
|
||||
@@ -249,6 +249,16 @@ void otBorderRoutingSetRdnssAddrCallback(otInstance *aInsta
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().SetRdnssAddrCallback(aCallback, aContext);
|
||||
}
|
||||
|
||||
otError otBorderRoutingGetNextIfAddrEntry(otInstance *aInstance,
|
||||
otBorderRoutingPrefixTableIterator *aIterator,
|
||||
otBorderRoutingIfAddrEntry *aEntry)
|
||||
{
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aEntry);
|
||||
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetNextIfAddrEntry(*aIterator, *aEntry);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
|
||||
otError otBorderRoutingGetNextPeerBrEntry(otInstance *aInstance,
|
||||
|
||||
@@ -1092,6 +1092,26 @@ void RoutingManager::RdnssAddress::CopyInfoTo(RdnssAddrEntry &aEntry, TimeMilli
|
||||
aEntry.mLifetime = GetLifetime();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// IfAddress
|
||||
|
||||
void RoutingManager::IfAddress::SetFrom(const Ip6::Address &aAddress, uint32_t aUptimeNow)
|
||||
{
|
||||
mAddress = aAddress;
|
||||
mLastUseUptime = aUptimeNow;
|
||||
}
|
||||
|
||||
bool RoutingManager::IfAddress::Matches(const InvalidChecker &aChecker) const
|
||||
{
|
||||
return !aChecker.Get<InfraIf>().HasAddress(mAddress);
|
||||
}
|
||||
|
||||
void RoutingManager::IfAddress::CopyInfoTo(IfAddrEntry &aEntry, uint32_t aUptimeNow) const
|
||||
{
|
||||
aEntry.mAddress = mAddress;
|
||||
aEntry.mSecSinceLastUse = aUptimeNow - mLastUseUptime;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------------
|
||||
// NetDataPeerBrTracker
|
||||
|
||||
@@ -1284,6 +1304,7 @@ void RoutingManager::RxRaTracker::Start(void) { HandleNetDataChange(); }
|
||||
void RoutingManager::RxRaTracker::Stop(void)
|
||||
{
|
||||
mRouters.Free();
|
||||
mIfAddresses.Free();
|
||||
mLocalRaHeader.Clear();
|
||||
mDecisionFactors.Clear();
|
||||
|
||||
@@ -1301,6 +1322,16 @@ void RoutingManager::RxRaTracker::ProcessRouterAdvertMessage(const RouterAdvert:
|
||||
|
||||
Router *router;
|
||||
|
||||
switch (aRaOrigin)
|
||||
{
|
||||
case kThisBrOtherEntity:
|
||||
case kThisBrRoutingManager:
|
||||
UpdateIfAddresses(aSrcAddress);
|
||||
break;
|
||||
case kAnotherRouter:
|
||||
break;
|
||||
}
|
||||
|
||||
VerifyOrExit(aRaOrigin != kThisBrRoutingManager);
|
||||
|
||||
router = mRouters.FindMatching(aSrcAddress);
|
||||
@@ -1600,6 +1631,27 @@ exit:
|
||||
}
|
||||
}
|
||||
|
||||
void RoutingManager::RxRaTracker::UpdateIfAddresses(const Ip6::Address &aAddress)
|
||||
{
|
||||
Entry<IfAddress> *entry;
|
||||
|
||||
mIfAddresses.RemoveAndFreeAllMatching(IfAddress::InvalidChecker(GetInstance()));
|
||||
|
||||
entry = mIfAddresses.FindMatching(aAddress);
|
||||
|
||||
if (entry == nullptr)
|
||||
{
|
||||
entry = AllocateEntry<IfAddress>();
|
||||
VerifyOrExit(entry != nullptr);
|
||||
mIfAddresses.Push(*entry);
|
||||
}
|
||||
|
||||
entry->SetFrom(aAddress, Get<Uptime>().GetUptimeInSeconds());
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
|
||||
template <>
|
||||
@@ -1618,8 +1670,8 @@ exit:
|
||||
template <class Type> RoutingManager::RxRaTracker::Entry<Type> *RoutingManager::RxRaTracker::AllocateEntry(void)
|
||||
{
|
||||
static_assert(TypeTraits::IsSame<Type, OnLinkPrefix>::kValue || TypeTraits::IsSame<Type, RoutePrefix>::kValue ||
|
||||
TypeTraits::IsSame<Type, RdnssAddress>::kValue,
|
||||
"Type MSUT be either RoutePrefix, OnLinkPrefix, or RdnssAddress");
|
||||
TypeTraits::IsSame<Type, RdnssAddress>::kValue || TypeTraits::IsSame<Type, IfAddress>::kValue,
|
||||
"Type MUST be RoutePrefix, OnLinkPrefix, RdnssAddress, or IfAddress");
|
||||
|
||||
Entry<Type> *entry = nullptr;
|
||||
SharedEntry *sharedEntry = mEntryPool.Allocate();
|
||||
@@ -1643,8 +1695,8 @@ template <> void RoutingManager::RxRaTracker::Entry<RoutingManager::RxRaTracker:
|
||||
template <class Type> void RoutingManager::RxRaTracker::Entry<Type>::Free(void)
|
||||
{
|
||||
static_assert(TypeTraits::IsSame<Type, OnLinkPrefix>::kValue || TypeTraits::IsSame<Type, RoutePrefix>::kValue ||
|
||||
TypeTraits::IsSame<Type, RdnssAddress>::kValue,
|
||||
"Type MSUT be either RoutePrefix, OnLinkPrefix, or RdnssAddress");
|
||||
TypeTraits::IsSame<Type, RdnssAddress>::kValue || TypeTraits::IsSame<Type, IfAddress>::kValue,
|
||||
"Type MUST be RoutePrefix, OnLinkPrefix, RdnssAddress, or IfAddress");
|
||||
|
||||
Get<RoutingManager>().mRxRaTracker.mEntryPool.Free(*reinterpret_cast<SharedEntry *>(this));
|
||||
}
|
||||
@@ -2206,6 +2258,21 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error RoutingManager::RxRaTracker::GetNextIfAddr(PrefixTableIterator &aIterator, IfAddrEntry &aEntry) const
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
Iterator &iterator = static_cast<Iterator &>(aIterator);
|
||||
|
||||
ClearAllBytes(aEntry);
|
||||
|
||||
SuccessOrExit(error = iterator.AdvanceToNextIfAddrEntry(mIfAddresses.GetHead()));
|
||||
|
||||
iterator.GetEntry<IfAddress>()->CopyInfoTo(aEntry, iterator.GetInitUptime());
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
uint16_t RoutingManager::RxRaTracker::CountReachablePeerBrs(void) const
|
||||
{
|
||||
@@ -2395,6 +2462,28 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Error RoutingManager::RxRaTracker::Iterator::AdvanceToNextIfAddrEntry(const Entry<IfAddress> *aListHead)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
if (GetType() == kUnspecified)
|
||||
{
|
||||
SetType(kIfAddrIterator);
|
||||
SetEntry(aListHead);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyOrExit(GetType() == kIfAddrIterator, error = kErrorInvalidArgs);
|
||||
VerifyOrExit(HasEntry(), error = kErrorNotFound);
|
||||
SetEntry(GetEntry<IfAddress>()->GetNext());
|
||||
}
|
||||
|
||||
VerifyOrExit(HasEntry(), error = kErrorNotFound);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
|
||||
Error RoutingManager::RxRaTracker::Iterator::AdvanceToNextPeerBr(const PeerBr *aPeerBrsHead)
|
||||
|
||||
@@ -104,6 +104,7 @@ public:
|
||||
typedef otBorderRoutingRouterEntry RouterEntry; ///< Router Entry.
|
||||
typedef otBorderRoutingRdnssAddrEntry RdnssAddrEntry; ///< RDNSS Address Entry.
|
||||
typedef otBorderRoutingRdnssAddrCallback RdnssAddrCallback; ///< RDNS Address changed callback.
|
||||
typedef otBorderRoutingIfAddrEntry IfAddrEntry; ///< Infra-if IPv6 Address Entry.
|
||||
typedef otBorderRoutingPeerBorderRouterEntry PeerBrEntry; ///< Peer Border Router Entry.
|
||||
typedef otBorderRoutingPrefixTableEntry Dhcp6PdPrefix; ///< DHCPv6 PD prefix.
|
||||
typedef otPdProcessedRaInfo Dhcp6PdCounters; ///< DHCPv6 PD counters.
|
||||
@@ -552,6 +553,23 @@ public:
|
||||
mRxRaTracker.SetRdnssCallback(aCallback, aContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the infrastructure interface address entries.
|
||||
*
|
||||
* These are addresses used by the BR itself, for example, when sending Router Advertisements.
|
||||
*
|
||||
* @param[in,out] aIterator An iterator.
|
||||
* @param[out] aEntry A reference to the entry to populate.
|
||||
*
|
||||
* @retval kErrorNone Iterated to the next address entry, @p aEntry and @p aIterator are updated.
|
||||
* @retval kErrorNotFound No more entries in the table.
|
||||
* @retval kErrorInvalidArgs The @p aIterator is not valid (e.g. used to iterate over other entry types).
|
||||
*/
|
||||
Error GetNextIfAddrEntry(PrefixTableIterator &aIterator, IfAddrEntry &aEntry)
|
||||
{
|
||||
return mRxRaTracker.GetNextIfAddr(aIterator, aEntry);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
|
||||
/**
|
||||
@@ -907,6 +925,31 @@ private:
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
class IfAddress // An if-address used by this BR itself (e.g., sending RA).
|
||||
{
|
||||
public:
|
||||
struct InvalidChecker : public InstanceLocator
|
||||
{
|
||||
// Used in `Matches()` to check if address is invalid `!Get<InfraIf>().HasAddress(mAddress)`.
|
||||
|
||||
explicit InvalidChecker(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void SetFrom(const Ip6::Address &aAddress, uint32_t aUptimeNow);
|
||||
bool Matches(const Ip6::Address &aAddress) const { return (mAddress == aAddress); }
|
||||
bool Matches(const InvalidChecker &aChecker) const;
|
||||
void CopyInfoTo(IfAddrEntry &aEntry, uint32_t aUptimeNow) const;
|
||||
|
||||
private:
|
||||
Ip6::Address mAddress;
|
||||
uint32_t mLastUseUptime;
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
|
||||
class RxRaTracker;
|
||||
@@ -1059,6 +1102,7 @@ private:
|
||||
Error GetNextEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
|
||||
Error GetNextRouter(PrefixTableIterator &aIterator, RouterEntry &aEntry) const;
|
||||
Error GetNextRdnssAddr(PrefixTableIterator &aIterator, RdnssAddrEntry &aEntry) const;
|
||||
Error GetNextIfAddr(PrefixTableIterator &aIterator, IfAddrEntry &aEntry) const;
|
||||
|
||||
// Callbacks notifying of changes
|
||||
void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
|
||||
@@ -1188,6 +1232,7 @@ private:
|
||||
kRouterIterator,
|
||||
kPrefixIterator,
|
||||
kRdnssAddrIterator,
|
||||
kIfAddrIterator,
|
||||
kPeerBrIterator,
|
||||
};
|
||||
|
||||
@@ -1201,6 +1246,7 @@ private:
|
||||
Error AdvanceToNextRouter(Type aType);
|
||||
Error AdvanceToNextEntry(void);
|
||||
Error AdvanceToNextRdnssAddrEntry(void);
|
||||
Error AdvanceToNextIfAddrEntry(const Entry<IfAddress> *aListHead);
|
||||
uint32_t GetInitUptime(void) const { return mData0; }
|
||||
TimeMilli GetInitTime(void) const { return TimeMilli(mData1); }
|
||||
Type GetType(void) const { return static_cast<Type>(mData2); }
|
||||
@@ -1248,6 +1294,7 @@ private:
|
||||
Entry<OnLinkPrefix> mOnLinkEntry;
|
||||
Entry<RoutePrefix> mRouteEntry;
|
||||
Entry<RdnssAddress> mRdnssAddrEntry;
|
||||
Entry<IfAddress> mIfAddrEntry;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1279,6 +1326,7 @@ private:
|
||||
void ProcessPrefixInfoOption(const PrefixInfoOption &aPio, Router &aRouter);
|
||||
void ProcessRouteInfoOption(const RouteInfoOption &aRio, Router &aRouter);
|
||||
void ProcessRecursiveDnsServerOption(const RecursiveDnsServerOption &aRdnss, Router &aRouter);
|
||||
void UpdateIfAddresses(const Ip6::Address &aAddress);
|
||||
void Evaluate(void);
|
||||
void DetermineStaleTimeFor(const OnLinkPrefix &aPrefix, NextFireTime &aStaleTime);
|
||||
void DetermineStaleTimeFor(const RoutePrefix &aPrefix, NextFireTime &aStaleTime);
|
||||
@@ -1303,10 +1351,12 @@ private:
|
||||
using RouterTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRxRaTrackerRouterTimer>;
|
||||
using RdnssAddrTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRxRaTrackerRdnssAddrTimer>;
|
||||
using RouterList = OwningList<Entry<Router>>;
|
||||
using IfAddressList = OwningList<Entry<IfAddress>>;
|
||||
using RdnssCallback = Callback<RdnssAddrCallback>;
|
||||
|
||||
DecisionFactors mDecisionFactors;
|
||||
RouterList mRouters;
|
||||
IfAddressList mIfAddresses;
|
||||
ExpirationTimer mExpirationTimer;
|
||||
StaleTimer mStaleTimer;
|
||||
RouterTimer mRouterTimer;
|
||||
@@ -1909,6 +1959,13 @@ inline RoutingManager::RxRaTracker::Entry<RoutingManager::RdnssAddress> &Routing
|
||||
return mRdnssAddrEntry;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline RoutingManager::RxRaTracker::Entry<RoutingManager::IfAddress> &RoutingManager::RxRaTracker::SharedEntry::
|
||||
GetEntry(void)
|
||||
{
|
||||
return mIfAddrEntry;
|
||||
}
|
||||
|
||||
// Declare template (full) specializations for `Router` type.
|
||||
|
||||
template <>
|
||||
|
||||
@@ -854,6 +854,9 @@ class Node(object):
|
||||
def br_get_multiail(self):
|
||||
return self._cli_single_output('br multiail')
|
||||
|
||||
def br_get_ifaddrs(self):
|
||||
return self.cli('br ifaddrs')
|
||||
|
||||
#- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
# trel
|
||||
|
||||
|
||||
@@ -119,6 +119,9 @@ for br in all_brs:
|
||||
for other_br in other_brs:
|
||||
rloc16 = other_br.get_rloc16()
|
||||
verify(any([rloc16 in peer for peer in peers]))
|
||||
ifaddrs = br.br_get_ifaddrs()
|
||||
verify(len(ifaddrs) == 1)
|
||||
verify(ifaddrs[0].startswith('fe80:'))
|
||||
|
||||
# Disable BR3 and validate that BR1 and BR2 detect this.
|
||||
# BR3 itself should continue to detect BR1 and BR2
|
||||
|
||||
Reference in New Issue
Block a user