From ee807d300160b726ea067f7ffcdc616f7d92ea0a Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Tue, 24 Aug 2021 15:07:02 -0700 Subject: [PATCH] [history-tracker] add support for neighbor table history (#6947) This commit adds support in `HistoryTracker` to record the history of changes to the neighbor table. An entry is recorded when a child or router neighbor is added, removed, changed, or being restored (the restored entries are only used for the previous children list retrieved from non-volatile settings on the device (re)start). Each entry provides: - Timestamp - Type: Child or Router - Event: Added, Removed, Changed - Extended Address - RLOC16 - MLE Link Mode (rx-on-when-idle, FTD/MDT, full-netdata). - Average RSS (in dBm) of received frames from the neighbor at the time the entry was recorded. This commit also updates CLI and adds `history neighbor` command to get the neighbor history. It also updates the documentation. --- include/openthread/history_tracker.h | 53 ++++++++++++++++++++++- include/openthread/instance.h | 2 +- src/cli/README_HISTORY.md | 52 +++++++++++++++++++++- src/cli/cli_history.cpp | 65 ++++++++++++++++++++++++++++ src/cli/cli_history.hpp | 5 ++- src/core/api/history_tracker_api.cpp | 10 +++++ src/core/config/history_tracker.h | 12 +++++ src/core/thread/child_table.cpp | 1 + src/core/thread/neighbor_table.cpp | 11 ++++- src/core/utils/history_tracker.cpp | 62 ++++++++++++++++++++++++++ src/core/utils/history_tracker.hpp | 37 +++++++++++++--- 11 files changed, 296 insertions(+), 14 deletions(-) diff --git a/include/openthread/history_tracker.h b/include/openthread/history_tracker.h index 979c30bca..517c6c83a 100644 --- a/include/openthread/history_tracker.h +++ b/include/openthread/history_tracker.h @@ -61,6 +61,8 @@ extern "C" { */ #define OT_HISTORY_TRACKER_MAX_AGE (49 * 24 * 60 * 60 * 1000u) +#define OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE 21 ///< Recommended size for string representation of an entry age. + /** * This type represents an iterator to iterate through a history list. * @@ -124,6 +126,38 @@ typedef struct otHistoryTrackerMessageInfo bool mRadioTrelUdp6 : 1; ///< Indicates whether msg was sent/received over a TREL radio link. } otHistoryTrackerMessageInfo; +/** + * This enumeration defines the events in a neighbor info (i.e. whether neighbor is added, removed, or changed). + * + * Event `OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING` is applicable to child neighbors only. It is triggered after + * the device (re)starts and when the previous children list is retrieved from non-volatile settings and the device + * tries to restore connection to them. + * + */ +typedef enum +{ + OT_HISTORY_TRACKER_NEIGHBOR_EVENT_ADDED = 0, ///< Neighbor is added. + OT_HISTORY_TRACKER_NEIGHBOR_EVENT_REMOVED = 1, ///< Neighbor is removed. + OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED = 2, ///< Neighbor changed (e.g., device mode flags changed). + OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING = 3, ///< Neighbor is being restored (applicable to child only). +} otHistoryTrackerNeighborEvent; + +/** + * This structure represents a neighbor info. + * + */ +typedef struct otHistoryTrackerNeighborInfo +{ + otExtAddress mExtAddress; ///< Neighbor's Extended Address. + uint16_t mRloc16; ///< Neighbor's RLOC16. + int8_t mAverageRssi; ///< Average RSSI of rx frames from neighbor at the time of recording entry. + uint8_t mEvent : 2; ///< Indicates the event (`OT_HISTORY_TRACKER_NEIGHBOR_EVENT_*` enumeration). + bool mRxOnWhenIdle : 1; ///< Rx-on-when-idle. + bool mFullThreadDevice : 1; ///< Full Thread Device. + bool mFullNetworkData : 1; ///< Full Network Data. + bool mIsChild : 1; ///< Indicates whether or not the neighbor is a child. +} otHistoryTrackerNeighborInfo; + /** * This function initializes an `otHistoryTrackerIterator`. * @@ -191,7 +225,22 @@ const otHistoryTrackerMessageInfo *otHistoryTrackerIterateTxHistory(otInstance * otHistoryTrackerIterator *aIterator, uint32_t * aEntryAge); -#define OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE 21 ///< Recommended size for string representation of an entry age. +/** + * This function iterates over the entries in the neighbor history list. + * + * @param[in] aInstance A pointer to the OpenThread instance. + * @param[inout] 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 `otHistoryTrackerNeighborInfo` entry or `NULL` if no more entries in the list. + * + */ +const otHistoryTrackerNeighborInfo *otHistoryTrackerIterateNeighborHistory(otInstance * aInstance, + otHistoryTrackerIterator *aIterator, + uint32_t * aEntryAge); /** * This function converts a given entry age to a human-readable string. @@ -204,7 +253,7 @@ const otHistoryTrackerMessageInfo *otHistoryTrackerIterateTxHistory(otInstance * * * @param[in] aEntryAge The entry age (duration in msec). * @param[out] aBuffer A pointer to a char array to output the string (MUST NOT be NULL). - * @param[in] aSize The size of @p aBuffer (in bytes). Recommended to use `OT_IP6_ADDRESS_STRING_SIZE`. + * @param[in] aSize The size of @p aBuffer. Recommended to use `OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE`. * */ void otHistoryTrackerEntryAgeToString(uint32_t aEntryAge, char *aBuffer, uint16_t aSize); diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 62cae648a..6a1afdcb6 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 (156) +#define OPENTHREAD_API_VERSION (157) /** * @addtogroup api-instance diff --git a/src/cli/README_HISTORY.md b/src/cli/README_HISTORY.md index be503653c..8e6c59ded 100644 --- a/src/cli/README_HISTORY.md +++ b/src/cli/README_HISTORY.md @@ -11,6 +11,7 @@ The number of entries recorded for each history list is configurable through a s Usage : `history [command] ...` - [help](#help) +- [neighbor](#neighbor) - [netinfo](#netinfo) - [rx](#rx) - [rxtx](#rxtx) @@ -45,6 +46,7 @@ Print SRP client help menu. ```bash > history help help +neighbor netinfo rx rxtx @@ -53,11 +55,59 @@ Done > ``` +### neighbor + +Usage `history neighbor [list] []` + +Print the neighbor table history. Each entry provides: + +- Type: Child or Router +- Event: Added, Removed, Changed (e.g., mode change). +- Extended Address +- RLOC16 +- MLE Link Mode +- Average RSS (in dBm) of received frames from neighbor at the time the entry was recorded + +Print the neighbor history as a table. + +```bash +> history neighbor +| Age | Type | Event | Extended Address | RLOC16 | Mode | Ave RSS | ++----------------------+--------+-----------+------------------+--------+------+---------+ +| 00:00:29.233 | Child | Added | ae5105292f0b9169 | 0x8404 | - | -20 | +| 00:01:38.368 | Child | Removed | ae5105292f0b9169 | 0x8401 | - | -20 | +| 00:04:27.181 | Child | Changed | ae5105292f0b9169 | 0x8401 | - | -20 | +| 00:04:51.236 | Router | Added | 865c7ca38a5fa960 | 0x9400 | rdn | -20 | +| 00:04:51.587 | Child | Removed | 865c7ca38a5fa960 | 0x8402 | rdn | -20 | +| 00:05:22.764 | Child | Changed | ae5105292f0b9169 | 0x8401 | rn | -20 | +| 00:06:40.764 | Child | Added | 4ec99efc874a1841 | 0x8403 | r | -20 | +| 00:06:44.060 | Child | Added | 865c7ca38a5fa960 | 0x8402 | rdn | -20 | +| 00:06:49.515 | Child | Added | ae5105292f0b9169 | 0x8401 | - | -20 | +Done +``` + +Print the neighbor history as a list. + +```bash + +> history neighbor list +00:00:34.753 -> type:Child event:Added extaddr:ae5105292f0b9169 rloc16:0x8404 mode:- rss:-20 +00:01:43.888 -> type:Child event:Removed extaddr:ae5105292f0b9169 rloc16:0x8401 mode:- rss:-20 +00:04:32.701 -> type:Child event:Changed extaddr:ae5105292f0b9169 rloc16:0x8401 mode:- rss:-20 +00:04:56.756 -> type:Router event:Added extaddr:865c7ca38a5fa960 rloc16:0x9400 mode:rdn rss:-20 +00:04:57.107 -> type:Child event:Removed extaddr:865c7ca38a5fa960 rloc16:0x8402 mode:rdn rss:-20 +00:05:28.284 -> type:Child event:Changed extaddr:ae5105292f0b9169 rloc16:0x8401 mode:rn rss:-20 +00:06:46.284 -> type:Child event:Added extaddr:4ec99efc874a1841 rloc16:0x8403 mode:r rss:-20 +00:06:49.580 -> type:Child event:Added extaddr:865c7ca38a5fa960 rloc16:0x8402 mode:rdn rss:-20 +00:06:55.035 -> type:Child event:Added extaddr:ae5105292f0b9169 rloc16:0x8401 mode:- rss:-20 +Done +``` + ### netinfo Usage `history netinfo [list] []` -Print the Network Info history. Each Network Info provides +Print the Network Info history. Each Network Info provides: - Device Role - MLE Link Mode diff --git a/src/cli/cli_history.cpp b/src/cli/cli_history.cpp index d5ede5529..ce3d33e29 100644 --- a/src/cli/cli_history.cpp +++ b/src/cli/cli_history.cpp @@ -80,6 +80,71 @@ otError History::ParseArgs(Arg aArgs[], bool &aIsList, uint16_t &aNumEntries) co return aArgs[0].IsEmpty() ? OT_ERROR_NONE : OT_ERROR_INVALID_ARGS; } +otError History::ProcessNeighbor(Arg aArgs[]) +{ + static const char *const kEventString[] = { + /* (0) OT_HISTORY_TRACKER_NEIGHBOR_EVENT_ADDED -> */ "Added", + /* (1) OT_HISTORY_TRACKER_NEIGHBOR_EVENT_REMOVED -> */ "Removed", + /* (2) OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED -> */ "Changed", + /* (3) OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING -> */ "Restoring", + }; + + otError error; + bool isList; + uint16_t numEntries; + otHistoryTrackerIterator iterator; + const otHistoryTrackerNeighborInfo *info; + uint32_t entryAge; + char ageString[OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE]; + otLinkModeConfig mode; + char linkModeString[Interpreter::kLinkModeStringSize]; + + static_assert(0 == OT_HISTORY_TRACKER_NEIGHBOR_EVENT_ADDED, "NEIGHBOR_EVENT_ADDED value is incorrect"); + static_assert(1 == OT_HISTORY_TRACKER_NEIGHBOR_EVENT_REMOVED, "NEIGHBOR_EVENT_REMOVED value is incorrect"); + static_assert(2 == OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED, "NEIGHBOR_EVENT_CHANGED value is incorrect"); + static_assert(3 == OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING, "NEIGHBOR_EVENT_RESTORING value is incorrect"); + + SuccessOrExit(error = ParseArgs(aArgs, isList, numEntries)); + + if (!isList) + { + // | Age | Type | Event | Extended Address | RLOC16 | Mode | Ave RSS | + // +----------------------+--------+-----------+------------------+--------+------+---------+ + + static const char *const kNeighborInfoTitles[] = { + "Age", "Type", "Event", "Extended Address", "RLOC16", "Mode", "Ave RSS", + }; + + static const uint8_t kNeighborInfoColumnWidths[] = {22, 8, 11, 18, 8, 6, 9}; + + mInterpreter.OutputTableHeader(kNeighborInfoTitles, kNeighborInfoColumnWidths); + } + + otHistoryTrackerInitIterator(&iterator); + + for (uint16_t index = 0; (numEntries == 0) || (index < numEntries); index++) + { + info = otHistoryTrackerIterateNeighborHistory(mInterpreter.mInstance, &iterator, &entryAge); + VerifyOrExit(info != nullptr); + + otHistoryTrackerEntryAgeToString(entryAge, ageString, sizeof(ageString)); + + mode.mRxOnWhenIdle = info->mRxOnWhenIdle; + mode.mDeviceType = info->mFullThreadDevice; + mode.mNetworkData = info->mFullNetworkData; + Interpreter::LinkModeToString(mode, linkModeString); + + mInterpreter.OutputFormat(isList ? "%s -> type:%s event:%s extaddr:" : "| %20s | %-6s | %-9s | ", ageString, + info->mIsChild ? "Child" : "Router", kEventString[info->mEvent]); + mInterpreter.OutputExtAddress(info->mExtAddress); + mInterpreter.OutputLine(isList ? " rloc16:0x%04x mode:%s rss:%d" : " | 0x%04x | %-4s | %7d |", info->mRloc16, + linkModeString, info->mAverageRssi); + } + +exit: + return error; +} + otError History::ProcessNetInfo(Arg aArgs[]) { otError error; diff --git a/src/cli/cli_history.hpp b/src/cli/cli_history.hpp index 223a705be..44bb7f787 100644 --- a/src/cli/cli_history.hpp +++ b/src/cli/cli_history.hpp @@ -97,6 +97,7 @@ private: otError ProcessHelp(Arg aArgs[]); otError ProcessNetInfo(Arg aArgs[]); + otError ProcessNeighbor(Arg aArgs[]); otError ProcessRx(Arg aArgs[]); otError ProcessRxTx(Arg aArgs[]); otError ProcessTx(Arg aArgs[]); @@ -111,8 +112,8 @@ private: static const char *MessageTypeToString(const otHistoryTrackerMessageInfo &aInfo); static constexpr Command sCommands[] = { - {"help", &History::ProcessHelp}, {"netinfo", &History::ProcessNetInfo}, {"rx", &History::ProcessRx}, - {"rxtx", &History::ProcessRxTx}, {"tx", &History::ProcessTx}, + {"help", &History::ProcessHelp}, {"neighbor", &History::ProcessNeighbor}, {"netinfo", &History::ProcessNetInfo}, + {"rx", &History::ProcessRx}, {"rxtx", &History::ProcessRxTx}, {"tx", &History::ProcessTx}, }; static_assert(Utils::LookupTable::IsSorted(sCommands), "Command Table is not sorted"); diff --git a/src/core/api/history_tracker_api.cpp b/src/core/api/history_tracker_api.cpp index e7a65d3d7..32cce971a 100644 --- a/src/core/api/history_tracker_api.cpp +++ b/src/core/api/history_tracker_api.cpp @@ -78,6 +78,16 @@ const otHistoryTrackerMessageInfo *otHistoryTrackerIterateTxHistory(otInstance * *static_cast(aIterator), *aEntryAge); } +const otHistoryTrackerNeighborInfo *otHistoryTrackerIterateNeighborHistory(otInstance * aInstance, + otHistoryTrackerIterator *aIterator, + uint32_t * aEntryAge) +{ + Instance &instance = *static_cast(aInstance); + + return instance.Get().IterateNeighborHistory( + *static_cast(aIterator), *aEntryAge); +} + void otHistoryTrackerEntryAgeToString(uint32_t aEntryAge, char *aBuffer, uint16_t aSize) { Utils::HistoryTracker::EntryAgeToString(aEntryAge, aBuffer, aSize); diff --git a/src/core/config/history_tracker.h b/src/core/config/history_tracker.h index 963c912be..e3f210e08 100644 --- a/src/core/config/history_tracker.h +++ b/src/core/config/history_tracker.h @@ -91,4 +91,16 @@ #define OPENTHREAD_CONFIG_HISTORY_TRACKER_EXCLUDE_THREAD_CONTROL_MESSAGES 1 #endif +/** + * @def OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE + * + * Specifies the maximum number of entries in neighbor table history list. + * + * Can be set to zero to configure History Tracker module not to collect any neighbor table history. + * + */ +#ifndef OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE +#define OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE 64 +#endif + #endif // CONFIG_HISTORY_TRACKER_H_ diff --git a/src/core/thread/child_table.cpp b/src/core/thread/child_table.cpp index 7e3e9e513..9eca6955f 100644 --- a/src/core/thread/child_table.cpp +++ b/src/core/thread/child_table.cpp @@ -248,6 +248,7 @@ void ChildTable::Restore(void) child->SetLastHeard(TimerMilli::GetNow()); child->SetVersion(static_cast(childInfo.GetVersion())); Get().SetChildUseShortAddress(*child, true); + Get().Signal(NeighborTable::kChildAdded, *child); numChildren++; } diff --git a/src/core/thread/neighbor_table.cpp b/src/core/thread/neighbor_table.cpp index a5fac3216..f7856a11d 100644 --- a/src/core/thread/neighbor_table.cpp +++ b/src/core/thread/neighbor_table.cpp @@ -257,7 +257,9 @@ exit: void NeighborTable::Signal(Event aEvent, const Neighbor &aNeighbor) { +#if !OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE if (mCallback != nullptr) +#endif { EntryInfo info; @@ -279,7 +281,14 @@ void NeighborTable::Signal(Event aEvent, const Neighbor &aNeighbor) break; } - mCallback(static_cast(aEvent), &info); +#if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE + Get().RecordNeighborEvent(aEvent, info); + + if (mCallback != nullptr) +#endif + { + mCallback(static_cast(aEvent), &info); + } } #if OPENTHREAD_CONFIG_OTNS_ENABLE diff --git a/src/core/utils/history_tracker.cpp b/src/core/utils/history_tracker.cpp index 341422090..8375a2920 100644 --- a/src/core/utils/history_tracker.cpp +++ b/src/core/utils/history_tracker.cpp @@ -193,6 +193,67 @@ exit: return; } +void HistoryTracker::RecordNeighborEvent(NeighborTable::Event aEvent, const NeighborTable::EntryInfo &aInfo) +{ + NeighborInfo *entry = mNeighborHistory.AddNewEntry(); + + VerifyOrExit(entry != nullptr); + + switch (aEvent) + { + case NeighborTable::kChildAdded: + case NeighborTable::kChildRemoved: + case NeighborTable::kChildModeChanged: + entry->mExtAddress = aInfo.mInfo.mChild.mExtAddress; + entry->mRloc16 = aInfo.mInfo.mChild.mRloc16; + entry->mAverageRssi = aInfo.mInfo.mChild.mAverageRssi; + entry->mRxOnWhenIdle = aInfo.mInfo.mChild.mRxOnWhenIdle; + entry->mFullThreadDevice = aInfo.mInfo.mChild.mFullThreadDevice; + entry->mFullNetworkData = aInfo.mInfo.mChild.mFullNetworkData; + entry->mIsChild = true; + break; + + case NeighborTable::kRouterAdded: + case NeighborTable::kRouterRemoved: + entry->mExtAddress = aInfo.mInfo.mRouter.mExtAddress; + entry->mRloc16 = aInfo.mInfo.mRouter.mRloc16; + entry->mAverageRssi = aInfo.mInfo.mRouter.mAverageRssi; + entry->mRxOnWhenIdle = aInfo.mInfo.mRouter.mRxOnWhenIdle; + entry->mFullThreadDevice = aInfo.mInfo.mRouter.mFullThreadDevice; + entry->mFullNetworkData = aInfo.mInfo.mRouter.mFullNetworkData; + entry->mIsChild = false; + break; + } + + switch (aEvent) + { + case NeighborTable::kChildAdded: + if (aInfo.mInfo.mChild.mIsStateRestoring) + { + entry->mEvent = kNeighborRestoring; + break; + } + + OT_FALL_THROUGH; + + case NeighborTable::kRouterAdded: + entry->mEvent = kNeighborAdded; + break; + + case NeighborTable::kChildRemoved: + case NeighborTable::kRouterRemoved: + entry->mEvent = kNeighborRemoved; + break; + + case NeighborTable::kChildModeChanged: + entry->mEvent = kNeighborChanged; + break; + } + +exit: + return; +} + void HistoryTracker::HandleNotifierEvents(Events aEvents) { if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadRlocAdded | kEventThreadRlocRemoved | @@ -212,6 +273,7 @@ void HistoryTracker::HandleTimer(void) mNetInfoHistory.UpdateAgedEntries(); mRxHistory.UpdateAgedEntries(); mTxHistory.UpdateAgedEntries(); + mNeighborHistory.UpdateAgedEntries(); mTimer.Start(kAgeCheckPeriod); } diff --git a/src/core/utils/history_tracker.hpp b/src/core/utils/history_tracker.hpp index 96f3d761f..21713122c 100644 --- a/src/core/utils/history_tracker.hpp +++ b/src/core/utils/history_tracker.hpp @@ -50,6 +50,7 @@ #include "thread/mesh_forwarder.hpp" #include "thread/mle.hpp" #include "thread/mle_types.hpp" +#include "thread/neighbor_table.hpp" namespace ot { namespace Utils { @@ -63,6 +64,7 @@ class HistoryTracker : public InstanceLocator, private NonCopyable friend class ot::MeshForwarder; friend class ot::Notifier; friend class ot::Mle::Mle; + friend class ot::NeighborTable; public: /** @@ -117,6 +119,12 @@ public: */ typedef otHistoryTrackerMessageInfo MessageInfo; + /** + * This type represents a neighbor info. + * + */ + typedef otHistoryTrackerNeighborInfo NeighborInfo; + /** * This constructor initializes the `HistoryTracker`. * @@ -173,6 +181,11 @@ public: return mTxHistory.Iterate(aIterator, aEntryAge); } + const NeighborInfo *IterateNeighborHistory(Iterator &aIterator, uint32_t &aEntryAge) const + { + return mNeighborHistory.Iterate(aIterator, aEntryAge); + } + /** * This static method converts a given entry age to a human-readable string. * @@ -201,13 +214,21 @@ private: static constexpr uint32_t kAgeCheckPeriod = 16 * kOneHourInMsec; - static constexpr uint16_t kNetInfoListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_INFO_LIST_SIZE; - 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 kNetInfoListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_INFO_LIST_SIZE; + 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 int8_t kInvalidRss = OT_RADIO_RSSI_INVALID; static constexpr uint16_t kInvalidRloc16 = Mac::kShortAddrInvalid; + typedef otHistoryTrackerNeighborEvent NeighborEvent; + + static constexpr NeighborEvent kNeighborAdded = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_ADDED; + static constexpr NeighborEvent kNeighborRemoved = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_REMOVED; + static constexpr NeighborEvent kNeighborChanged = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED; + static constexpr NeighborEvent kNeighborRestoring = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING; + class Timestamp { public: @@ -301,14 +322,16 @@ private: void RecordNetworkInfo(void); void RecordMessage(const Message &aMessage, const Mac::Address &aMacAddress, MessageType aType); + void RecordNeighborEvent(NeighborTable::Event aEvent, const NeighborTable::EntryInfo &aInfo); void HandleNotifierEvents(Events aEvents); static void HandleTimer(Timer &aTimer); void HandleTimer(void); - EntryList mNetInfoHistory; - EntryList mRxHistory; - EntryList mTxHistory; - TimerMilli mTimer; + EntryList mNetInfoHistory; + EntryList mRxHistory; + EntryList mTxHistory; + EntryList mNeighborHistory; + TimerMilli mTimer; }; } // namespace Utils