From a4223001f2f87313f9bdfcbeb8866acd6522b263 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 13 Feb 2023 08:41:42 -0800 Subject: [PATCH] [history-tracker] track changes to router table (next hop, cost) (#8734) This commit adds anew feature in `HistoryTracker` to track the history of changes to routers. In particular we track when a new router is added or removed, or when next hop and/or path cost towards a router is changed. On a cost change the recorded entry, provides the old cost value along with the new path cost. This helps to track the cost changes more easily (no need to look back at history to find the old cost value). This commit also adds CLI command `history router` for the new feature. --- include/openthread/history_tracker.h | 46 +++++++++++++++ include/openthread/instance.h | 2 +- src/cli/README_HISTORY.md | 80 ++++++++++++++++++++++++- src/cli/cli_history.cpp | 88 +++++++++++++++++++++++++++- src/core/api/history_tracker_api.cpp | 9 +++ src/core/config/history_tracker.h | 12 ++++ src/core/thread/router_table.cpp | 6 +- src/core/thread/router_table.hpp | 2 +- src/core/utils/history_tracker.cpp | 74 +++++++++++++++++++++++ src/core/utils/history_tracker.hpp | 42 +++++++++++++ 10 files changed, 356 insertions(+), 5 deletions(-) diff --git a/include/openthread/history_tracker.h b/include/openthread/history_tracker.h index 4c9b4088e..02d72f2e5 100644 --- a/include/openthread/history_tracker.h +++ b/include/openthread/history_tracker.h @@ -192,6 +192,35 @@ typedef struct otHistoryTrackerNeighborInfo bool mIsChild : 1; ///< Indicates whether or not the neighbor is a child. } otHistoryTrackerNeighborInfo; +/** + * This enumeration defines the events in a router info (i.e. whether router is added, removed, or changed). + * + */ +typedef enum +{ + OT_HISTORY_TRACKER_ROUTER_EVENT_ADDED = 0, ///< Router is added (router ID allocated). + OT_HISTORY_TRACKER_ROUTER_EVENT_REMOVED = 1, ///< Router entry is removed (router ID released). + OT_HISTORY_TRACKER_ROUTER_EVENT_NEXT_HOP_CHANGED = 2, ///< Router entry next hop and cost changed. + OT_HISTORY_TRACKER_ROUTER_EVENT_COST_CHANGED = 3, ///< Router entry path cost changed (next hop as before). +} otHistoryTrackerRouterEvent; + +#define OT_HISTORY_TRACKER_NO_NEXT_HOP 63 ///< No next hop - For `mNextHop` in `otHistoryTrackerRouterInfo`. + +#define OT_HISTORY_TRACKER_INFINITE_PATH_COST 0 ///< Infinite path cost - used in `otHistoryTrackerRouterInfo`. + +/** + * This structure represents a router table entry event. + * + */ +typedef struct otHistoryTrackerRouterInfo +{ + uint8_t mEvent : 2; ///< Router entry event (`OT_HISTORY_TRACKER_ROUTER_EVENT_*` enumeration). + uint8_t mRouterId : 6; ///< Router ID. + uint8_t mNextHop; ///< Next Hop Router ID - `OT_HISTORY_TRACKER_NO_NEXT_HOP` if no next hop. + uint8_t mOldPathCost : 4; ///< Old path cost - `OT_HISTORY_TRACKER_INFINITE_PATH_COST` if infinite or unknown. + uint8_t mPathCost : 4; ///< New path cost - `OT_HISTORY_TRACKER_INFINITE_PATH_COST` if infinite or unknown. +} otHistoryTrackerRouterInfo; + /** * This enumeration defines the events for a Network Data entry (i.e., whether an entry is added or removed). * @@ -342,6 +371,23 @@ const otHistoryTrackerNeighborInfo *otHistoryTrackerIterateNeighborHistory(otIns otHistoryTrackerIterator *aIterator, uint32_t *aEntryAge); +/** + * This function iterates over the entries in the router history list. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[in,out] aIterator A pointer to an iterator. MUST be initialized or the behavior is undefined. + * @param[out] aEntryAge A pointer to a variable to output the entry's age. MUST NOT be NULL. + * Age is provided as the duration (in milliseconds) from when entry was recorded to + * @p aIterator initialization time. It is set to `OT_HISTORY_TRACKER_MAX_AGE` for entries + * older than max age. + * + * @returns The `otHistoryTrackerRouterInfo` entry or `NULL` if no more entries in the list. + * + */ +const otHistoryTrackerRouterInfo *otHistoryTrackerIterateRouterHistory(otInstance *aInstance, + otHistoryTrackerIterator *aIterator, + uint32_t *aEntryAge); + /** * This function iterates over the entries in the Network Data on mesh prefix entry history list. * diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 30443d8c0..d7c88e390 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (284) +#define OPENTHREAD_API_VERSION (285) /** * @addtogroup api-instance diff --git a/src/cli/README_HISTORY.md b/src/cli/README_HISTORY.md index e3ea55dc8..268cf7d24 100644 --- a/src/cli/README_HISTORY.md +++ b/src/cli/README_HISTORY.md @@ -17,6 +17,7 @@ Usage : `history [command] ...` - [netinfo](#netinfo) - [prefix](#prefix) - [route](#route) +- [router](#router) - [rx](#rx) - [rxtx](#rxtx) - [tx](#tx) @@ -56,6 +57,7 @@ neighbor netinfo prefix route +router rx rxtx tx @@ -298,7 +300,7 @@ Print the history as a list. 00:06:01.711 -> event:Added prefix:fd00:dead:beef:1::/64 flags:paros pref:med rloc16:0x8800 ``` -### prefix +### route Usage `history route [list] []` @@ -337,6 +339,82 @@ Print the history as a list (last two entries). Done ``` +### router + +Usage `history router [list] []` + +Print the route table history. Each item provides: + +- Event (`Added`, `Removed`, `NextHopChnaged`, `CostChanged`) +- Router ID and RLOC16 of router +- Next Hop (Router ID and RLOC16) - `none` if no next hop. +- Path cost (old `->` new) - `inf` to indicate infinite path cost. + +Print the history as a table. + +```bash +> history router +| Age | Event | ID (RLOC16) | Next Hop | Path Cost | ++----------------------+----------------+-------------+-------------+------------+ +| 00:00:05.258 | NextHopChanged | 7 (0x1c00) | 34 (0x8800) | inf -> 3 | +| 00:00:08.604 | NextHopChanged | 34 (0x8800) | 34 (0x8800) | inf -> 2 | +| 00:00:08.604 | Added | 7 (0x1c00) | none | inf -> inf | +| 00:00:11.931 | Added | 34 (0x8800) | none | inf -> inf | +| 00:00:14.948 | Removed | 59 (0xec00) | none | inf -> inf | +| 00:00:14.948 | Removed | 54 (0xd800) | none | inf -> inf | +| 00:00:14.948 | Removed | 34 (0x8800) | none | inf -> inf | +| 00:00:14.948 | Removed | 7 (0x1c00) | none | inf -> inf | +| 00:00:54.795 | NextHopChanged | 59 (0xec00) | 34 (0x8800) | 1 -> 5 | +| 00:02:33.735 | NextHopChanged | 54 (0xd800) | none | 15 -> inf | +| 00:03:10.915 | CostChanged | 54 (0xd800) | 34 (0x8800) | 13 -> 15 | +| 00:03:45.716 | NextHopChanged | 54 (0xd800) | 34 (0x8800) | 15 -> 13 | +| 00:03:46.188 | CostChanged | 54 (0xd800) | 59 (0xec00) | 13 -> 15 | +| 00:04:19.124 | CostChanged | 54 (0xd800) | 59 (0xec00) | 11 -> 13 | +| 00:04:52.008 | CostChanged | 54 (0xd800) | 59 (0xec00) | 9 -> 11 | +| 00:05:23.176 | CostChanged | 54 (0xd800) | 59 (0xec00) | 7 -> 9 | +| 00:05:51.081 | CostChanged | 54 (0xd800) | 59 (0xec00) | 5 -> 7 | +| 00:06:48.721 | CostChanged | 54 (0xd800) | 59 (0xec00) | 3 -> 5 | +| 00:07:13.792 | NextHopChanged | 54 (0xd800) | 59 (0xec00) | 1 -> 3 | +| 00:09:28.681 | NextHopChanged | 7 (0x1c00) | 34 (0x8800) | inf -> 3 | +| 00:09:31.882 | Added | 7 (0x1c00) | none | inf -> inf | +| 00:09:51.240 | NextHopChanged | 54 (0xd800) | 54 (0xd800) | inf -> 1 | +| 00:09:54.204 | Added | 54 (0xd800) | none | inf -> inf | +| 00:10:20.645 | NextHopChanged | 34 (0x8800) | 34 (0x8800) | inf -> 2 | +| 00:10:24.242 | NextHopChanged | 59 (0xec00) | 59 (0xec00) | inf -> 1 | +| 00:10:24.242 | Added | 34 (0x8800) | none | inf -> inf | +| 00:10:41.900 | NextHopChanged | 59 (0xec00) | none | 1 -> inf | +| 00:10:42.480 | Added | 3 (0x0c00) | 3 (0x0c00) | inf -> inf | +| 00:10:43.614 | Added | 59 (0xec00) | 59 (0xec00) | inf -> 1 | +Done +``` + +Print the history as a list (last 20 entries). + +```bash +> history router list 20 +00:00:06.959 -> event:NextHopChanged router:7(0x1c00) nexthop:34(0x8800) old-cost:inf new-cost:3 +00:00:10.305 -> event:NextHopChanged router:34(0x8800) nexthop:34(0x8800) old-cost:inf new-cost:2 +00:00:10.305 -> event:Added router:7(0x1c00) nexthop:none old-cost:inf new-cost:inf +00:00:13.632 -> event:Added router:34(0x8800) nexthop:none old-cost:inf new-cost:inf +00:00:16.649 -> event:Removed router:59(0xec00) nexthop:none old-cost:inf new-cost:inf +00:00:16.649 -> event:Removed router:54(0xd800) nexthop:none old-cost:inf new-cost:inf +00:00:16.649 -> event:Removed router:34(0x8800) nexthop:none old-cost:inf new-cost:inf +00:00:16.649 -> event:Removed router:7(0x1c00) nexthop:none old-cost:inf new-cost:inf +00:00:56.496 -> event:NextHopChanged router:59(0xec00) nexthop:34(0x8800) old-cost:1 new-cost:5 +00:02:35.436 -> event:NextHopChanged router:54(0xd800) nexthop:none old-cost:15 new-cost:inf +00:03:12.616 -> event:CostChanged router:54(0xd800) nexthop:34(0x8800) old-cost:13 new-cost:15 +00:03:47.417 -> event:NextHopChanged router:54(0xd800) nexthop:34(0x8800) old-cost:15 new-cost:13 +00:03:47.889 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:13 new-cost:15 +00:04:20.825 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:11 new-cost:13 +00:04:53.709 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:9 new-cost:11 +00:05:24.877 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:7 new-cost:9 +00:05:52.782 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:5 new-cost:7 +00:06:50.422 -> event:CostChanged router:54(0xd800) nexthop:59(0xec00) old-cost:3 new-cost:5 +00:07:15.493 -> event:NextHopChanged router:54(0xd800) nexthop:59(0xec00) old-cost:1 new-cost:3 +00:09:30.382 -> event:NextHopChanged router:7(0x1c00) nexthop:34(0x8800) old-cost:inf new-cost:3 +Done +``` + ### rx Usage `history rx [list] []` diff --git a/src/cli/cli_history.cpp b/src/cli/cli_history.cpp index b712b26ab..e5285658c 100644 --- a/src/cli/cli_history.cpp +++ b/src/cli/cli_history.cpp @@ -256,6 +256,92 @@ exit: return error; } +template <> otError History::Process(Arg aArgs[]) +{ + static const char *const kEventString[] = { + /* (0) OT_HISTORY_TRACKER_ROUTER_EVENT_ADDED -> */ "Added", + /* (1) OT_HISTORY_TRACKER_ROUTER_EVENT_REMOVED -> */ "Removed", + /* (2) OT_HISTORY_TRACKER_ROUTER_EVENT_NEXT_HOP_CHANGED -> */ "NextHopChanged", + /* (3) OT_HISTORY_TRACKER_ROUTER_EVENT_COST_CHANGED -> */ "CostChanged", + }; + + constexpr uint8_t kRouterIdOffset = 10; // Bit offset of Router ID in RLOC16 + + otError error; + bool isList; + uint16_t numEntries; + otHistoryTrackerIterator iterator; + const otHistoryTrackerRouterInfo *info; + uint32_t entryAge; + char ageString[OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE]; + + static_assert(0 == OT_HISTORY_TRACKER_ROUTER_EVENT_ADDED, "EVENT_ADDED is incorrect"); + static_assert(1 == OT_HISTORY_TRACKER_ROUTER_EVENT_REMOVED, "EVENT_REMOVED is incorrect"); + static_assert(2 == OT_HISTORY_TRACKER_ROUTER_EVENT_NEXT_HOP_CHANGED, "EVENT_NEXT_HOP_CHANGED is incorrect"); + static_assert(3 == OT_HISTORY_TRACKER_ROUTER_EVENT_COST_CHANGED, "EVENT_COST_CHANGED is incorrect"); + + SuccessOrExit(error = ParseArgs(aArgs, isList, numEntries)); + + if (!isList) + { + // | Age | Event | ID (RlOC16) | Next Hop | Path Cost | + // +----------------------+----------------+-------------+------------+-------------+ + + static const char *const kRouterInfoTitles[] = { + "Age", "Event", "ID (RLOC16)", "Next Hop", "Path Cost", + }; + + static const uint8_t kRouterInfoColumnWidths[] = {22, 16, 13, 13, 12}; + + OutputTableHeader(kRouterInfoTitles, kRouterInfoColumnWidths); + } + + otHistoryTrackerInitIterator(&iterator); + + for (uint16_t index = 0; (numEntries == 0) || (index < numEntries); index++) + { + info = otHistoryTrackerIterateRouterHistory(GetInstancePtr(), &iterator, &entryAge); + VerifyOrExit(info != nullptr); + + otHistoryTrackerEntryAgeToString(entryAge, ageString, sizeof(ageString)); + + OutputFormat(isList ? "%s -> event:%s router:%u(0x%04x) nexthop:" : "| %20s | %-14s | %2u (0x%04x) | ", + ageString, kEventString[info->mEvent], info->mRouterId, + static_cast(info->mRouterId) << kRouterIdOffset); + + if (info->mNextHop != OT_HISTORY_TRACKER_NO_NEXT_HOP) + { + OutputFormat(isList ? "%u(0x%04x)" : "%2u (0x%04x)", info->mNextHop, + static_cast(info->mNextHop) << kRouterIdOffset); + } + else + { + OutputFormat(isList ? "%s" : "%11s", "none"); + } + + if (info->mOldPathCost != OT_HISTORY_TRACKER_INFINITE_PATH_COST) + { + OutputFormat(isList ? " old-cost:%u" : " | %3u ->", info->mOldPathCost); + } + else + { + OutputFormat(isList ? " old-cost:inf" : " | inf ->"); + } + + if (info->mPathCost != OT_HISTORY_TRACKER_INFINITE_PATH_COST) + { + OutputLine(isList ? " new-cost:%u" : " %3u |", info->mPathCost); + } + else + { + OutputLine(isList ? " new-cost:inf" : " inf |"); + } + } + +exit: + return error; +} + template <> otError History::Process(Arg aArgs[]) { otError error; @@ -659,7 +745,7 @@ otError History::Process(Arg aArgs[]) static constexpr Command kCommands[] = { CmdEntry("ipaddr"), CmdEntry("ipmaddr"), CmdEntry("neighbor"), CmdEntry("netinfo"), CmdEntry("prefix"), - CmdEntry("route"), CmdEntry("rx"), CmdEntry("rxtx"), CmdEntry("tx"), + CmdEntry("route"), CmdEntry("router"), CmdEntry("rx"), CmdEntry("rxtx"), CmdEntry("tx"), }; #undef CmdEntry diff --git a/src/core/api/history_tracker_api.cpp b/src/core/api/history_tracker_api.cpp index d1a6b05c2..f3d0357c3 100644 --- a/src/core/api/history_tracker_api.cpp +++ b/src/core/api/history_tracker_api.cpp @@ -103,6 +103,15 @@ const otHistoryTrackerNeighborInfo *otHistoryTrackerIterateNeighborHistory(otIns return AsCoreType(aInstance).Get().IterateNeighborHistory(AsCoreType(aIterator), *aEntryAge); } +const otHistoryTrackerRouterInfo *otHistoryTrackerIterateRouterHistory(otInstance *aInstance, + otHistoryTrackerIterator *aIterator, + uint32_t *aEntryAge) +{ + AssertPointerIsNotNull(aEntryAge); + + return AsCoreType(aInstance).Get().IterateRouterHistory(AsCoreType(aIterator), *aEntryAge); +} + const otHistoryTrackerOnMeshPrefixInfo *otHistoryTrackerIterateOnMeshPrefixHistory(otInstance *aInstance, otHistoryTrackerIterator *aIterator, uint32_t *aEntryAge) diff --git a/src/core/config/history_tracker.h b/src/core/config/history_tracker.h index 32da285aa..591474a3f 100644 --- a/src/core/config/history_tracker.h +++ b/src/core/config/history_tracker.h @@ -127,6 +127,18 @@ #define OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE 64 #endif +/** + * @def OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE + * + * Specifies the maximum number of entries in router table history list. + * + * Can be set to zero to configure History Tracker module not to collect any router table history. + * + */ +#ifndef OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE +#define OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE 256 +#endif + /** * @def OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE * diff --git a/src/core/thread/router_table.cpp b/src/core/thread/router_table.cpp index 71d78c8f2..fb6feb5b5 100644 --- a/src/core/thread/router_table.cpp +++ b/src/core/thread/router_table.cpp @@ -871,10 +871,14 @@ void RouterTable::HandleTableChanged(void) #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) LogRouteTable(); #endif + +#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE + Get().RecordRouterTableChange(); +#endif } #if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO) -void RouterTable::LogRouteTable(void) +void RouterTable::LogRouteTable(void) const { static constexpr uint16_t kStringSize = 128; diff --git a/src/core/thread/router_table.hpp b/src/core/thread/router_table.hpp index 1e4e5da4b..02b6f2fc4 100644 --- a/src/core/thread/router_table.hpp +++ b/src/core/thread/router_table.hpp @@ -440,7 +440,7 @@ private: void SignalTableChanged(void); void HandleTableChanged(void); - void LogRouteTable(void); + void LogRouteTable(void) const; class RouterIdMap { diff --git a/src/core/utils/history_tracker.cpp b/src/core/utils/history_tracker.cpp index 9fa465d35..fece22fad 100644 --- a/src/core/utils/history_tracker.cpp +++ b/src/core/utils/history_tracker.cpp @@ -59,6 +59,10 @@ HistoryTracker::HistoryTracker(Instance &aInstance) #endif { mTimer.Start(kAgeCheckPeriod); + +#if OPENTHREAD_FTD && (OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE > 0) + memset(mRouterEntries, 0, sizeof(mRouterEntries)); +#endif } void HistoryTracker::RecordNetworkInfo(void) @@ -279,6 +283,76 @@ exit: return; } +#if OPENTHREAD_FTD +void HistoryTracker::RecordRouterTableChange(void) +{ +#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE > 0 + + for (uint8_t routerId = 0; routerId <= Mle::kMaxRouterId; routerId++) + { + RouterInfo entry; + RouterEntry &oldEntry = mRouterEntries[routerId]; + + entry.mRouterId = routerId; + + if (Get().IsAllocated(routerId)) + { + uint16_t nextHopRloc; + uint8_t pathCost; + + Get().GetNextHopAndPathCost(Mle::Rloc16FromRouterId(routerId), nextHopRloc, pathCost); + + entry.mNextHop = (nextHopRloc == Mle::kInvalidRloc16) ? kNoNextHop : Mle::RouterIdFromRloc16(nextHopRloc); + entry.mPathCost = (pathCost < Mle::kMaxRouteCost) ? pathCost : 0; + + if (!oldEntry.mIsAllocated) + { + entry.mEvent = kRouterAdded; + entry.mOldPathCost = 0; + } + else if (oldEntry.mNextHop != entry.mNextHop) + { + entry.mEvent = kRouterNextHopChanged; + entry.mOldPathCost = oldEntry.mPathCost; + } + else if ((entry.mNextHop != kNoNextHop) && (oldEntry.mPathCost != entry.mPathCost)) + { + entry.mEvent = kRouterCostChanged; + entry.mOldPathCost = oldEntry.mPathCost; + } + else + { + continue; + } + + mRouterHistory.AddNewEntry(entry); + + oldEntry.mIsAllocated = true; + oldEntry.mNextHop = entry.mNextHop; + oldEntry.mPathCost = entry.mPathCost; + } + else + { + // `routerId` is not allocated. + + if (oldEntry.mIsAllocated) + { + entry.mEvent = kRouterRemoved; + entry.mNextHop = Mle::kInvalidRouterId; + entry.mOldPathCost = 0; + entry.mPathCost = 0; + + mRouterHistory.AddNewEntry(entry); + + oldEntry.mIsAllocated = false; + } + } + } + +#endif // (OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE > 0) +} +#endif // OPENTHREAD_FTD + #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA void HistoryTracker::RecordNetworkDataChange(void) { diff --git a/src/core/utils/history_tracker.hpp b/src/core/utils/history_tracker.hpp index f92d8c49d..a7bcee2eb 100644 --- a/src/core/utils/history_tracker.hpp +++ b/src/core/utils/history_tracker.hpp @@ -54,6 +54,7 @@ #include "thread/mle_types.hpp" #include "thread/neighbor_table.hpp" #include "thread/network_data.hpp" +#include "thread/router_table.hpp" namespace ot { namespace Utils { @@ -78,6 +79,9 @@ class HistoryTracker : public InstanceLocator, private NonCopyable friend class ot::Mle::Mle; friend class ot::NeighborTable; friend class ot::Ip6::Netif; +#if OPENTHREAD_FTD + friend class ot::RouterTable; +#endif public: /** @@ -94,6 +98,14 @@ public: */ static constexpr uint16_t kEntryAgeStringSize = OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE; + /** + * This constants specifid no next hop. + * + * Used for `mNextHop` in `RouteInfo` struture. + * + */ + static constexpr uint8_t kNoNextHop = OT_HISTORY_TRACKER_NO_NEXT_HOP; + /** * This type represents an iterator to iterate through a history list. * @@ -125,6 +137,7 @@ public: typedef otHistoryTrackerMulticastAddressInfo MulticastAddressInfo; ///< Multicast IPv6 address info. typedef otHistoryTrackerMessageInfo MessageInfo; ///< RX/TX IPv6 message info. typedef otHistoryTrackerNeighborInfo NeighborInfo; ///< Neighbor info. + typedef otHistoryTrackerRouterInfo RouterInfo; ///< Router info. typedef otHistoryTrackerOnMeshPrefixInfo OnMeshPrefixInfo; ///< Network Data on mesh prefix info. typedef otHistoryTrackerExternalRouteInfo ExternalRouteInfo; ///< Network Data external route info @@ -226,6 +239,11 @@ public: return mNeighborHistory.Iterate(aIterator, aEntryAge); } + const RouterInfo *IterateRouterHistory(Iterator &aIterator, uint32_t &aEntryAge) const + { + return mRouterHistory.Iterate(aIterator, aEntryAge); + } + const OnMeshPrefixInfo *IterateOnMeshPrefixHistory(Iterator &aIterator, uint32_t &aEntryAge) const { return mOnMeshPrefixHistory.Iterate(aIterator, aEntryAge); @@ -265,6 +283,7 @@ private: static constexpr uint16_t kRxListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_RX_LIST_SIZE; static constexpr uint16_t kTxListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_TX_LIST_SIZE; static constexpr uint16_t kNeighborListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE; + static constexpr uint16_t kRouterListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE; static constexpr uint16_t kOnMeshPrefixListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE; static constexpr uint16_t kExternalRouteListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE; @@ -282,6 +301,13 @@ private: static constexpr NeighborEvent kNeighborChanged = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED; static constexpr NeighborEvent kNeighborRestoring = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING; + typedef otHistoryTrackerRouterEvent RouterEvent; + + static constexpr RouterEvent kRouterAdded = OT_HISTORY_TRACKER_ROUTER_EVENT_ADDED; + static constexpr RouterEvent kRouterRemoved = OT_HISTORY_TRACKER_ROUTER_EVENT_REMOVED; + static constexpr RouterEvent kRouterNextHopChanged = OT_HISTORY_TRACKER_ROUTER_EVENT_NEXT_HOP_CHANGED; + static constexpr RouterEvent kRouterCostChanged = OT_HISTORY_TRACKER_ROUTER_EVENT_COST_CHANGED; + typedef otHistoryTrackerNetDataEvent NetDataEvent; static constexpr NetDataEvent kNetDataEntryAdded = OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED; @@ -387,6 +413,9 @@ private: Ip6::Netif::AddressOrigin aAddressOrigin); void HandleNotifierEvents(Events aEvents); void HandleTimer(void); +#if OPENTHREAD_FTD + void RecordRouterTableChange(void); +#endif #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA void RecordNetworkDataChange(void); void RecordOnMeshPrefixEvent(NetDataEvent aEvent, const NetworkData::OnMeshPrefixConfig &aPrefix); @@ -401,11 +430,23 @@ private: EntryList mRxHistory; EntryList mTxHistory; EntryList mNeighborHistory; + EntryList mRouterHistory; EntryList mOnMeshPrefixHistory; EntryList mExternalRouteHistory; TrackerTimer mTimer; +#if OPENTHREAD_FTD && (OPENTHREAD_CONFIG_HISTORY_TRACKER_ROUTER_LIST_SIZE > 0) + struct RouterEntry + { + bool mIsAllocated : 1; + uint8_t mNextHop : 6; + uint8_t mPathCost : 4; + }; + + RouterEntry mRouterEntries[Mle::kMaxRouterId + 1]; +#endif + #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA NetworkData::MutableNetworkData mPreviousNetworkData; @@ -419,6 +460,7 @@ DefineCoreType(otHistoryTrackerIterator, Utils::HistoryTracker::Iterator); DefineCoreType(otHistoryTrackerNetworkInfo, Utils::HistoryTracker::NetworkInfo); DefineCoreType(otHistoryTrackerMessageInfo, Utils::HistoryTracker::MessageInfo); DefineCoreType(otHistoryTrackerNeighborInfo, Utils::HistoryTracker::NeighborInfo); +DefineCoreType(otHistoryTrackerRouterInfo, Utils::HistoryTracker::RouterInfo); DefineCoreType(otHistoryTrackerOnMeshPrefixInfo, Utils::HistoryTracker::OnMeshPrefixInfo); DefineCoreType(otHistoryTrackerExternalRouteInfo, Utils::HistoryTracker::ExternalRouteInfo);