• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020, 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 for Thread Link Metrics query and management.
32  */
33 
34 #ifndef LINK_METRICS_HPP_
35 #define LINK_METRICS_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
40 
41 #if (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2)
42 #error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE" \
43        "and OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE."
44 #endif
45 
46 #include <openthread/link.h>
47 
48 #include "common/as_core_type.hpp"
49 #include "common/clearable.hpp"
50 #include "common/locator.hpp"
51 #include "common/message.hpp"
52 #include "common/non_copyable.hpp"
53 #include "common/pool.hpp"
54 #include "net/ip6_address.hpp"
55 #include "thread/link_metrics_tlvs.hpp"
56 #include "thread/link_quality.hpp"
57 
58 namespace ot {
59 class Neighbor;
60 
61 namespace LinkMetrics {
62 
63 /**
64  * @addtogroup core-link-metrics
65  *
66  * @brief
67  *   This module includes definitions for Thread Link Metrics query and management.
68  *
69  * @{
70  */
71 
72 /**
73  * This type represents the results (values) for a set of metrics.
74  *
75  * @sa otLinkMetricsValues.
76  *
77  */
78 class MetricsValues : public otLinkMetricsValues, public Clearable<MetricsValues>
79 {
80 public:
81     /**
82      * This method gets the metrics flags.
83      *
84      * @returns The metrics flags.
85      *
86      */
GetMetrics(void)87     Metrics &GetMetrics(void) { return static_cast<Metrics &>(mMetrics); }
88 
89     /**
90      * This method gets the metrics flags.
91      *
92      * @returns The metrics flags.
93      *
94      */
GetMetrics(void) const95     const Metrics &GetMetrics(void) const { return static_cast<const Metrics &>(mMetrics); }
96 
97     /**
98      * This method set the metrics flags.
99      *
100      * @param[in] aMetrics  The metrics flags to set from.
101      *
102      */
SetMetrics(const Metrics & aMetrics)103     void SetMetrics(const Metrics &aMetrics) { mMetrics = aMetrics; }
104 };
105 
106 /**
107  * This class represents one Series that is being tracked by the Subject.
108  *
109  * When an Initiator successfully configured a Forward Tracking Series, the Subject would use an instance of this class
110  * to track the information of the Series. The Subject has a `Pool` of `SeriesInfo`. It would allocate one when a new
111  * Series comes, and free it when a Series finishes.
112  *
113  * This class inherits `LinkedListEntry` and each `Neighbor` has a list of `SeriesInfo` so that the Subject could track
114  * per Series initiated by neighbors as long as it has available resources.
115  *
116  */
117 class SeriesInfo : public LinkedListEntry<SeriesInfo>
118 {
119     friend class LinkedList<SeriesInfo>;
120     friend class LinkedListEntry<SeriesInfo>;
121 
122 public:
123     /**
124      * This constant represents Link Probe when filtering frames to be accounted using Series Flag. There's
125      * already `kFcfFrameData`, `kFcfFrameAck` and `kFcfFrameMacCmd`. This item is added so that we can
126      * filter a Link Probe for series in the same way as other frames.
127      *
128      */
129     static constexpr uint8_t kSeriesTypeLinkProbe = 0;
130 
131     /**
132      * This method initializes the SeriesInfo object.
133      *
134      * @param[in]  aSeriesId      The Series ID.
135      * @param[in]  aSeriesFlags   The Series Flags which specify what types of frames are to be accounted.
136      * @param[in]  aMetrics       Metrics to query.
137      *
138      */
139     void Init(uint8_t aSeriesId, const SeriesFlags &aSeriesFlags, const Metrics &aMetrics);
140 
141     /**
142      * This method gets the Series ID.
143      *
144      * @returns  The Series ID.
145      *
146      */
GetSeriesId(void) const147     uint8_t GetSeriesId(void) const { return mSeriesId; }
148 
149     /**
150      * This method gets the PDU count.
151      *
152      * @returns  The PDU count.
153      *
154      */
GetPduCount(void) const155     uint32_t GetPduCount(void) const { return mPduCount; }
156 
157     /**
158      * This method gets the average LQI.
159      *
160      * @returns  The average LQI.
161      *
162      */
GetAverageLqi(void) const163     uint8_t GetAverageLqi(void) const { return mLqiAverager.GetAverage(); }
164 
165     /**
166      * This method gets the average RSS.
167      *
168      * @returns  The average RSS.
169      *
170      */
GetAverageRss(void) const171     int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); }
172 
173     /**
174      * This method aggregates the Link Metrics data of a frame into this series.
175      *
176      * @param[in]  aFrameType    The type of the frame.
177      * @param[in]  aLqi          The LQI value.
178      * @param[in]  aRss          The RSS value.
179      *
180      */
181     void AggregateLinkMetrics(uint8_t aFrameType, uint8_t aLqi, int8_t aRss);
182 
183     /**
184      * This methods gets the metrics.
185      *
186      * @returns  The metrics associated with `SeriesInfo`.
187      *
188      */
GetLinkMetrics(void) const189     const Metrics &GetLinkMetrics(void) const { return mMetrics; }
190 
191 private:
Matches(const uint8_t & aSeriesId) const192     bool Matches(const uint8_t &aSeriesId) const { return mSeriesId == aSeriesId; }
193     bool IsFrameTypeMatch(uint8_t aFrameType) const;
194 
195     SeriesInfo *mNext;
196     uint8_t     mSeriesId;
197     SeriesFlags mSeriesFlags;
198     Metrics     mMetrics;
199     RssAverager mRssAverager;
200     LqiAverager mLqiAverager;
201     uint32_t    mPduCount;
202 };
203 
204 /**
205  * This enumeration type represent Link Metrics Status.
206  *
207  */
208 enum Status : uint8_t
209 {
210     kStatusSuccess                   = OT_LINK_METRICS_STATUS_SUCCESS,
211     kStatusCannotSupportNewSeries    = OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES,
212     kStatusSeriesIdAlreadyRegistered = OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED,
213     kStatusSeriesIdNotRecognized     = OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED,
214     kStatusNoMatchingFramesReceived  = OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED,
215     kStatusOtherError                = OT_LINK_METRICS_STATUS_OTHER_ERROR,
216 };
217 
218 /**
219  * This class implements Thread Link Metrics query and management.
220  *
221  */
222 class LinkMetrics : public InstanceLocator, private NonCopyable
223 {
224     friend class ot::Neighbor;
225 
226 public:
227     typedef otLinkMetricsReportCallback                ReportCallback;
228     typedef otLinkMetricsMgmtResponseCallback          MgmtResponseCallback;
229     typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback;
230 
231     /**
232      * This constructor initializes an instance of the LinkMetrics class.
233      *
234      * @param[in]  aInstance  A reference to the OpenThread interface.
235      *
236      */
237     explicit LinkMetrics(Instance &aInstance);
238 
239     /**
240      * This method sends an MLE Data Request containing Link Metrics Query TLV to query Link Metrics data.
241      *
242      * It could be either a Single Probe or a Forward Tracking Series.
243      *
244      * @param[in]  aDestination       A reference to the IPv6 address of the destination.
245      * @param[in]  aSeriesId          The Series ID to query, 0 for single probe.
246      * @param[in]  aMetrics           A pointer to metrics to query.
247      *
248      * @retval kErrorNone             Successfully sent a Link Metrics query message.
249      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Data Request message.
250      * @retval kErrorInvalidArgs      TypeIdFlags are not valid or exceed the count limit.
251      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
252      *
253      */
254     Error Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics);
255 
256     /**
257      * This method sends an MLE Link Metrics Management Request to configure/clear a Forward Tracking Series.
258      *
259      * @param[in] aDestination       A reference to the IPv6 address of the destination.
260      * @param[in] aSeriesId          The Series ID.
261      * @param[in] aSeriesFlags       The Series Flags info which specify what types of frames are to be accounted.
262      * @param[in] aMetrics           A pointer to flags specifying what metrics to query.
263      *
264      * @retval kErrorNone             Successfully sent a Link Metrics Management Request message.
265      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Metrics Management Request message.
266      * @retval kErrorInvalidArgs      @p aSeriesId is not within the valid range.
267      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
268      *
269      */
270     Error SendMgmtRequestForwardTrackingSeries(const Ip6::Address &     aDestination,
271                                                uint8_t                  aSeriesId,
272                                                const SeriesFlags::Info &aSeriesFlags,
273                                                const Metrics *          aMetrics);
274 
275 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
276     /**
277      * This method sends an MLE Link Metrics Management Request to configure/clear a Enhanced-ACK Based Probing.
278      *
279      * @param[in] aDestination       A reference to the IPv6 address of the destination.
280      * @param[in] aEnhAckFlags       Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear
281      *                               and `1` to register. Other values are reserved.
282      * @param[in] aMetrics           A pointer to flags specifying what metrics to query. Should be `nullptr` when
283      *                               `aEnhAckFlags` is `0`.
284      *
285      * @retval kErrorNone             Successfully sent a Link Metrics Management Request message.
286      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Metrics Management Request message.
287      * @retval kErrorInvalidArgs      @p aEnhAckFlags is not a valid value or @p aMetrics isn't correct.
288      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
289      *
290      */
291     Error SendMgmtRequestEnhAckProbing(const Ip6::Address &aDestination,
292                                        EnhAckFlags         aEnhAckFlags,
293                                        const Metrics *     aMetrics);
294 
295     /**
296      * This method sends an MLE Link Probe message.
297      *
298      * @param[in] aDestination    A reference to the IPv6 address of the destination.
299      * @param[in] aSeriesId       The Series ID which the Probe message targets at.
300      * @param[in] aLength         The length of the data payload in Link Probe TLV, [0, 64].
301      *
302      * @retval kErrorNone             Successfully sent a Link Probe message.
303      * @retval kErrorNoBufs           Insufficient buffers to generate the MLE Link Probe message.
304      * @retval kErrorInvalidArgs      @p aSeriesId or @p aLength is not within the valid range.
305      * @retval kErrorUnknownNeighbor  @p aDestination is not link-local or the neighbor is not found.
306      *
307      */
308     Error SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength);
309 #endif
310 
311 #if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
312     /**
313      * This method appends a Link Metrics Report to a message according to the Link Metrics query.
314      *
315      * @param[out]  aMessage           A reference to the message to append report.
316      * @param[in]   aRequestMessage    A reference to the message of the Data Request.
317      * @param[in]   aNeighbor          A reference to the neighbor who queries the report.
318      *
319      * @retval kErrorNone         Successfully appended the Thread Discovery TLV.
320      * @retval kErrorParse        Cannot parse query sub TLV successfully.
321      * @retval kErrorInvalidArgs  QueryId is invalid or any Type ID is invalid.
322      *
323      */
324     Error AppendReport(Message &aMessage, const Message &aRequestMessage, Neighbor &aNeighbor);
325 #endif
326     /**
327      * This method handles the received Link Metrics Management Request contained in @p aMessage and return a status.
328      *
329      * @param[in]   aMessage     A reference to the message that contains the Link Metrics Management Request.
330      * @param[in]   aNeighbor    A reference to the neighbor who sends the request.
331      * @param[out]  aStatus      A reference to the status which indicates the handling result.
332      *
333      * @retval kErrorNone     Successfully handled the Link Metrics Management Request.
334      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
335      *
336      */
337     Error HandleManagementRequest(const Message &aMessage, Neighbor &aNeighbor, Status &aStatus);
338 
339     /**
340      * This method handles the received Link Metrics Management Response contained in @p aMessage.
341      *
342      * @param[in]  aMessage    A reference to the message that contains the Link Metrics Management Response.
343      * @param[in]  aAddress    A reference to the source address of the message.
344      *
345      * @retval kErrorNone     Successfully handled the Link Metrics Management Response.
346      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
347      *
348      */
349     Error HandleManagementResponse(const Message &aMessage, const Ip6::Address &aAddress);
350 
351     /**
352      * This method handles the received Link Metrics report contained in @p aMessage.
353      *
354      * @param[in]  aMessage      A reference to the message.
355      * @param[in]  aOffset       The offset in bytes where the metrics report sub-TLVs start.
356      * @param[in]  aLength       The length of the metrics report sub-TLVs in bytes.
357      * @param[in]  aAddress      A reference to the source address of the message.
358      *
359      */
360     void HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t aLength, const Ip6::Address &aAddress);
361 
362     /**
363      * This method handles the Link Probe contained in @p aMessage.
364      *
365      * @param[in]   aMessage     A reference to the message that contains the Link Probe Message.
366      * @param[out]  aSeriesId    A reference to Series ID that parsed from the message.
367      *
368      * @retval kErrorNone     Successfully handled the Link Metrics Management Response.
369      * @retval kErrorParse    Cannot parse sub-TLVs from @p aMessage successfully.
370      *
371      */
372     Error HandleLinkProbe(const Message &aMessage, uint8_t &aSeriesId);
373 
374     /**
375      * This method registers a callback to handle Link Metrics report received.
376      *
377      * @param[in]  aCallback  A pointer to a function that is called when a Link Metrics report is received.
378      * @param[in]  aContext   A pointer to application-specific context.
379      *
380      */
381     void SetReportCallback(ReportCallback aCallback, void *aContext);
382 
383     /**
384      * This method registers a callback to handle Link Metrics Management Response received.
385      *
386      * @param[in]  aCallback A pointer to a function that is called when a Link Metrics Management Response is received.
387      * @param[in]  aContext  A pointer to application-specific context.
388      *
389      */
390     void SetMgmtResponseCallback(MgmtResponseCallback aCallback, void *aContext);
391 
392     /**
393      * This method registers a callback to handle Link Metrics when Enh-ACK Probing IE is received.
394      *
395      * @param[in]  aCallback A pointer to a function that is called when Enh-ACK Probing IE is received is received.
396      * @param[in]  aContext  A pointer to application-specific context.
397      *
398      */
399     void SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback, void *aContext);
400 
401     /**
402      * This method processes received Enh-ACK Probing IE data.
403      *
404      * @param[in] aData      A pointer to buffer containing the Enh-ACK Probing IE data.
405      * @param[in] aLength    The length of @p aData.
406      * @param[in] aNeighbor  The neighbor from which the Enh-ACK Probing IE was received.
407      *
408      */
409     void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLength, const Neighbor &aNeighbor);
410 
411 private:
412     static constexpr uint8_t kMaxTypeIdFlags = 4;
413 
414     // Max number of SeriesInfo that could be allocated by the pool.
415     static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED;
416 
417     static constexpr uint8_t kQueryIdSingleProbe = 0;   // This query ID represents Single Probe.
418     static constexpr uint8_t kSeriesIdAllSeries  = 255; // This series ID represents all series.
419     static constexpr uint8_t kLinkProbeMaxLen    = 64;  // Max length of data payload in Link Probe TLV.
420 
421     Error SendLinkMetricsQuery(const Ip6::Address &aDestination,
422                                uint8_t             aSeriesId,
423                                const TypeIdFlags * aTypeIdFlags,
424                                uint8_t             aTypeIdFlagsCount);
425 
426     Status ConfigureForwardTrackingSeries(uint8_t            aSeriesId,
427                                           const SeriesFlags &aSeriesFlags,
428                                           const Metrics &    aMetrics,
429                                           Neighbor &         aNeighbor);
430 
431     Status ConfigureEnhAckProbing(EnhAckFlags aEnhAckFlags, const Metrics &aMetrics, Neighbor &aNeighbor);
432 
433     Neighbor *GetNeighborFromLinkLocalAddr(const Ip6::Address &aDestination);
434 
435     static Error ReadTypeIdFlagsFromMessage(const Message &aMessage,
436                                             uint8_t        aStartPos,
437                                             uint8_t        aEndPos,
438                                             Metrics &      aMetrics);
439     static Error AppendReportSubTlvToMessage(Message &aMessage, uint8_t &aLength, const MetricsValues &aValues);
440     static Error AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, Status aStatus);
441 
442     ReportCallback                mReportCallback;
443     void *                        mReportCallbackContext;
444     MgmtResponseCallback          mMgmtResponseCallback;
445     void *                        mMgmtResponseCallbackContext;
446     EnhAckProbingIeReportCallback mEnhAckProbingIeReportCallback;
447     void *                        mEnhAckProbingIeReportCallbackContext;
448 
449     Pool<SeriesInfo, kMaxSeriesSupported> mSeriesInfoPool;
450 };
451 
452 /**
453  * @}
454  */
455 
456 } // namespace LinkMetrics
457 
458 DefineCoreType(otLinkMetrics, LinkMetrics::Metrics);
459 DefineCoreType(otLinkMetricsValues, LinkMetrics::MetricsValues);
460 DefineMapEnum(otLinkMetricsEnhAckFlags, LinkMetrics::EnhAckFlags);
461 
462 } // namespace ot
463 
464 #endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
465 
466 #endif // LINK_METRICS_HPP
467