blob: 318aea0e6a3f7587a8b1f1e4feabc597cdf8bbd3 [file] [log] [blame]
/*
* Copyright (c) 2020, 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 Thread Link Metrics query and management.
*/
#ifndef LINK_METRICS_HPP_
#define LINK_METRICS_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
#if (OPENTHREAD_CONFIG_THREAD_VERSION < OT_THREAD_VERSION_1_2)
#error "Thread 1.2 or higher version is required for OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE" \
"and OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE."
#endif
#include <openthread/link.h>
#include "common/as_core_type.hpp"
#include "common/clearable.hpp"
#include "common/locator.hpp"
#include "common/message.hpp"
#include "common/non_copyable.hpp"
#include "common/pool.hpp"
#include "net/ip6_address.hpp"
#include "thread/link_metrics_tlvs.hpp"
#include "thread/link_quality.hpp"
namespace ot {
class Neighbor;
namespace LinkMetrics {
/**
* @addtogroup core-link-metrics
*
* @brief
* This module includes definitions for Thread Link Metrics query and management.
*
* @{
*/
/**
* This type represents the results (values) for a set of metrics.
*
* @sa otLinkMetricsValues.
*
*/
class MetricsValues : public otLinkMetricsValues, public Clearable<MetricsValues>
{
public:
/**
* This method gets the metrics flags.
*
* @returns The metrics flags.
*
*/
Metrics &GetMetrics(void) { return static_cast<Metrics &>(mMetrics); }
/**
* This method gets the metrics flags.
*
* @returns The metrics flags.
*
*/
const Metrics &GetMetrics(void) const { return static_cast<const Metrics &>(mMetrics); }
/**
* This method set the metrics flags.
*
* @param[in] aMetrics The metrics flags to set from.
*
*/
void SetMetrics(const Metrics &aMetrics) { mMetrics = aMetrics; }
};
/**
* This class represents one Series that is being tracked by the Subject.
*
* When an Initiator successfully configured a Forward Tracking Series, the Subject would use an instance of this class
* to track the information of the Series. The Subject has a `Pool` of `SeriesInfo`. It would allocate one when a new
* Series comes, and free it when a Series finishes.
*
* This class inherits `LinkedListEntry` and each `Neighbor` has a list of `SeriesInfo` so that the Subject could track
* per Series initiated by neighbors as long as it has available resources.
*
*/
class SeriesInfo : public LinkedListEntry<SeriesInfo>
{
friend class LinkedList<SeriesInfo>;
friend class LinkedListEntry<SeriesInfo>;
public:
/**
* This constant represents Link Probe when filtering frames to be accounted using Series Flag. There's
* already `kFcfFrameData`, `kFcfFrameAck` and `kFcfFrameMacCmd`. This item is added so that we can
* filter a Link Probe for series in the same way as other frames.
*
*/
static constexpr uint8_t kSeriesTypeLinkProbe = 0;
/**
* This method initializes the SeriesInfo object.
*
* @param[in] aSeriesId The Series ID.
* @param[in] aSeriesFlags The Series Flags which specify what types of frames are to be accounted.
* @param[in] aMetrics Metrics to query.
*
*/
void Init(uint8_t aSeriesId, const SeriesFlags &aSeriesFlags, const Metrics &aMetrics);
/**
* This method gets the Series ID.
*
* @returns The Series ID.
*
*/
uint8_t GetSeriesId(void) const { return mSeriesId; }
/**
* This method gets the PDU count.
*
* @returns The PDU count.
*
*/
uint32_t GetPduCount(void) const { return mPduCount; }
/**
* This method gets the average LQI.
*
* @returns The average LQI.
*
*/
uint8_t GetAverageLqi(void) const { return mLqiAverager.GetAverage(); }
/**
* This method gets the average RSS.
*
* @returns The average RSS.
*
*/
int8_t GetAverageRss(void) const { return mRssAverager.GetAverage(); }
/**
* This method aggregates the Link Metrics data of a frame into this series.
*
* @param[in] aFrameType The type of the frame.
* @param[in] aLqi The LQI value.
* @param[in] aRss The RSS value.
*
*/
void AggregateLinkMetrics(uint8_t aFrameType, uint8_t aLqi, int8_t aRss);
/**
* This methods gets the metrics.
*
* @returns The metrics associated with `SeriesInfo`.
*
*/
const Metrics &GetLinkMetrics(void) const { return mMetrics; }
private:
bool Matches(const uint8_t &aSeriesId) const { return mSeriesId == aSeriesId; }
bool IsFrameTypeMatch(uint8_t aFrameType) const;
SeriesInfo *mNext;
uint8_t mSeriesId;
SeriesFlags mSeriesFlags;
Metrics mMetrics;
RssAverager mRssAverager;
LqiAverager mLqiAverager;
uint32_t mPduCount;
};
/**
* This enumeration type represent Link Metrics Status.
*
*/
enum Status : uint8_t
{
kStatusSuccess = OT_LINK_METRICS_STATUS_SUCCESS,
kStatusCannotSupportNewSeries = OT_LINK_METRICS_STATUS_CANNOT_SUPPORT_NEW_SERIES,
kStatusSeriesIdAlreadyRegistered = OT_LINK_METRICS_STATUS_SERIESID_ALREADY_REGISTERED,
kStatusSeriesIdNotRecognized = OT_LINK_METRICS_STATUS_SERIESID_NOT_RECOGNIZED,
kStatusNoMatchingFramesReceived = OT_LINK_METRICS_STATUS_NO_MATCHING_FRAMES_RECEIVED,
kStatusOtherError = OT_LINK_METRICS_STATUS_OTHER_ERROR,
};
/**
* This class implements Thread Link Metrics query and management.
*
*/
class LinkMetrics : public InstanceLocator, private NonCopyable
{
friend class ot::Neighbor;
public:
typedef otLinkMetricsReportCallback ReportCallback;
typedef otLinkMetricsMgmtResponseCallback MgmtResponseCallback;
typedef otLinkMetricsEnhAckProbingIeReportCallback EnhAckProbingIeReportCallback;
/**
* This constructor initializes an instance of the LinkMetrics class.
*
* @param[in] aInstance A reference to the OpenThread interface.
*
*/
explicit LinkMetrics(Instance &aInstance);
/**
* This method sends an MLE Data Request containing Link Metrics Query TLV to query Link Metrics data.
*
* It could be either a Single Probe or a Forward Tracking Series.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aSeriesId The Series ID to query, 0 for single probe.
* @param[in] aMetrics A pointer to metrics to query.
*
* @retval kErrorNone Successfully sent a Link Metrics query message.
* @retval kErrorNoBufs Insufficient buffers to generate the MLE Data Request message.
* @retval kErrorInvalidArgs TypeIdFlags are not valid or exceed the count limit.
* @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found.
*
*/
Error Query(const Ip6::Address &aDestination, uint8_t aSeriesId, const Metrics *aMetrics);
/**
* This method sends an MLE Link Metrics Management Request to configure/clear a Forward Tracking Series.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aSeriesId The Series ID.
* @param[in] aSeriesFlags The Series Flags info which specify what types of frames are to be accounted.
* @param[in] aMetrics A pointer to flags specifying what metrics to query.
*
* @retval kErrorNone Successfully sent a Link Metrics Management Request message.
* @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Metrics Management Request message.
* @retval kErrorInvalidArgs @p aSeriesId is not within the valid range.
* @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found.
*
*/
Error SendMgmtRequestForwardTrackingSeries(const Ip6::Address & aDestination,
uint8_t aSeriesId,
const SeriesFlags::Info &aSeriesFlags,
const Metrics * aMetrics);
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE
/**
* This method sends an MLE Link Metrics Management Request to configure/clear a Enhanced-ACK Based Probing.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aEnhAckFlags Enh-ACK Flags to indicate whether to register or clear the probing. `0` to clear
* and `1` to register. Other values are reserved.
* @param[in] aMetrics A pointer to flags specifying what metrics to query. Should be `nullptr` when
* `aEnhAckFlags` is `0`.
*
* @retval kErrorNone Successfully sent a Link Metrics Management Request message.
* @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Metrics Management Request message.
* @retval kErrorInvalidArgs @p aEnhAckFlags is not a valid value or @p aMetrics isn't correct.
* @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found.
*
*/
Error SendMgmtRequestEnhAckProbing(const Ip6::Address &aDestination,
EnhAckFlags aEnhAckFlags,
const Metrics * aMetrics);
/**
* This method sends an MLE Link Probe message.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aSeriesId The Series ID which the Probe message targets at.
* @param[in] aLength The length of the data payload in Link Probe TLV, [0, 64].
*
* @retval kErrorNone Successfully sent a Link Probe message.
* @retval kErrorNoBufs Insufficient buffers to generate the MLE Link Probe message.
* @retval kErrorInvalidArgs @p aSeriesId or @p aLength is not within the valid range.
* @retval kErrorUnknownNeighbor @p aDestination is not link-local or the neighbor is not found.
*
*/
Error SendLinkProbe(const Ip6::Address &aDestination, uint8_t aSeriesId, uint8_t aLength);
#endif
#if OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
/**
* This method appends a Link Metrics Report to a message according to the Link Metrics query.
*
* @param[out] aMessage A reference to the message to append report.
* @param[in] aRequestMessage A reference to the message of the Data Request.
* @param[in] aNeighbor A reference to the neighbor who queries the report.
*
* @retval kErrorNone Successfully appended the Thread Discovery TLV.
* @retval kErrorParse Cannot parse query sub TLV successfully.
* @retval kErrorInvalidArgs QueryId is invalid or any Type ID is invalid.
*
*/
Error AppendReport(Message &aMessage, const Message &aRequestMessage, Neighbor &aNeighbor);
#endif
/**
* This method handles the received Link Metrics Management Request contained in @p aMessage and return a status.
*
* @param[in] aMessage A reference to the message that contains the Link Metrics Management Request.
* @param[in] aNeighbor A reference to the neighbor who sends the request.
* @param[out] aStatus A reference to the status which indicates the handling result.
*
* @retval kErrorNone Successfully handled the Link Metrics Management Request.
* @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully.
*
*/
Error HandleManagementRequest(const Message &aMessage, Neighbor &aNeighbor, Status &aStatus);
/**
* This method handles the received Link Metrics Management Response contained in @p aMessage.
*
* @param[in] aMessage A reference to the message that contains the Link Metrics Management Response.
* @param[in] aAddress A reference to the source address of the message.
*
* @retval kErrorNone Successfully handled the Link Metrics Management Response.
* @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully.
*
*/
Error HandleManagementResponse(const Message &aMessage, const Ip6::Address &aAddress);
/**
* This method handles the received Link Metrics report contained in @p aMessage.
*
* @param[in] aMessage A reference to the message.
* @param[in] aOffset The offset in bytes where the metrics report sub-TLVs start.
* @param[in] aLength The length of the metrics report sub-TLVs in bytes.
* @param[in] aAddress A reference to the source address of the message.
*
*/
void HandleReport(const Message &aMessage, uint16_t aOffset, uint16_t aLength, const Ip6::Address &aAddress);
/**
* This method handles the Link Probe contained in @p aMessage.
*
* @param[in] aMessage A reference to the message that contains the Link Probe Message.
* @param[out] aSeriesId A reference to Series ID that parsed from the message.
*
* @retval kErrorNone Successfully handled the Link Metrics Management Response.
* @retval kErrorParse Cannot parse sub-TLVs from @p aMessage successfully.
*
*/
Error HandleLinkProbe(const Message &aMessage, uint8_t &aSeriesId);
/**
* This method registers a callback to handle Link Metrics report received.
*
* @param[in] aCallback A pointer to a function that is called when a Link Metrics report is received.
* @param[in] aContext A pointer to application-specific context.
*
*/
void SetReportCallback(ReportCallback aCallback, void *aContext);
/**
* This method registers a callback to handle Link Metrics Management Response received.
*
* @param[in] aCallback A pointer to a function that is called when a Link Metrics Management Response is received.
* @param[in] aContext A pointer to application-specific context.
*
*/
void SetMgmtResponseCallback(MgmtResponseCallback aCallback, void *aContext);
/**
* This method registers a callback to handle Link Metrics when Enh-ACK Probing IE is received.
*
* @param[in] aCallback A pointer to a function that is called when Enh-ACK Probing IE is received is received.
* @param[in] aContext A pointer to application-specific context.
*
*/
void SetEnhAckProbingCallback(EnhAckProbingIeReportCallback aCallback, void *aContext);
/**
* This method processes received Enh-ACK Probing IE data.
*
* @param[in] aData A pointer to buffer containing the Enh-ACK Probing IE data.
* @param[in] aLength The length of @p aData.
* @param[in] aNeighbor The neighbor from which the Enh-ACK Probing IE was received.
*
*/
void ProcessEnhAckIeData(const uint8_t *aData, uint8_t aLength, const Neighbor &aNeighbor);
private:
static constexpr uint8_t kMaxTypeIdFlags = 4;
// Max number of SeriesInfo that could be allocated by the pool.
static constexpr uint16_t kMaxSeriesSupported = OPENTHREAD_CONFIG_MLE_LINK_METRICS_MAX_SERIES_SUPPORTED;
static constexpr uint8_t kQueryIdSingleProbe = 0; // This query ID represents Single Probe.
static constexpr uint8_t kSeriesIdAllSeries = 255; // This series ID represents all series.
static constexpr uint8_t kLinkProbeMaxLen = 64; // Max length of data payload in Link Probe TLV.
Error SendLinkMetricsQuery(const Ip6::Address &aDestination,
uint8_t aSeriesId,
const TypeIdFlags * aTypeIdFlags,
uint8_t aTypeIdFlagsCount);
Status ConfigureForwardTrackingSeries(uint8_t aSeriesId,
const SeriesFlags &aSeriesFlags,
const Metrics & aMetrics,
Neighbor & aNeighbor);
Status ConfigureEnhAckProbing(EnhAckFlags aEnhAckFlags, const Metrics &aMetrics, Neighbor &aNeighbor);
Neighbor *GetNeighborFromLinkLocalAddr(const Ip6::Address &aDestination);
static Error ReadTypeIdFlagsFromMessage(const Message &aMessage,
uint8_t aStartPos,
uint8_t aEndPos,
Metrics & aMetrics);
static Error AppendReportSubTlvToMessage(Message &aMessage, uint8_t &aLength, const MetricsValues &aValues);
static Error AppendStatusSubTlvToMessage(Message &aMessage, uint8_t &aLength, Status aStatus);
ReportCallback mReportCallback;
void * mReportCallbackContext;
MgmtResponseCallback mMgmtResponseCallback;
void * mMgmtResponseCallbackContext;
EnhAckProbingIeReportCallback mEnhAckProbingIeReportCallback;
void * mEnhAckProbingIeReportCallbackContext;
Pool<SeriesInfo, kMaxSeriesSupported> mSeriesInfoPool;
};
/**
* @}
*/
} // namespace LinkMetrics
DefineCoreType(otLinkMetrics, LinkMetrics::Metrics);
DefineCoreType(otLinkMetricsValues, LinkMetrics::MetricsValues);
DefineMapEnum(otLinkMetricsEnhAckFlags, LinkMetrics::EnhAckFlags);
} // namespace ot
#endif // OPENTHREAD_CONFIG_MLE_LINK_METRICS_INITIATOR_ENABLE || OPENTHREAD_CONFIG_MLE_LINK_METRICS_SUBJECT_ENABLE
#endif // LINK_METRICS_HPP