mirror of
https://github.com/espressif/openthread.git
synced 2026-08-06 18:57:47 +00:00
[border-router] separate RxRaTracker into its own class (#12001)
This commit separates the `RxRaTracker` logic from `RoutingManager` into its own class and source files. Previously, `RxRaTracker` was a nested class within `RoutingManager`. This change moves it to `src/core/border_router/rx_ra_tracker.hpp` and `src/core/border_router/rx_ra_tracker.cpp`, making it a standalone class within the `ot::BorderRouter` namespace. This separation improves modularity and prepares for future changes where `RxRaTracker` may operate independently of `RoutingManager`.
This commit is contained in:
@@ -388,6 +388,8 @@ openthread_core_files = [
|
||||
"border_router/infra_if.hpp",
|
||||
"border_router/routing_manager.cpp",
|
||||
"border_router/routing_manager.hpp",
|
||||
"border_router/rx_ra_tracker.cpp",
|
||||
"border_router/rx_ra_tracker.hpp",
|
||||
"coap/coap.cpp",
|
||||
"coap/coap.hpp",
|
||||
"coap/coap_message.cpp",
|
||||
|
||||
@@ -102,6 +102,7 @@ set(COMMON_SOURCES
|
||||
border_router/dhcp6_pd_client.cpp
|
||||
border_router/infra_if.cpp
|
||||
border_router/routing_manager.cpp
|
||||
border_router/rx_ra_tracker.cpp
|
||||
coap/coap.cpp
|
||||
coap/coap_message.cpp
|
||||
coap/coap_secure.cpp
|
||||
|
||||
@@ -208,7 +208,7 @@ void otBorderRoutingPrefixTableInitIterator(otInstance *aInstance, otBorderRouti
|
||||
{
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(*aIterator);
|
||||
AsCoreType(aInstance).Get<BorderRouter::RxRaTracker>().InitIterator(*aIterator);
|
||||
}
|
||||
|
||||
otError otBorderRoutingGetNextPrefixTableEntry(otInstance *aInstance,
|
||||
@@ -218,7 +218,7 @@ otError otBorderRoutingGetNextPrefixTableEntry(otInstance
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aEntry);
|
||||
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetNextPrefixTableEntry(*aIterator, *aEntry);
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RxRaTracker>().GetNextPrefixTableEntry(*aIterator, *aEntry);
|
||||
}
|
||||
|
||||
otError otBorderRoutingGetNextRouterEntry(otInstance *aInstance,
|
||||
@@ -228,7 +228,7 @@ otError otBorderRoutingGetNextRouterEntry(otInstance *aI
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aEntry);
|
||||
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetNextRouterEntry(*aIterator, *aEntry);
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RxRaTracker>().GetNextRouterEntry(*aIterator, *aEntry);
|
||||
}
|
||||
|
||||
otError otBorderRoutingGetNextRdnssAddrEntry(otInstance *aInstance,
|
||||
@@ -238,14 +238,14 @@ otError otBorderRoutingGetNextRdnssAddrEntry(otInstance
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aEntry);
|
||||
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetNextRdnssAddrEntry(*aIterator, *aEntry);
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RxRaTracker>().GetNextRdnssAddrEntry(*aIterator, *aEntry);
|
||||
}
|
||||
|
||||
void otBorderRoutingSetRdnssAddrCallback(otInstance *aInstance,
|
||||
otBorderRoutingRdnssAddrCallback aCallback,
|
||||
void *aContext)
|
||||
{
|
||||
AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().SetRdnssAddrCallback(aCallback, aContext);
|
||||
AsCoreType(aInstance).Get<BorderRouter::RxRaTracker>().SetRdnssAddrCallback(aCallback, aContext);
|
||||
}
|
||||
|
||||
otError otBorderRoutingGetNextIfAddrEntry(otInstance *aInstance,
|
||||
@@ -255,7 +255,7 @@ otError otBorderRoutingGetNextIfAddrEntry(otInstance *aI
|
||||
AssertPointerIsNotNull(aIterator);
|
||||
AssertPointerIsNotNull(aEntry);
|
||||
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RoutingManager>().GetNextIfAddrEntry(*aIterator, *aEntry);
|
||||
return AsCoreType(aInstance).Get<BorderRouter::RxRaTracker>().GetNextIfAddrEntry(*aIterator, *aEntry);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
#include "border_router/br_types.hpp"
|
||||
#include "common/log.hpp"
|
||||
#include "net/ip6_address.hpp"
|
||||
|
||||
namespace ot {
|
||||
@@ -85,10 +86,10 @@ void LogRecursiveDnsServerOption(const Ip6::Address &aAddress, uint32_t aLifetim
|
||||
|
||||
#else
|
||||
|
||||
void LogRaHeader(const RouterAdvert::Header &) {}
|
||||
void LogPrefixInfoOption(const Ip6::Prefix &, uint32_t, uint32_t, PrefixInfoOption::Flags) {}
|
||||
void LogRouteInfoOption(const Ip6::Prefix &, uint32_t, RoutePreference) {}
|
||||
void LogRecursiveDnsServerOption(const Ip6::Address &, uint32_t) {}
|
||||
inline void LogRaHeader(const RouterAdvert::Header &) {}
|
||||
inline void LogPrefixInfoOption(const Ip6::Prefix &, uint32_t, uint32_t, PrefixInfoOption::Flags) {}
|
||||
inline void LogRouteInfoOption(const Ip6::Prefix &, uint32_t, RoutePreference) {}
|
||||
inline void LogRecursiveDnsServerOption(const Ip6::Address &, uint32_t) {}
|
||||
|
||||
#endif // OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ uint16_t NetDataBrTracker::CountBrs(Filter aFilter, uint32_t &aMinAge) const
|
||||
|
||||
Error NetDataBrTracker::GetNext(Filter aFilter, TableIterator &aIterator, BorderRouterEntry &aEntry) const
|
||||
{
|
||||
using Iterator = RoutingManager::RxRaTracker::Iterator;
|
||||
using Iterator = RxRaTracker::Iterator;
|
||||
|
||||
Iterator &iterator = static_cast<Iterator &>(aIterator);
|
||||
Error error = kErrorNone;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -63,6 +63,7 @@
|
||||
#include "border_router/br_tracker.hpp"
|
||||
#include "border_router/br_types.hpp"
|
||||
#include "border_router/infra_if.hpp"
|
||||
#include "border_router/rx_ra_tracker.hpp"
|
||||
#include "common/array.hpp"
|
||||
#include "common/callback.hpp"
|
||||
#include "common/equatable.hpp"
|
||||
@@ -99,6 +100,7 @@ class RoutingManager : public InstanceLocator
|
||||
friend class ot::Notifier;
|
||||
friend class ot::Instance;
|
||||
friend class NetDataBrTracker;
|
||||
friend class RxRaTracker;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -454,92 +456,6 @@ public:
|
||||
*/
|
||||
void HandleInfraIfStateChanged(void) { EvaluateState(); }
|
||||
|
||||
/**
|
||||
* Initializes a `PrefixTableIterator`.
|
||||
*
|
||||
* An iterator can be initialized again to start from the beginning of the table.
|
||||
*
|
||||
* When iterating over entries in the table, to ensure the entry update times are consistent, they are given
|
||||
* relative to the time the iterator was initialized.
|
||||
*
|
||||
* @param[out] aIterator The iterator to initialize.
|
||||
*/
|
||||
void InitPrefixTableIterator(PrefixTableIterator &aIterator) const { mRxRaTracker.InitIterator(aIterator); }
|
||||
|
||||
/**
|
||||
* Iterates over entries in the discovered prefix table.
|
||||
*
|
||||
* @param[in,out] aIterator An iterator.
|
||||
* @param[out] aEntry A reference to the entry to populate.
|
||||
*
|
||||
* @retval kErrorNone Got the next entry, @p aEntry is updated and @p aIterator is advanced.
|
||||
* @retval kErrorNotFound No more entries in the table.
|
||||
*/
|
||||
Error GetNextPrefixTableEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const
|
||||
{
|
||||
return mRxRaTracker.GetNextEntry(aIterator, aEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over discovered router entries on infrastructure link.
|
||||
*
|
||||
* @param[in,out] aIterator An iterator.
|
||||
* @param[out] aEntry A reference to the entry to populate.
|
||||
*
|
||||
* @retval kErrorNone Got the next router info, @p aEntry is updated and @p aIterator is advanced.
|
||||
* @retval kErrorNotFound No more routers.
|
||||
*/
|
||||
Error GetNextRouterEntry(PrefixTableIterator &aIterator, RouterEntry &aEntry) const
|
||||
{
|
||||
return mRxRaTracker.GetNextRouter(aIterator, aEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over the discovered Recursive DNS Server (RDNSS) address entries.
|
||||
*
|
||||
* @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 GetNextRdnssAddrEntry(PrefixTableIterator &aIterator, RdnssAddrEntry &aEntry) const
|
||||
{
|
||||
return mRxRaTracker.GetNextRdnssAddr(aIterator, aEntry);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the callback to be notified of changes to discovered Recursive DNS Server (RDNSS) address entries.
|
||||
*
|
||||
* A subsequent call to this method, replaces a previously set callback.
|
||||
*
|
||||
* @param[in] aCallback The callback function pointer. Can be `nullptr` if no callback is required.
|
||||
* @param[in] aConext An arbitrary context information (used when invoking the callback).
|
||||
*
|
||||
*/
|
||||
void SetRdnssAddrCallback(RdnssAddrCallback aCallback, void *aContext)
|
||||
{
|
||||
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) const
|
||||
{
|
||||
return mRxRaTracker.GetNextIfAddr(aIterator, aEntry);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
|
||||
/**
|
||||
@@ -696,8 +612,6 @@ private:
|
||||
static constexpr uint32_t kDefaultOnLinkPrefixLifetime = 1800;
|
||||
static constexpr uint32_t kDefaultNat64PrefixLifetime = 300;
|
||||
|
||||
static constexpr uint32_t kStaleTime = 600; // 10 minutes.
|
||||
|
||||
// RA transmission constants (in milliseconds). Initially, three
|
||||
// RAs are sent with a short interval of 16 seconds (± 2 seconds
|
||||
// jitter). Subsequently, a longer, regular RA beacon interval of
|
||||
@@ -728,13 +642,6 @@ private:
|
||||
kAdvPrefixesFromNetData,
|
||||
};
|
||||
|
||||
enum RouterAdvOrigin : uint8_t // Origin of a received Router Advert message.
|
||||
{
|
||||
kAnotherRouter, // From another router on infra-if.
|
||||
kThisBrRoutingManager, // From this BR generated by `RoutingManager` itself.
|
||||
kThisBrOtherEntity, // From this BR generated by another sw entity.
|
||||
};
|
||||
|
||||
enum ScheduleMode : uint8_t // Used in `ScheduleRoutingPolicyEvaluation()`
|
||||
{
|
||||
kImmediately,
|
||||
@@ -787,7 +694,7 @@ private:
|
||||
|
||||
bool mDetected;
|
||||
uint16_t mNetDataPeerBrCount;
|
||||
uint16_t mRxRaTrackerReachablePeerBrCount;
|
||||
uint16_t mReachablePeerBrCount;
|
||||
DetectTimer mTimer;
|
||||
DetectCallback mCallback;
|
||||
};
|
||||
@@ -796,327 +703,6 @@ private:
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void HandleRxRaTrackerSignalTask(void) { mRxRaTracker.HandleSignalTask(); }
|
||||
void HandleRxRaTrackerRdnssAddrTask(void) { mRxRaTracker.HandleRdnssAddrTask(); }
|
||||
void HandleRxRaTrackerExpirationTimer(void) { mRxRaTracker.HandleExpirationTimer(); }
|
||||
void HandleRxRaTrackerStaleTimer(void) { mRxRaTracker.HandleStaleTimer(); }
|
||||
void HandleRxRaTrackerRouterTimer(void) { mRxRaTracker.HandleRouterTimer(); }
|
||||
void HandleRxRaTrackerRdnssAddrTimer(void) { mRxRaTracker.HandleRdnssAddrTimer(); }
|
||||
|
||||
class RxRaTracker : public InstanceLocator
|
||||
{
|
||||
// Processes received RA and NA messages tracking a table of active
|
||||
// routers and their advertised on-link and route prefixes. Also
|
||||
// manages prefix lifetimes and router reachability (sending NS probes
|
||||
// as needed).
|
||||
//
|
||||
// When there is any change in the table (an entry is added, removed,
|
||||
// or modified), it signals the change to `RoutingManager` by calling
|
||||
// `HandleRaPrefixTableChanged()` callback. A `Tasklet` is used for
|
||||
// signalling which ensures that if there are multiple changes within
|
||||
// the same flow of execution, the callback is invoked after all the
|
||||
// changes are processed.
|
||||
|
||||
friend class NetDataBrTracker;
|
||||
|
||||
public:
|
||||
explicit RxRaTracker(Instance &aInstance);
|
||||
|
||||
void Start(void);
|
||||
void Stop(void);
|
||||
|
||||
void SetRdnssCallback(RdnssAddrCallback aCallback, void *aContext) { mRdnssCallback.Set(aCallback, aContext); }
|
||||
|
||||
void ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage,
|
||||
const Ip6::Address &aSrcAddress,
|
||||
RouterAdvOrigin aRaOrigin);
|
||||
void ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage);
|
||||
|
||||
// Decision factors
|
||||
bool ContainsDefaultOrNonUlaRoutePrefix(void) const { return mDecisionFactors.mHasNonUlaRoute; }
|
||||
bool ContainsNonUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasNonUlaOnLink; }
|
||||
bool ContainsUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasUlaOnLink; }
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
uint16_t GetReachablePeerBrCount(void) const { return mDecisionFactors.mReachablePeerBrCount; }
|
||||
#endif
|
||||
|
||||
const Ip6::Prefix &GetFavoredOnLinkPrefix(void) const { return mDecisionFactors.mFavoredOnLinkPrefix; }
|
||||
void SetHeaderFlagsOn(RouterAdvert::Header &aHeader) const;
|
||||
|
||||
const RouterAdvert::Header &GetLocalRaHeaderToMirror(void) const { return mLocalRaHeader; }
|
||||
|
||||
bool IsAddressOnLink(const Ip6::Address &aAddress) const;
|
||||
bool IsAddressReachableThroughExplicitRoute(const Ip6::Address &aAddress) const;
|
||||
|
||||
// Iterating over discovered items
|
||||
void InitIterator(PrefixTableIterator &aIterator) const;
|
||||
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);
|
||||
void HandleLocalOnLinkPrefixChanged(void);
|
||||
void HandleNetDataChange(void);
|
||||
|
||||
// Tasklet or timer callbacks
|
||||
void HandleSignalTask(void);
|
||||
void HandleRdnssAddrTask(void);
|
||||
void HandleExpirationTimer(void);
|
||||
void HandleStaleTimer(void);
|
||||
void HandleRouterTimer(void);
|
||||
void HandleRdnssAddrTimer(void);
|
||||
|
||||
private:
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
template <class Type>
|
||||
struct Entry : public Type,
|
||||
public LinkedListEntry<Entry<Type>>,
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
public Heap::Allocatable<Entry<Type>>
|
||||
#else
|
||||
public InstanceLocatorInit
|
||||
#endif
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
void Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); }
|
||||
void Free(void);
|
||||
#endif
|
||||
|
||||
Entry<Type> *mNext;
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct Router : public Clearable<Router>
|
||||
{
|
||||
// Reachability timeout intervals before starting Neighbor
|
||||
// Solicitation (NS) probes. Generally 60 seconds (± 2
|
||||
// seconds jitter) is used. For peer BRs a longer timeout
|
||||
// of 200 seconds (3 min and 20 seconds) is used. This is
|
||||
// selected to be longer than regular RA beacon interval
|
||||
// of 3 minutes (± 15 seconds jitter).
|
||||
|
||||
static constexpr uint32_t kReachableInterval = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
|
||||
static constexpr uint32_t kPeerBrReachableInterval = Time::kOneSecondInMsec * 200;
|
||||
|
||||
static constexpr uint8_t kMaxNsProbes = 5; // Max number of NS probe attempts.
|
||||
static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts.
|
||||
static constexpr uint32_t kNsProbeTimeout = 2000; // In msec. Max Wait time after last NS probe.
|
||||
static constexpr uint32_t kJitter = 2000; // In msec. Jitter to randomize probe starts.
|
||||
|
||||
static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255");
|
||||
|
||||
struct EmptyChecker
|
||||
{
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
|
||||
struct HistoryInfo : public Equatable<HistoryInfo>, public Clearable<HistoryInfo>
|
||||
{
|
||||
void DetermineFrom(const Router &aRouter);
|
||||
|
||||
bool mHistoryRecorded : 1;
|
||||
bool mManagedAddressConfigFlag : 1;
|
||||
bool mOtherConfigFlag : 1;
|
||||
bool mSnacRouterFlag : 1;
|
||||
bool mIsLocalDevice : 1;
|
||||
bool mIsReachable : 1;
|
||||
bool mIsPeerBr : 1;
|
||||
bool mProvidesDefaultRoute : 1;
|
||||
RoutePreference mDefRoutePreference;
|
||||
Ip6::Prefix mFavoredOnLinkPrefix;
|
||||
};
|
||||
#endif
|
||||
|
||||
bool IsReachable(void) const { return mNsProbeCount <= kMaxNsProbes; }
|
||||
bool ShouldCheckReachability(void) const;
|
||||
void ResetReachabilityState(void);
|
||||
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>>;
|
||||
using RoutePrefixList = OwningList<Entry<RoutePrefix>>;
|
||||
using RdnssAddressList = OwningList<Entry<RdnssAddress>>;
|
||||
|
||||
// `mDiscoverTime` tracks the initial discovery time of
|
||||
// this router. To accommodate longer durations, the
|
||||
// `Uptime` is used, as `TimeMilli` (which uses `uint32_t`
|
||||
// intervals) would be limited to tracking ~ 49 days.
|
||||
//
|
||||
// `mLastUpdateTime` tracks the most recent time an RA or
|
||||
// NA was received from this router. It is bounded due to
|
||||
// the frequency of reachability checks, so we can safely
|
||||
// use `TimeMilli` for it.
|
||||
|
||||
Ip6::Address mAddress;
|
||||
OnLinkPrefixList mOnLinkPrefixes;
|
||||
RoutePrefixList mRoutePrefixes;
|
||||
RdnssAddressList mRdnssAddresses;
|
||||
uint32_t mDiscoverTime;
|
||||
TimeMilli mLastUpdateTime;
|
||||
TimeMilli mTimeoutTime;
|
||||
uint8_t mNsProbeCount;
|
||||
bool mManagedAddressConfigFlag : 1;
|
||||
bool mOtherConfigFlag : 1;
|
||||
bool mSnacRouterFlag : 1;
|
||||
bool mIsLocalDevice : 1;
|
||||
bool mAllEntriesDisregarded : 1;
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
|
||||
HistoryInfo mHistoryInfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct Iterator : public PrefixTableIterator
|
||||
{
|
||||
enum Type : uint8_t
|
||||
{
|
||||
kUnspecified,
|
||||
kRouterIterator,
|
||||
kPrefixIterator,
|
||||
kRdnssAddrIterator,
|
||||
kIfAddrIterator,
|
||||
kNetDataBrIterator, // Used by `NetDataPeerBrTracker`
|
||||
};
|
||||
|
||||
enum PrefixType : uint8_t
|
||||
{
|
||||
kOnLinkPrefix,
|
||||
kRoutePrefix,
|
||||
};
|
||||
|
||||
void Init(const Entry<Router> *aRoutersHead, uint32_t aUptime);
|
||||
Error AdvanceToNextRouter(Type aType);
|
||||
Error AdvanceToNextPrefixEntry(void);
|
||||
Error AdvanceToNextRdnssAddrEntry(void);
|
||||
Error AdvanceToNextIfAddrEntry(const Entry<IfAddress> *aListHead);
|
||||
uint32_t GetInitUptime(void) const { return mData0; }
|
||||
void SetInitUptime(uint32_t aUptime) { mData0 = aUptime; }
|
||||
TimeMilli GetInitTime(void) const { return TimeMilli(mData1); }
|
||||
void SetInitTime(void) { mData1 = TimerMilli::GetNow().GetValue(); }
|
||||
const Entry<Router> *GetRouter(void) const { return static_cast<const Entry<Router> *>(mPtr1); }
|
||||
void SetRouter(const Entry<Router> *aRouter) { mPtr1 = aRouter; }
|
||||
Type GetType(void) const { return static_cast<Type>(mData2); }
|
||||
void SetType(Type aType) { mData2 = aType; }
|
||||
const void *GetEntry(void) const { return mPtr2; }
|
||||
void SetEntry(const void *aEntry) { mPtr2 = aEntry; }
|
||||
bool HasEntry(void) const { return mPtr2 != nullptr; }
|
||||
PrefixType GetPrefixType(void) const { return static_cast<PrefixType>(mData3); }
|
||||
void SetPrefixType(PrefixType aType) { mData3 = aType; }
|
||||
|
||||
template <typename ObjectType> const Entry<ObjectType> *GetEntry(void) const
|
||||
{
|
||||
return static_cast<const Entry<ObjectType> *>(mPtr2);
|
||||
}
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS;
|
||||
static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES;
|
||||
|
||||
union SharedEntry
|
||||
{
|
||||
SharedEntry(void) { mNext = nullptr; }
|
||||
void SetNext(SharedEntry *aNext) { mNext = aNext; }
|
||||
SharedEntry *GetNext(void) { return mNext; }
|
||||
const SharedEntry *GetNext(void) const { return mNext; }
|
||||
|
||||
template <class Type> Entry<Type> &GetEntry(void);
|
||||
|
||||
SharedEntry *mNext;
|
||||
Entry<OnLinkPrefix> mOnLinkEntry;
|
||||
Entry<RoutePrefix> mRouteEntry;
|
||||
Entry<RdnssAddress> mRdnssAddrEntry;
|
||||
Entry<IfAddress> mIfAddrEntry;
|
||||
};
|
||||
#endif
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct DecisionFactors : public Clearable<DecisionFactors>, public Equatable<DecisionFactors>
|
||||
{
|
||||
DecisionFactors(void) { Clear(); }
|
||||
|
||||
bool HasFavoredOnLink(void) const { return (mFavoredOnLinkPrefix.GetLength() != 0); }
|
||||
void UpdateFlagsFrom(const Router &aRouter);
|
||||
void UpdateFrom(const OnLinkPrefix &aOnLinkPrefix);
|
||||
void UpdateFrom(const RoutePrefix &aRoutePrefix);
|
||||
|
||||
Ip6::Prefix mFavoredOnLinkPrefix;
|
||||
bool mHasNonUlaRoute : 1;
|
||||
bool mHasNonUlaOnLink : 1;
|
||||
bool mHasUlaOnLink : 1;
|
||||
bool mHeaderManagedAddressConfigFlag : 1;
|
||||
bool mHeaderOtherConfigFlag : 1;
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
uint16_t mReachablePeerBrCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ProcessRaHeader(const RouterAdvert::Header &aRaHeader, Router &aRouter, RouterAdvOrigin aRaOrigin);
|
||||
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);
|
||||
void SendNeighborSolicitToRouter(const Router &aRouter);
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
uint16_t CountReachablePeerBrs(void) const;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
|
||||
void ReportChangesToHistoryTracker(Router &aRouter, bool aRemoved);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
template <class Type> Entry<Type> *AllocateEntry(void) { return Entry<Type>::Allocate(); }
|
||||
#else
|
||||
template <class Type> Entry<Type> *AllocateEntry(void);
|
||||
#endif
|
||||
|
||||
using SignalTask = TaskletIn<RoutingManager, &RoutingManager::HandleRxRaTrackerSignalTask>;
|
||||
using RdnssAddrTask = TaskletIn<RoutingManager, &RoutingManager::HandleRxRaTrackerRdnssAddrTask>;
|
||||
using ExpirationTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRxRaTrackerExpirationTimer>;
|
||||
using StaleTimer = TimerMilliIn<RoutingManager, &RoutingManager::HandleRxRaTrackerStaleTimer>;
|
||||
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;
|
||||
RdnssAddrTimer mRdnssAddrTimer;
|
||||
SignalTask mSignalTask;
|
||||
RdnssAddrTask mRdnssAddrTask;
|
||||
RdnssCallback mRdnssCallback;
|
||||
RouterAdvert::Header mLocalRaHeader;
|
||||
TimeMilli mLocalRaHeaderUpdateTime;
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
Pool<SharedEntry, kMaxEntries> mEntryPool;
|
||||
Pool<Entry<Router>, kMaxRouters> mRouterPool;
|
||||
#endif
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
class OmrPrefixManager : public InstanceLocator
|
||||
{
|
||||
public:
|
||||
@@ -1576,7 +1162,7 @@ private:
|
||||
|
||||
static bool IsValidBrUlaPrefix(const Ip6::Prefix &aBrUlaPrefix);
|
||||
|
||||
static const char *RouterAdvOriginToString(RouterAdvOrigin aRaOrigin);
|
||||
static const char *RouterAdvOriginToString(RxRaTracker::RouterAdvOrigin aRaOrigin);
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------
|
||||
// Variables
|
||||
@@ -1608,8 +1194,6 @@ private:
|
||||
MultiAilDetector mMultiAilDetector;
|
||||
#endif
|
||||
|
||||
RxRaTracker mRxRaTracker;
|
||||
|
||||
RoutePublisher mRoutePublisher;
|
||||
|
||||
#if OPENTHREAD_CONFIG_NAT64_BORDER_ROUTING_ENABLE
|
||||
@@ -1627,45 +1211,6 @@ private:
|
||||
RoutingPolicyTimer mRoutingPolicyTimer;
|
||||
};
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Template specializations and declarations
|
||||
|
||||
template <>
|
||||
inline RoutingManager::RxRaTracker::Entry<OnLinkPrefix> &RoutingManager::RxRaTracker::SharedEntry::GetEntry(void)
|
||||
{
|
||||
return mOnLinkEntry;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline RoutingManager::RxRaTracker::Entry<RoutePrefix> &RoutingManager::RxRaTracker::SharedEntry::GetEntry(void)
|
||||
{
|
||||
return mRouteEntry;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline RoutingManager::RxRaTracker::Entry<RdnssAddress> &RoutingManager::RxRaTracker::SharedEntry::GetEntry(void)
|
||||
{
|
||||
return mRdnssAddrEntry;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline RoutingManager::RxRaTracker::Entry<IfAddress> &RoutingManager::RxRaTracker::SharedEntry::GetEntry(void)
|
||||
{
|
||||
return mIfAddrEntry;
|
||||
}
|
||||
|
||||
// Declare template (full) specializations for `Router` type.
|
||||
|
||||
template <>
|
||||
RoutingManager::RxRaTracker::Entry<RoutingManager::RxRaTracker::Router> *RoutingManager::RxRaTracker::AllocateEntry(
|
||||
void);
|
||||
|
||||
template <> void RoutingManager::RxRaTracker::Entry<RoutingManager::RxRaTracker::Router>::Free(void);
|
||||
|
||||
#endif // #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
|
||||
} // namespace BorderRouter
|
||||
|
||||
DefineMapEnum(otBorderRoutingState, BorderRouter::RoutingManager::State);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,572 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes definitions for the Received RA Tracker.
|
||||
*/
|
||||
|
||||
#ifndef RX_RA_TRACKER_HPP_
|
||||
#define RX_RA_TRACKER_HPP_
|
||||
|
||||
#include "openthread-core-config.h"
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
#include <openthread/border_routing.h>
|
||||
|
||||
#include "border_router/br_types.hpp"
|
||||
#include "border_router/infra_if.hpp"
|
||||
#include "common/callback.hpp"
|
||||
#include "common/equatable.hpp"
|
||||
#include "common/error.hpp"
|
||||
#include "common/heap_allocatable.hpp"
|
||||
#include "common/linked_list.hpp"
|
||||
#include "common/locator.hpp"
|
||||
#include "common/message.hpp"
|
||||
#include "common/notifier.hpp"
|
||||
#include "common/owning_list.hpp"
|
||||
#include "common/pool.hpp"
|
||||
#include "common/string.hpp"
|
||||
#include "common/tasklet.hpp"
|
||||
#include "common/timer.hpp"
|
||||
#include "net/ip6.hpp"
|
||||
#include "net/nd6.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace BorderRouter {
|
||||
|
||||
class NetDataBrTracker;
|
||||
|
||||
/**
|
||||
* Implements processing and tracking of received Router Advertisement (RA) and Neighbor Advertisement (NA) messages.
|
||||
*
|
||||
* This class processes received RA and NA messages, tracking a table of active routers on the infrastructure link and
|
||||
* their advertised on-link and route prefixes and other information. It also manages prefix lifetimes and router
|
||||
* reachability (sending Neighbor Solicitation probes as needed).
|
||||
*/
|
||||
class RxRaTracker : public InstanceLocator
|
||||
{
|
||||
friend class NetDataBrTracker;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Represents the origin of a received Router Advertisement message.
|
||||
*/
|
||||
enum RouterAdvOrigin : uint8_t
|
||||
{
|
||||
kAnotherRouter, ///< From another router on the infrastructure interface.
|
||||
kThisBrRoutingManager, ///< From this Border Router, generated by `RoutingManager` itself.
|
||||
kThisBrOtherEntity, ///< From this Border Router, generated by another software entity.
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the `RxRaTracker` object.
|
||||
*
|
||||
* @param[in] aInstance The OpenThread instance.
|
||||
*/
|
||||
explicit RxRaTracker(Instance &aInstance);
|
||||
|
||||
/**
|
||||
* Starts the RA tracker.
|
||||
*/
|
||||
void Start(void);
|
||||
|
||||
/**
|
||||
* Stops the RA tracker.
|
||||
*/
|
||||
void Stop(void);
|
||||
|
||||
/**
|
||||
* Processes a received Router Advertisement (RA) message.
|
||||
*
|
||||
* @param[in] aRaMessage The received RA message.
|
||||
* @param[in] aSrcAddress The source address of the RA message.
|
||||
* @param[in] aRaOrigin The origin of the RA message.
|
||||
*/
|
||||
void ProcessRouterAdvertMessage(const RouterAdvert::RxMessage &aRaMessage,
|
||||
const Ip6::Address &aSrcAddress,
|
||||
RouterAdvOrigin aRaOrigin);
|
||||
|
||||
/**
|
||||
* Processes a received Neighbor Advertisement (NA) message.
|
||||
*
|
||||
* @param[in] aNaMessage The received NA message.
|
||||
*/
|
||||
void ProcessNeighborAdvertMessage(const NeighborAdvertMessage &aNaMessage);
|
||||
|
||||
/**
|
||||
* Initializes a `PrefixTableIterator`.
|
||||
*
|
||||
* An iterator can be initialized again to start from the beginning of the table.
|
||||
*
|
||||
* When iterating over entries in the table, to ensure the entry update times are consistent, they are given
|
||||
* relative to the time the iterator was initialized.
|
||||
*
|
||||
* @param[out] aIterator The iterator to initialize.
|
||||
*/
|
||||
void InitIterator(PrefixTableIterator &aIterator) const;
|
||||
|
||||
/**
|
||||
* Iterates over entries in the discovered prefix table.
|
||||
*
|
||||
* @param[in,out] aIterator An iterator.
|
||||
* @param[out] aEntry A reference to the entry to populate.
|
||||
*
|
||||
* @retval kErrorNone Got the next entry, @p aEntry is updated and @p aIterator is advanced.
|
||||
* @retval kErrorNotFound No more entries in the table.
|
||||
*/
|
||||
Error GetNextPrefixTableEntry(PrefixTableIterator &aIterator, PrefixTableEntry &aEntry) const;
|
||||
|
||||
/**
|
||||
* Iterates over discovered router entries on infrastructure link.
|
||||
*
|
||||
* @param[in,out] aIterator An iterator.
|
||||
* @param[out] aEntry A reference to the entry to populate.
|
||||
*
|
||||
* @retval kErrorNone Got the next router info, @p aEntry is updated and @p aIterator is advanced.
|
||||
* @retval kErrorNotFound No more routers.
|
||||
*/
|
||||
Error GetNextRouterEntry(PrefixTableIterator &aIterator, RouterEntry &aEntry) const;
|
||||
|
||||
/**
|
||||
* Iterates over the discovered Recursive DNS Server (RDNSS) address entries.
|
||||
*
|
||||
* @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 GetNextRdnssAddrEntry(PrefixTableIterator &aIterator, RdnssAddrEntry &aEntry) const;
|
||||
|
||||
/**
|
||||
* Sets the callback to be notified of changes to discovered Recursive DNS Server (RDNSS) address entries.
|
||||
*
|
||||
* A subsequent call to this method, replaces a previously set callback.
|
||||
*
|
||||
* @param[in] aCallback The callback function pointer. Can be `nullptr` if no callback is required.
|
||||
* @param[in] aConext An arbitrary context information (used when invoking the callback).
|
||||
*
|
||||
*/
|
||||
void SetRdnssAddrCallback(RdnssAddrCallback aCallback, void *aContext) { mRdnssCallback.Set(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) const;
|
||||
|
||||
/**
|
||||
* Indicates whether a discovered route prefix is a default route or a non-ULA prefix.
|
||||
*
|
||||
* @retval TRUE A default route or a non-ULA route prefix is discovered.
|
||||
* @retval FALSE No default route or non-ULA route prefix is discovered.
|
||||
*/
|
||||
bool ContainsDefaultOrNonUlaRoutePrefix(void) const { return mDecisionFactors.mHasNonUlaRoute; }
|
||||
|
||||
/**
|
||||
* Indicates whether a discovered on-link prefix is a non-ULA prefix.
|
||||
*
|
||||
* @retval TRUE A non-ULA on-link prefix is discovered.
|
||||
* @retval FALSE No non-ULA on-link prefix is discovered.
|
||||
*/
|
||||
bool ContainsNonUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasNonUlaOnLink; }
|
||||
|
||||
/**
|
||||
* Indicates whether a discovered on-link prefix is a ULA prefix.
|
||||
*
|
||||
* @retval TRUE A ULA on-link prefix is discovered.
|
||||
* @retval FALSE No ULA on-link prefix is discovered.
|
||||
*/
|
||||
bool ContainsUlaOnLinkPrefix(void) const { return mDecisionFactors.mHasUlaOnLink; }
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
/**
|
||||
* Gets the number of reachable peer Border Routers.
|
||||
*
|
||||
* A peer BR is a BR on the same Thread mesh that is also connected to the same infrastructure link.
|
||||
*
|
||||
* @returns The number of reachable peer BRs.
|
||||
*/
|
||||
uint16_t GetReachablePeerBrCount(void) const { return mDecisionFactors.mReachablePeerBrCount; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Gets the favored on-link prefix among all discovered on-link prefixes.
|
||||
*
|
||||
* @returns The favored on-link prefix.
|
||||
*/
|
||||
const Ip6::Prefix &GetFavoredOnLinkPrefix(void) const { return mDecisionFactors.mFavoredOnLinkPrefix; }
|
||||
|
||||
/**
|
||||
* Sets the Managed Address Configuration (M) and Other Configuration (O) flags on a Router Advertisement header.
|
||||
*
|
||||
* The flags are set based on the currently discovered information from other routers on the infrastructure link.
|
||||
*
|
||||
* @param[out] aHeader The RA header to update.
|
||||
*/
|
||||
void SetHeaderFlagsOn(RouterAdvert::Header &aHeader) const;
|
||||
|
||||
/**
|
||||
* Gets the last received Router Advertisement header from a local software entity.
|
||||
*
|
||||
* This can be used to mirror the RA flags in the RA messages sent by the Border Router.
|
||||
*
|
||||
* @returns The last received RA header from a local software entity.
|
||||
*/
|
||||
const RouterAdvert::Header &GetLocalRaHeaderToMirror(void) const { return mLocalRaHeader; }
|
||||
|
||||
/**
|
||||
* Indicates whether an address is considered on-link on the infrastructure link.
|
||||
*
|
||||
* An address is considered on-link if it matches the local on-link prefix or any of the discovered on-link
|
||||
* prefixes advertised by other routers.
|
||||
*
|
||||
* @param[in] aAddress The IPv6 address to check.
|
||||
*
|
||||
* @retval TRUE The address is on-link.
|
||||
* @retval FALSE The address is not on-link.
|
||||
*/
|
||||
bool IsAddressOnLink(const Ip6::Address &aAddress) const;
|
||||
|
||||
/**
|
||||
* Indicates whether an address is reachable through an explicit route on the infrastructure link.
|
||||
*
|
||||
* This method checks if the given address matches any discovered route prefix, excluding the default route.
|
||||
*
|
||||
* @param[in] aAddress The IPv6 address to check.
|
||||
*
|
||||
* @retval TRUE The address is reachable through an explicit route.
|
||||
* @retval FALSE The address is not reachable through an explicit route.
|
||||
*/
|
||||
bool IsAddressReachableThroughExplicitRoute(const Ip6::Address &aAddress) const;
|
||||
|
||||
// Callbacks notifying of changes
|
||||
void RemoveOrDeprecateOldEntries(TimeMilli aTimeThreshold);
|
||||
void HandleLocalOnLinkPrefixChanged(void);
|
||||
void HandleNetDataChange(void);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t kStaleTime = 600; // 10 minutes.
|
||||
|
||||
typedef Ip6::Nd::Option Option;
|
||||
typedef Ip6::Nd::TxMessage TxMessage;
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
template <class Type>
|
||||
struct Entry : public Type,
|
||||
public LinkedListEntry<Entry<Type>>,
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
public Heap::Allocatable<Entry<Type>>
|
||||
#else
|
||||
public InstanceLocatorInit
|
||||
#endif
|
||||
{
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
void Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); }
|
||||
void Free(void);
|
||||
#endif
|
||||
|
||||
Entry<Type> *mNext;
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct Router : public Clearable<Router>
|
||||
{
|
||||
// Reachability timeout intervals before starting Neighbor
|
||||
// Solicitation (NS) probes. Generally 60 seconds (± 2
|
||||
// seconds jitter) is used. For peer BRs a longer timeout
|
||||
// of 200 seconds (3 min and 20 seconds) is used. This is
|
||||
// selected to be longer than regular RA beacon interval
|
||||
// of 3 minutes (± 15 seconds jitter).
|
||||
|
||||
static constexpr uint32_t kReachableInterval = OPENTHREAD_CONFIG_BORDER_ROUTING_ROUTER_ACTIVE_CHECK_TIMEOUT;
|
||||
static constexpr uint32_t kPeerBrReachableInterval = Time::kOneSecondInMsec * 200;
|
||||
|
||||
static constexpr uint8_t kMaxNsProbes = 5; // Max number of NS probe attempts.
|
||||
static constexpr uint32_t kNsProbeRetryInterval = 1000; // In msec. Time between NS probe attempts.
|
||||
static constexpr uint32_t kNsProbeTimeout = 2000; // In msec. Max Wait time after last NS probe.
|
||||
static constexpr uint32_t kJitter = 2000; // In msec. Jitter to randomize probe starts.
|
||||
|
||||
static_assert(kMaxNsProbes < 255, "kMaxNsProbes MUST not be 255");
|
||||
|
||||
struct EmptyChecker
|
||||
{
|
||||
};
|
||||
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
|
||||
struct HistoryInfo : public Equatable<HistoryInfo>, public Clearable<HistoryInfo>
|
||||
{
|
||||
void DetermineFrom(const Router &aRouter);
|
||||
|
||||
bool mHistoryRecorded : 1;
|
||||
bool mManagedAddressConfigFlag : 1;
|
||||
bool mOtherConfigFlag : 1;
|
||||
bool mSnacRouterFlag : 1;
|
||||
bool mIsLocalDevice : 1;
|
||||
bool mIsReachable : 1;
|
||||
bool mIsPeerBr : 1;
|
||||
bool mProvidesDefaultRoute : 1;
|
||||
RoutePreference mDefRoutePreference;
|
||||
Ip6::Prefix mFavoredOnLinkPrefix;
|
||||
};
|
||||
#endif
|
||||
|
||||
bool IsReachable(void) const { return mNsProbeCount <= kMaxNsProbes; }
|
||||
bool ShouldCheckReachability(void) const;
|
||||
void ResetReachabilityState(void);
|
||||
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>>;
|
||||
using RoutePrefixList = OwningList<Entry<RoutePrefix>>;
|
||||
using RdnssAddressList = OwningList<Entry<RdnssAddress>>;
|
||||
|
||||
// `mDiscoverTime` tracks the initial discovery time of
|
||||
// this router. To accommodate longer durations, the
|
||||
// `Uptime` is used, as `TimeMilli` (which uses `uint32_t`
|
||||
// intervals) would be limited to tracking ~ 49 days.
|
||||
//
|
||||
// `mLastUpdateTime` tracks the most recent time an RA or
|
||||
// NA was received from this router. It is bounded due to
|
||||
// the frequency of reachability checks, so we can safely
|
||||
// use `TimeMilli` for it.
|
||||
|
||||
Ip6::Address mAddress;
|
||||
OnLinkPrefixList mOnLinkPrefixes;
|
||||
RoutePrefixList mRoutePrefixes;
|
||||
RdnssAddressList mRdnssAddresses;
|
||||
uint32_t mDiscoverTime;
|
||||
TimeMilli mLastUpdateTime;
|
||||
TimeMilli mTimeoutTime;
|
||||
uint8_t mNsProbeCount;
|
||||
bool mManagedAddressConfigFlag : 1;
|
||||
bool mOtherConfigFlag : 1;
|
||||
bool mSnacRouterFlag : 1;
|
||||
bool mIsLocalDevice : 1;
|
||||
bool mAllEntriesDisregarded : 1;
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
|
||||
HistoryInfo mHistoryInfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct Iterator : public PrefixTableIterator
|
||||
{
|
||||
enum Type : uint8_t
|
||||
{
|
||||
kUnspecified,
|
||||
kRouterIterator,
|
||||
kPrefixIterator,
|
||||
kRdnssAddrIterator,
|
||||
kIfAddrIterator,
|
||||
kNetDataBrIterator, // Used by `NetDataPeerBrTracker`
|
||||
};
|
||||
|
||||
enum PrefixType : uint8_t
|
||||
{
|
||||
kOnLinkPrefix,
|
||||
kRoutePrefix,
|
||||
};
|
||||
|
||||
void Init(const Entry<Router> *aRoutersHead, uint32_t aUptime);
|
||||
Error AdvanceToNextRouter(Type aType);
|
||||
Error AdvanceToNextPrefixEntry(void);
|
||||
Error AdvanceToNextRdnssAddrEntry(void);
|
||||
Error AdvanceToNextIfAddrEntry(const Entry<IfAddress> *aListHead);
|
||||
uint32_t GetInitUptime(void) const { return mData0; }
|
||||
void SetInitUptime(uint32_t aUptime) { mData0 = aUptime; }
|
||||
TimeMilli GetInitTime(void) const { return TimeMilli(mData1); }
|
||||
void SetInitTime(void) { mData1 = TimerMilli::GetNow().GetValue(); }
|
||||
const Entry<Router> *GetRouter(void) const { return static_cast<const Entry<Router> *>(mPtr1); }
|
||||
void SetRouter(const Entry<Router> *aRouter) { mPtr1 = aRouter; }
|
||||
Type GetType(void) const { return static_cast<Type>(mData2); }
|
||||
void SetType(Type aType) { mData2 = aType; }
|
||||
const void *GetEntry(void) const { return mPtr2; }
|
||||
void SetEntry(const void *aEntry) { mPtr2 = aEntry; }
|
||||
bool HasEntry(void) const { return mPtr2 != nullptr; }
|
||||
PrefixType GetPrefixType(void) const { return static_cast<PrefixType>(mData3); }
|
||||
void SetPrefixType(PrefixType aType) { mData3 = aType; }
|
||||
|
||||
template <typename ObjectType> const Entry<ObjectType> *GetEntry(void) const
|
||||
{
|
||||
return static_cast<const Entry<ObjectType> *>(mPtr2);
|
||||
}
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
static constexpr uint16_t kMaxRouters = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_ROUTERS;
|
||||
static constexpr uint16_t kMaxEntries = OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES;
|
||||
|
||||
union SharedEntry
|
||||
{
|
||||
SharedEntry(void) { mNext = nullptr; }
|
||||
void SetNext(SharedEntry *aNext) { mNext = aNext; }
|
||||
SharedEntry *GetNext(void) { return mNext; }
|
||||
const SharedEntry *GetNext(void) const { return mNext; }
|
||||
|
||||
template <class Type> Entry<Type> &GetEntry(void);
|
||||
|
||||
SharedEntry *mNext;
|
||||
Entry<OnLinkPrefix> mOnLinkEntry;
|
||||
Entry<RoutePrefix> mRouteEntry;
|
||||
Entry<RdnssAddress> mRdnssAddrEntry;
|
||||
Entry<IfAddress> mIfAddrEntry;
|
||||
};
|
||||
#endif
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
struct DecisionFactors : public Clearable<DecisionFactors>, public Equatable<DecisionFactors>
|
||||
{
|
||||
DecisionFactors(void) { Clear(); }
|
||||
|
||||
bool HasFavoredOnLink(void) const { return (mFavoredOnLinkPrefix.GetLength() != 0); }
|
||||
void UpdateFlagsFrom(const Router &aRouter);
|
||||
void UpdateFrom(const OnLinkPrefix &aOnLinkPrefix);
|
||||
void UpdateFrom(const RoutePrefix &aRoutePrefix);
|
||||
|
||||
Ip6::Prefix mFavoredOnLinkPrefix;
|
||||
bool mHasNonUlaRoute : 1;
|
||||
bool mHasNonUlaOnLink : 1;
|
||||
bool mHasUlaOnLink : 1;
|
||||
bool mHeaderManagedAddressConfigFlag : 1;
|
||||
bool mHeaderOtherConfigFlag : 1;
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
uint16_t mReachablePeerBrCount;
|
||||
#endif
|
||||
};
|
||||
|
||||
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
void ProcessRaHeader(const RouterAdvert::Header &aRaHeader, Router &aRouter, RouterAdvOrigin aRaOrigin);
|
||||
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);
|
||||
void SendNeighborSolicitToRouter(const Router &aRouter);
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_MULTI_AIL_DETECTION_ENABLE
|
||||
uint16_t CountReachablePeerBrs(void) const;
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
|
||||
void ReportChangesToHistoryTracker(Router &aRouter, bool aRemoved);
|
||||
#endif
|
||||
// Tasklet or timer callbacks
|
||||
void HandleSignalTask(void);
|
||||
void HandleRdnssAddrTask(void);
|
||||
void HandleExpirationTimer(void);
|
||||
void HandleStaleTimer(void);
|
||||
void HandleRouterTimer(void);
|
||||
void HandleRdnssAddrTimer(void);
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
template <class Type> Entry<Type> *AllocateEntry(void) { return Entry<Type>::Allocate(); }
|
||||
#else
|
||||
template <class Type> Entry<Type> *AllocateEntry(void);
|
||||
#endif
|
||||
|
||||
using SignalTask = TaskletIn<RxRaTracker, &RxRaTracker::HandleSignalTask>;
|
||||
using RdnssAddrTask = TaskletIn<RxRaTracker, &RxRaTracker::HandleRdnssAddrTask>;
|
||||
using ExpirationTimer = TimerMilliIn<RxRaTracker, &RxRaTracker::HandleExpirationTimer>;
|
||||
using StaleTimer = TimerMilliIn<RxRaTracker, &RxRaTracker::HandleStaleTimer>;
|
||||
using RouterTimer = TimerMilliIn<RxRaTracker, &RxRaTracker::HandleRouterTimer>;
|
||||
using RdnssAddrTimer = TimerMilliIn<RxRaTracker, &RxRaTracker::HandleRdnssAddrTimer>;
|
||||
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;
|
||||
RdnssAddrTimer mRdnssAddrTimer;
|
||||
SignalTask mSignalTask;
|
||||
RdnssAddrTask mRdnssAddrTask;
|
||||
RdnssCallback mRdnssCallback;
|
||||
RouterAdvert::Header mLocalRaHeader;
|
||||
TimeMilli mLocalRaHeaderUpdateTime;
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
Pool<SharedEntry, kMaxEntries> mEntryPool;
|
||||
Pool<Entry<Router>, kMaxRouters> mRouterPool;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// Template specializations and declarations
|
||||
|
||||
template <> inline RxRaTracker::Entry<OnLinkPrefix> &RxRaTracker::SharedEntry::GetEntry(void) { return mOnLinkEntry; }
|
||||
|
||||
template <> inline RxRaTracker::Entry<RoutePrefix> &RxRaTracker::SharedEntry::GetEntry(void) { return mRouteEntry; }
|
||||
|
||||
template <> inline RxRaTracker::Entry<RdnssAddress> &RxRaTracker::SharedEntry::GetEntry(void)
|
||||
{
|
||||
return mRdnssAddrEntry;
|
||||
}
|
||||
|
||||
template <> inline RxRaTracker::Entry<IfAddress> &RxRaTracker::SharedEntry::GetEntry(void) { return mIfAddrEntry; }
|
||||
|
||||
// Declare template (full) specializations for `Router` type.
|
||||
|
||||
template <> RxRaTracker::Entry<RxRaTracker::Router> *RxRaTracker::AllocateEntry(void);
|
||||
|
||||
template <> void RxRaTracker::Entry<RxRaTracker::Router>::Free(void);
|
||||
|
||||
#endif // #if !OPENTHREAD_CONFIG_BORDER_ROUTING_USE_HEAP_ENABLE
|
||||
|
||||
} // namespace BorderRouter
|
||||
} // namespace ot
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
|
||||
#endif // RX_RA_TRACKER_HPP_
|
||||
@@ -267,6 +267,7 @@ Instance::Instance(void)
|
||||
, mAnnounceSender(*this)
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
, mRxRaTracker(*this)
|
||||
, mRoutingManager(*this)
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
, mNetDataBrTracker(*this)
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
#include "backbone_router/bbr_manager.hpp"
|
||||
#include "border_router/dhcp6_pd_client.hpp"
|
||||
#include "border_router/routing_manager.hpp"
|
||||
#include "border_router/rx_ra_tracker.hpp"
|
||||
#include "coap/coap_secure.hpp"
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/notifier.hpp"
|
||||
@@ -710,6 +711,7 @@ private:
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
BorderRouter::RxRaTracker mRxRaTracker;
|
||||
BorderRouter::RoutingManager mRoutingManager;
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
BorderRouter::NetDataBrTracker mNetDataBrTracker;
|
||||
@@ -1093,6 +1095,7 @@ template <> inline LinkMetrics::Subject &Instance::Get(void) { return mSubject;
|
||||
#endif // (OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2)
|
||||
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
template <> inline BorderRouter::RxRaTracker &Instance::Get(void) { return mRxRaTracker; }
|
||||
template <> inline BorderRouter::RoutingManager &Instance::Get(void) { return mRoutingManager; }
|
||||
template <> inline BorderRouter::InfraIf &Instance::Get(void) { return mRoutingManager.mInfraIf; }
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_TRACK_PEER_BR_INFO_ENABLE
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include <openthread/platform/radio.h>
|
||||
|
||||
#include "border_router/routing_manager.hpp"
|
||||
#include "border_router/rx_ra_tracker.hpp"
|
||||
#include "common/as_core_type.hpp"
|
||||
#include "common/clearable.hpp"
|
||||
#include "common/locator.hpp"
|
||||
@@ -158,6 +159,7 @@ class Local : public InstanceLocator, private NonCopyable
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
|
||||
friend class ot::BorderRouter::RoutingManager;
|
||||
friend class ot::BorderRouter::RxRaTracker;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
@@ -1080,9 +1080,9 @@ void VerifyPrefixTable(const OnLinkPrefix *aOnLinkPrefixes,
|
||||
|
||||
Log("VerifyPrefixTable()");
|
||||
|
||||
sInstance->Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(iter);
|
||||
sInstance->Get<BorderRouter::RxRaTracker>().InitIterator(iter);
|
||||
|
||||
while (sInstance->Get<BorderRouter::RoutingManager>().GetNextPrefixTableEntry(iter, entry) == kErrorNone)
|
||||
while (sInstance->Get<BorderRouter::RxRaTracker>().GetNextPrefixTableEntry(iter, entry) == kErrorNone)
|
||||
{
|
||||
bool didFind = false;
|
||||
|
||||
@@ -1168,9 +1168,9 @@ void VerifyRdnssAddressTable(const RdnssAddress *aRdnssAddresses, uint16_t aNumA
|
||||
|
||||
Log("VerifyRdnssAddressTable()");
|
||||
|
||||
sInstance->Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(iter);
|
||||
sInstance->Get<BorderRouter::RxRaTracker>().InitIterator(iter);
|
||||
|
||||
while (sInstance->Get<BorderRouter::RoutingManager>().GetNextRdnssAddrEntry(iter, entry) == kErrorNone)
|
||||
while (sInstance->Get<BorderRouter::RxRaTracker>().GetNextRdnssAddrEntry(iter, entry) == kErrorNone)
|
||||
{
|
||||
bool didFind = false;
|
||||
|
||||
@@ -1235,9 +1235,9 @@ void VerifyDiscoveredRouters(const InfraRouter *aRouters, uint16_t aNumRouters)
|
||||
|
||||
Log("VerifyDiscoveredRouters()");
|
||||
|
||||
sInstance->Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(iter);
|
||||
sInstance->Get<BorderRouter::RxRaTracker>().InitIterator(iter);
|
||||
|
||||
while (sInstance->Get<BorderRouter::RoutingManager>().GetNextRouterEntry(iter, entry) == kErrorNone)
|
||||
while (sInstance->Get<BorderRouter::RxRaTracker>().GetNextRouterEntry(iter, entry) == kErrorNone)
|
||||
{
|
||||
bool didFind = false;
|
||||
|
||||
@@ -4977,7 +4977,7 @@ void TestRdnss(void)
|
||||
// Set the RDNSS callback on Routing Manager
|
||||
|
||||
rdnssCallbackCalled = false;
|
||||
sInstance->Get<BorderRouter::RoutingManager>().SetRdnssAddrCallback(HandleRdnssChanged, &rdnssCallbackCalled);
|
||||
sInstance->Get<BorderRouter::RxRaTracker>().SetRdnssAddrCallback(HandleRdnssChanged, &rdnssCallbackCalled);
|
||||
|
||||
VerifyOrQuit(!rdnssCallbackCalled);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user