• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2021, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  *   This file includes definitions to support History Tracker module.
32  */
33 
34 #ifndef HISTORY_TRACKER_HPP_
35 #define HISTORY_TRACKER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
40 
41 #include <openthread/history_tracker.h>
42 #include <openthread/platform/radio.h>
43 
44 #include "common/as_core_type.hpp"
45 #include "common/clearable.hpp"
46 #include "common/locator.hpp"
47 #include "common/non_copyable.hpp"
48 #include "common/notifier.hpp"
49 #include "common/timer.hpp"
50 #include "net/netif.hpp"
51 #include "net/socket.hpp"
52 #include "thread/mesh_forwarder.hpp"
53 #include "thread/mle.hpp"
54 #include "thread/mle_types.hpp"
55 #include "thread/neighbor_table.hpp"
56 #include "thread/network_data.hpp"
57 
58 namespace ot {
59 namespace Utils {
60 
61 #ifdef OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
62 #error "OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA should not be defined directly." \
63        "It is derived from other configs: on-mesh prefix and external route history list sizes"
64 #endif
65 
66 #define OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA                       \
67     ((OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE > 0) || \
68      (OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE > 0))
69 
70 /**
71  * This class implements History Tracker.
72  *
73  */
74 class HistoryTracker : public InstanceLocator, private NonCopyable
75 {
76     friend class ot::MeshForwarder;
77     friend class ot::Notifier;
78     friend class ot::Mle::Mle;
79     friend class ot::NeighborTable;
80     friend class ot::Ip6::Netif;
81 
82 public:
83     /**
84      * This constant specifies the maximum age of entries which is 49 days (value in msec).
85      *
86      * Entries older than the max age will give this value as their age.
87      *
88      */
89     static constexpr uint32_t kMaxAge = OT_HISTORY_TRACKER_MAX_AGE;
90 
91     /**
92      * This constant specifies the recommend string size to represent an entry age
93      *
94      */
95     static constexpr uint16_t kEntryAgeStringSize = OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE;
96 
97     /**
98      * This type represents an iterator to iterate through a history list.
99      *
100      */
101     class Iterator : public otHistoryTrackerIterator
102     {
103         friend class HistoryTracker;
104 
105     public:
106         /**
107          * This method initializes an `Iterator`
108          *
109          * An iterator MUST be initialized before it is used. An iterator can be initialized again to start from
110          * the beginning of the list.
111          *
112          */
Init(void)113         void Init(void) { ResetEntryNumber(), SetInitTime(); }
114 
115     private:
GetEntryNumber(void) const116         uint16_t  GetEntryNumber(void) const { return mData16; }
ResetEntryNumber(void)117         void      ResetEntryNumber(void) { mData16 = 0; }
IncrementEntryNumber(void)118         void      IncrementEntryNumber(void) { mData16++; }
GetInitTime(void) const119         TimeMilli GetInitTime(void) const { return TimeMilli(mData32); }
SetInitTime(void)120         void      SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); }
121     };
122 
123     typedef otHistoryTrackerNetworkInfo          NetworkInfo;          ///< Thread network info.
124     typedef otHistoryTrackerUnicastAddressInfo   UnicastAddressInfo;   ///< Unicast IPv6 address info.
125     typedef otHistoryTrackerMulticastAddressInfo MulticastAddressInfo; ///< Multicast IPv6 address info.
126     typedef otHistoryTrackerMessageInfo          MessageInfo;          ///< RX/TX IPv6 message info.
127     typedef otHistoryTrackerNeighborInfo         NeighborInfo;         ///< Neighbor info.
128     typedef otHistoryTrackerOnMeshPrefixInfo     OnMeshPrefixInfo;     ///< Network Data on mesh prefix info.
129     typedef otHistoryTrackerExternalRouteInfo    ExternalRouteInfo;    ///< Network Data external route info
130 
131     /**
132      * This constructor initializes the `HistoryTracker`.
133      *
134      * @param[in]  aInstance     A reference to the OpenThread instance.
135      *
136      */
137     explicit HistoryTracker(Instance &aInstance);
138 
139     /**
140      * This method iterates over the entries in the network info history list.
141      *
142      * @param[in,out] aIterator  An iterator. MUST be initialized.
143      * @param[out]    aEntryAge  A reference to a variable to output the entry's age.
144      *                           Age is provided as the duration (in milliseconds) from when entry was recorded to
145      *                           @p aIterator initialization time. It is set to `kMaxAge` for entries older than max
146      *                           age.
147      *
148      * @returns A pointer to `NetworkInfo` entry or `nullptr` if no more entries in the list.
149      *
150      */
IterateNetInfoHistory(Iterator & aIterator,uint32_t & aEntryAge) const151     const NetworkInfo *IterateNetInfoHistory(Iterator &aIterator, uint32_t &aEntryAge) const
152     {
153         return mNetInfoHistory.Iterate(aIterator, aEntryAge);
154     }
155 
156     /**
157      * This method iterates over the entries in the unicast address history list.
158      *
159      * @param[in,out] aIterator  An iterator. MUST be initialized.
160      * @param[out]    aEntryAge  A reference to a variable to output the entry's age.
161      *                           Age is provided as the duration (in milliseconds) from when entry was recorded to
162      *                           @p aIterator initialization time. It is set to `kMaxAge` for entries older than max
163      *                           age.
164      *
165      * @returns A pointer to `UnicastAddress` entry or `nullptr` if no more entries in the list.
166      *
167      */
IterateUnicastAddressHistory(Iterator & aIterator,uint32_t & aEntryAge) const168     const UnicastAddressInfo *IterateUnicastAddressHistory(Iterator &aIterator, uint32_t &aEntryAge) const
169     {
170         return mUnicastAddressHistory.Iterate(aIterator, aEntryAge);
171     }
172 
173     /**
174      * This method iterates over the entries in the multicast address history list.
175      *
176      * @param[in,out] aIterator  An iterator. MUST be initialized.
177      * @param[out]    aEntryAge  A reference to a variable to output the entry's age.
178      *                           Age is provided as the duration (in milliseconds) from when entry was recorded to
179      *                           @p aIterator initialization time. It is set to `kMaxAge` for entries older than max
180      *                           age.
181      *
182      * @returns A pointer to `MulticastAddress` entry or `nullptr` if no more entries in the list.
183      *
184      */
IterateMulticastAddressHistory(Iterator & aIterator,uint32_t & aEntryAge) const185     const MulticastAddressInfo *IterateMulticastAddressHistory(Iterator &aIterator, uint32_t &aEntryAge) const
186     {
187         return mMulticastAddressHistory.Iterate(aIterator, aEntryAge);
188     }
189 
190     /**
191      * This method iterates over the entries in the RX history list.
192      *
193      * @param[in,out] aIterator  An iterator. MUST be initialized.
194      * @param[out]    aEntryAge  A reference to a variable to output the entry's age.
195      *                           Age is provided as the duration (in milliseconds) from when entry was recorded to
196      *                           @p aIterator initialization time. It is set to `kMaxAge` for entries older than max
197      *                           age.
198      *
199      * @returns A pointer to `MessageInfo` entry or `nullptr` if no more entries in the list.
200      *
201      */
IterateRxHistory(Iterator & aIterator,uint32_t & aEntryAge) const202     const MessageInfo *IterateRxHistory(Iterator &aIterator, uint32_t &aEntryAge) const
203     {
204         return mRxHistory.Iterate(aIterator, aEntryAge);
205     }
206 
207     /**
208      * This method iterates over the entries in the TX history list.
209      *
210      * @param[in,out] aIterator  An iterator. MUST be initialized.
211      * @param[out]    aEntryAge  A reference to a variable to output the entry's age.
212      *                           Age is provided as the duration (in milliseconds) from when entry was recorded to
213      *                           @p aIterator initialization time. It is set to `kMaxAge` for entries older than max
214      *                           age.
215      *
216      * @returns A pointer to `MessageInfo` entry or `nullptr` if no more entries in the list.
217      *
218      */
IterateTxHistory(Iterator & aIterator,uint32_t & aEntryAge) const219     const MessageInfo *IterateTxHistory(Iterator &aIterator, uint32_t &aEntryAge) const
220     {
221         return mTxHistory.Iterate(aIterator, aEntryAge);
222     }
223 
IterateNeighborHistory(Iterator & aIterator,uint32_t & aEntryAge) const224     const NeighborInfo *IterateNeighborHistory(Iterator &aIterator, uint32_t &aEntryAge) const
225     {
226         return mNeighborHistory.Iterate(aIterator, aEntryAge);
227     }
228 
IterateOnMeshPrefixHistory(Iterator & aIterator,uint32_t & aEntryAge) const229     const OnMeshPrefixInfo *IterateOnMeshPrefixHistory(Iterator &aIterator, uint32_t &aEntryAge) const
230     {
231         return mOnMeshPrefixHistory.Iterate(aIterator, aEntryAge);
232     }
233 
IterateExternalRouteHistory(Iterator & aIterator,uint32_t & aEntryAge) const234     const ExternalRouteInfo *IterateExternalRouteHistory(Iterator &aIterator, uint32_t &aEntryAge) const
235     {
236         return mExternalRouteHistory.Iterate(aIterator, aEntryAge);
237     }
238 
239     /**
240      * This static method converts a given entry age to a human-readable string.
241      *
242      * The entry age string follows the format "<hh>:<mm>:<ss>.<mmmm>" for hours, minutes, seconds and millisecond
243      * (if shorter than one day) or "<dd> days <hh>:<mm>:<ss>.<mmmm>" (if longer than one day).
244      *
245      * If the resulting string does not fit in @p aBuffer (within its @p aSize characters), the string will be
246      * truncated but the outputted string is always null-terminated.
247      *
248      * @param[in]  aEntryAge The entry age (duration in msec).
249      * @param[out] aBuffer   A pointer to a char array to output the string (MUST NOT be NULL).
250      * @param[in]  aSize     The size of @p aBuffer (in bytes). Recommended to use `OT_IP6_ADDRESS_STRING_SIZE`.
251      *
252      */
253     static void EntryAgeToString(uint32_t aEntryAge, char *aBuffer, uint16_t aSize);
254 
255 private:
256     // `Timestamp` uses `uint32_t` value. `2^32` msec is 49 days, 17
257     // hours, 2 minutes and 47 seconds and 296 msec. We use 49 days
258     // as `kMaxAge` and check for aged entries every 16 hours.
259 
260     static constexpr uint32_t kAgeCheckPeriod = 16 * Time::kOneHourInMsec;
261 
262     static constexpr uint16_t kNetInfoListSize       = OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_INFO_LIST_SIZE;
263     static constexpr uint16_t kUnicastAddrListSize   = OPENTHREAD_CONFIG_HISTORY_TRACKER_UNICAST_ADDRESS_LIST_SIZE;
264     static constexpr uint16_t kMulticastAddrListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_MULTICAST_ADDRESS_LIST_SIZE;
265     static constexpr uint16_t kRxListSize            = OPENTHREAD_CONFIG_HISTORY_TRACKER_RX_LIST_SIZE;
266     static constexpr uint16_t kTxListSize            = OPENTHREAD_CONFIG_HISTORY_TRACKER_TX_LIST_SIZE;
267     static constexpr uint16_t kNeighborListSize      = OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE;
268     static constexpr uint16_t kOnMeshPrefixListSize  = OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE;
269     static constexpr uint16_t kExternalRouteListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE;
270 
271     typedef otHistoryTrackerAddressEvent AddressEvent;
272 
273     static constexpr AddressEvent kAddressAdded   = OT_HISTORY_TRACKER_ADDRESS_EVENT_ADDED;
274     static constexpr AddressEvent kAddressRemoved = OT_HISTORY_TRACKER_ADDRESS_EVENT_REMOVED;
275 
276     static constexpr int8_t   kInvalidRss    = OT_RADIO_RSSI_INVALID;
277     static constexpr uint16_t kInvalidRloc16 = Mac::kShortAddrInvalid;
278 
279     typedef otHistoryTrackerNeighborEvent NeighborEvent;
280 
281     static constexpr NeighborEvent kNeighborAdded     = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_ADDED;
282     static constexpr NeighborEvent kNeighborRemoved   = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_REMOVED;
283     static constexpr NeighborEvent kNeighborChanged   = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED;
284     static constexpr NeighborEvent kNeighborRestoring = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING;
285 
286     typedef otHistoryTrackerNetDataEvent NetDataEvent;
287 
288     static constexpr NetDataEvent kNetDataEntryAdded   = OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED;
289     static constexpr NetDataEvent kNetDataEntryRemoved = OT_HISTORY_TRACKER_NET_DATA_ENTRY_REMOVED;
290 
291     class Timestamp
292     {
293     public:
294         void     SetToNow(void);
295         uint32_t GetDurationTill(TimeMilli aTime) const;
IsDistantPast(void) const296         bool     IsDistantPast(void) const { return (mTime.GetValue() == kDistantPast); }
MarkAsDistantPast(void)297         void     MarkAsDistantPast(void) { return mTime.SetValue(kDistantPast); }
298 
299     private:
300         static constexpr uint32_t kDistantPast = 0;
301 
302         TimeMilli mTime;
303     };
304 
305     // An ordered list of timestamped items (base class of `EntryList<Entry, kSize>`).
306     class List : private NonCopyable
307     {
308     public:
309         void     Clear(void);
GetSize(void) const310         uint16_t GetSize(void) const { return mSize; }
311 
312     protected:
313         List(void);
314         uint16_t Add(uint16_t aMaxSize, Timestamp aTimestamps[]);
315         void     UpdateAgedEntries(uint16_t aMaxSize, Timestamp aTimestamps[]);
316         uint16_t MapEntryNumberToListIndex(uint16_t aEntryNumber, uint16_t aMaxSize) const;
317         Error    Iterate(uint16_t        aMaxSize,
318                          const Timestamp aTimestamps[],
319                          Iterator &      aIterator,
320                          uint16_t &      aListIndex,
321                          uint32_t &      aEntryAge) const;
322 
323     private:
324         uint16_t mStartIndex;
325         uint16_t mSize;
326     };
327 
328     // A history list (with given max size) of timestamped `Entry` items.
329     template <typename Entry, uint16_t kMaxSize> class EntryList : public List
330     {
331     public:
332         // Adds a new entry to the list or overwrites the oldest entry
333         // if list is full. First version returns a pointer to the
334         // new `Entry` (for caller to populate). Second version copies
335         // the given `aEntry`.
AddNewEntry(void)336         Entry *AddNewEntry(void) { return &mEntries[Add(kMaxSize, mTimestamps)]; }
AddNewEntry(const Entry & aEntry)337         void   AddNewEntry(const Entry &aEntry) { mEntries[Add(kMaxSize, mTimestamps)] = aEntry; }
338 
UpdateAgedEntries(void)339         void UpdateAgedEntries(void) { List::UpdateAgedEntries(kMaxSize, mTimestamps); }
340 
Iterate(Iterator & aIterator,uint32_t & aEntryAge) const341         const Entry *Iterate(Iterator &aIterator, uint32_t &aEntryAge) const
342         {
343             uint16_t index;
344 
345             return (List::Iterate(kMaxSize, mTimestamps, aIterator, index, aEntryAge) == kErrorNone) ? &mEntries[index]
346                                                                                                      : nullptr;
347         }
348 
349     private:
350         Timestamp mTimestamps[kMaxSize];
351         Entry     mEntries[kMaxSize];
352     };
353 
354     // Partial specialization for `kMaxSize` zero.
355     template <typename Entry> class EntryList<Entry, 0> : private NonCopyable
356     {
357     public:
Clear(void)358         void         Clear(void) {}
GetSize(void) const359         uint16_t     GetSize(void) const { return 0; }
AddNewEntry(void)360         Entry *      AddNewEntry(void) { return nullptr; }
AddNewEntry(const Entry &)361         void         AddNewEntry(const Entry &) {}
Iterate(Iterator &,uint32_t &) const362         const Entry *Iterate(Iterator &, uint32_t &) const { return nullptr; }
RemoveAgedEntries(void)363         void         RemoveAgedEntries(void) {}
364     };
365 
366     enum MessageType : uint8_t
367     {
368         kRxMessage,
369         kTxMessage,
370     };
371 
RecordRxMessage(const Message & aMessage,const Mac::Address & aMacSource)372     void RecordRxMessage(const Message &aMessage, const Mac::Address &aMacSource)
373     {
374         RecordMessage(aMessage, aMacSource, kRxMessage);
375     }
376 
RecordTxMessage(const Message & aMessage,const Mac::Address & aMacDest)377     void RecordTxMessage(const Message &aMessage, const Mac::Address &aMacDest)
378     {
379         RecordMessage(aMessage, aMacDest, kTxMessage);
380     }
381 
382     void        RecordNetworkInfo(void);
383     void        RecordMessage(const Message &aMessage, const Mac::Address &aMacAddress, MessageType aType);
384     void        RecordNeighborEvent(NeighborTable::Event aEvent, const NeighborTable::EntryInfo &aInfo);
385     void        RecordAddressEvent(Ip6::Netif::AddressEvent aEvent, const Ip6::Netif::UnicastAddress &aUnicastAddress);
386     void        RecordAddressEvent(Ip6::Netif::AddressEvent            aEvent,
387                                    const Ip6::Netif::MulticastAddress &aMulticastAddress,
388                                    Ip6::Netif::AddressOrigin           aAddressOrigin);
389     void        HandleNotifierEvents(Events aEvents);
390     static void HandleTimer(Timer &aTimer);
391     void        HandleTimer(void);
392 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
393     void RecordNetworkDataChange(void);
394     void RecordOnMeshPrefixEvent(NetDataEvent aEvent, const NetworkData::OnMeshPrefixConfig &aPrefix);
395     void RecordExternalRouteEvent(NetDataEvent aEvent, const NetworkData::ExternalRouteConfig &aRoute);
396 #endif
397 
398     EntryList<NetworkInfo, kNetInfoListSize>                mNetInfoHistory;
399     EntryList<UnicastAddressInfo, kUnicastAddrListSize>     mUnicastAddressHistory;
400     EntryList<MulticastAddressInfo, kMulticastAddrListSize> mMulticastAddressHistory;
401     EntryList<MessageInfo, kRxListSize>                     mRxHistory;
402     EntryList<MessageInfo, kTxListSize>                     mTxHistory;
403     EntryList<NeighborInfo, kNeighborListSize>              mNeighborHistory;
404     EntryList<OnMeshPrefixInfo, kOnMeshPrefixListSize>      mOnMeshPrefixHistory;
405     EntryList<ExternalRouteInfo, kExternalRouteListSize>    mExternalRouteHistory;
406 
407     TimerMilli mTimer;
408 
409 #if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
410     NetworkData::MutableNetworkData mPreviousNetworkData;
411 
412     uint8_t mNetworkDataTlvBuffer[NetworkData::NetworkData::kMaxSize];
413 #endif
414 };
415 
416 } // namespace Utils
417 
418 DefineCoreType(otHistoryTrackerIterator, Utils::HistoryTracker::Iterator);
419 DefineCoreType(otHistoryTrackerNetworkInfo, Utils::HistoryTracker::NetworkInfo);
420 DefineCoreType(otHistoryTrackerMessageInfo, Utils::HistoryTracker::MessageInfo);
421 DefineCoreType(otHistoryTrackerNeighborInfo, Utils::HistoryTracker::NeighborInfo);
422 DefineCoreType(otHistoryTrackerOnMeshPrefixInfo, Utils::HistoryTracker::OnMeshPrefixInfo);
423 DefineCoreType(otHistoryTrackerExternalRouteInfo, Utils::HistoryTracker::ExternalRouteInfo);
424 
425 } // namespace ot
426 
427 #endif // OPENTHREAD_CONFIG_HISTORY_TRACKER_ENABLE
428 
429 #endif // HISTORY_TRACKER_HPP_
430