mirror of
https://github.com/espressif/openthread.git
synced 2026-06-05 21:14:49 +00:00
[history-tracker] support tracking netdata prefix and route entries (#7324)
This commit adds a mechanism in `HistoryTracker` to track changes in Thread Network Data maintaining a history of on-mesh prefix and external route entries as they are added or removed by different nodes in Network Data. This commit also adds new `cli history` commands to retrieve the Network Data prefix/route history list and updates the documentation in `cli/README_HISTORY.md`.
This commit is contained in:
committed by
GitHub
parent
556cee64d3
commit
314e945bb6
@@ -29,6 +29,7 @@
|
||||
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/ip6.h>
|
||||
#include <openthread/netdata.h>
|
||||
#include <openthread/thread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -191,6 +192,36 @@ typedef struct otHistoryTrackerNeighborInfo
|
||||
bool mIsChild : 1; ///< Indicates whether or not the neighbor is a child.
|
||||
} otHistoryTrackerNeighborInfo;
|
||||
|
||||
/**
|
||||
* This enumeration defines the events for a Network Data entry (i.e., whether an entry is added or removed).
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED = 0, ///< Network data entry is added.
|
||||
OT_HISTORY_TRACKER_NET_DATA_ENTRY_REMOVED = 1, ///< Network data entry is removed.
|
||||
} otHistoryTrackerNetDataEvent;
|
||||
|
||||
/**
|
||||
* This structure represent a Network Data on mesh prefix info.
|
||||
*
|
||||
*/
|
||||
typedef struct otHistoryTrackerOnMeshPrefixInfo
|
||||
{
|
||||
otBorderRouterConfig mPrefix; ///< The on mesh prefix entry.
|
||||
otHistoryTrackerNetDataEvent mEvent; ///< Indicates the event (added/removed).
|
||||
} otHistoryTrackerOnMeshPrefixInfo;
|
||||
|
||||
/**
|
||||
* This structure represent a Network Data extern route info.
|
||||
*
|
||||
*/
|
||||
typedef struct otHistoryTrackerExternalRouteInfo
|
||||
{
|
||||
otExternalRouteConfig mRoute; ///< The external route entry.
|
||||
otHistoryTrackerNetDataEvent mEvent; ///< Indicates the event (added/removed).
|
||||
} otHistoryTrackerExternalRouteInfo;
|
||||
|
||||
/**
|
||||
* This function initializes an `otHistoryTrackerIterator`.
|
||||
*
|
||||
@@ -311,6 +342,41 @@ const otHistoryTrackerNeighborInfo *otHistoryTrackerIterateNeighborHistory(otIns
|
||||
otHistoryTrackerIterator *aIterator,
|
||||
uint32_t * aEntryAge);
|
||||
|
||||
/**
|
||||
* This function iterates over the entries in the Network Data on mesh prefix entry 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 `otHistoryTrackerOnMeshPrefixInfo` entry or `NULL` if no more entries in the list.
|
||||
*
|
||||
*/
|
||||
const otHistoryTrackerOnMeshPrefixInfo *otHistoryTrackerIterateOnMeshPrefixHistory(otInstance * aInstance,
|
||||
otHistoryTrackerIterator *aIterator,
|
||||
uint32_t * aEntryAge);
|
||||
|
||||
/**
|
||||
* This function iterates over the entries in the Network Data external route entry 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 `otHistoryTrackerExternalRouteInfo` entry or `NULL` if no more entries in the list.
|
||||
*
|
||||
*/
|
||||
const otHistoryTrackerExternalRouteInfo *otHistoryTrackerIterateExternalRouteHistory(
|
||||
otInstance * aInstance,
|
||||
otHistoryTrackerIterator *aIterator,
|
||||
uint32_t * aEntryAge);
|
||||
|
||||
/**
|
||||
* This function converts a given entry age to a human-readable string.
|
||||
*
|
||||
|
||||
@@ -53,7 +53,7 @@ extern "C" {
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (185)
|
||||
#define OPENTHREAD_API_VERSION (186)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -15,6 +15,8 @@ Usage : `history [command] ...`
|
||||
- [ipmaddr](#ipmaddr)
|
||||
- [neighbor](#neighbor)
|
||||
- [netinfo](#netinfo)
|
||||
- [prefix](#prefix)
|
||||
- [route](#route)
|
||||
- [rx](#rx)
|
||||
- [rxtx](#rxtx)
|
||||
- [tx](#tx)
|
||||
@@ -52,6 +54,8 @@ ipaddr
|
||||
ipmaddr
|
||||
neighbor
|
||||
netinfo
|
||||
prefix
|
||||
route
|
||||
rx
|
||||
rxtx
|
||||
tx
|
||||
@@ -243,6 +247,96 @@ Print only the latest 2 entries.
|
||||
Done
|
||||
```
|
||||
|
||||
### prefix
|
||||
|
||||
Usage `history prefix [list] [<num-entries>]`
|
||||
|
||||
Print the Network Data on mesh prefix history. Each item provides:
|
||||
|
||||
- Event (`Added` or `Removed`)
|
||||
- Prefix
|
||||
- Flags
|
||||
- Preference (`high`, `med`, `low`)
|
||||
- RLOC16
|
||||
|
||||
The flags are as follows:
|
||||
|
||||
- `p`: Preferred flag
|
||||
- `a`: Stateless IPv6 Address Autoconfiguration flag
|
||||
- `d`: DHCPv6 IPv6 Address Configuration flag
|
||||
- `c`: DHCPv6 Other Configuration flag
|
||||
- `r`: Default Route flag
|
||||
- `o`: On Mesh flag
|
||||
- `s`: Stable flag
|
||||
- `n`: Nd Dns flag
|
||||
- `D`: Domain Prefix flag
|
||||
|
||||
Print the history as a table.
|
||||
|
||||
```bash
|
||||
> history prefix
|
||||
| Age | Event | Prefix | Flags | Pref | RLOC16 |
|
||||
+----------------------+---------+---------------------------------------------+-----------+------+--------+
|
||||
| 00:00:10.663 | Added | fd00:1111:2222:3333::/64 | paro | med | 0x5400 |
|
||||
| 00:01:02.054 | Removed | fd00:dead:beef:1::/64 | paros | high | 0x5400 |
|
||||
| 00:01:21.136 | Added | fd00:abba:cddd:0::/64 | paos | med | 0x5400 |
|
||||
| 00:01:45.144 | Added | fd00:dead:beef:1::/64 | paros | high | 0x3c00 |
|
||||
| 00:01:50.944 | Added | fd00:dead:beef:1::/64 | paros | high | 0x5400 |
|
||||
| 00:01:59.887 | Added | fd00:dead:beef:1::/64 | paros | med | 0x8800 |
|
||||
Done
|
||||
```
|
||||
|
||||
Print the history as a list.
|
||||
|
||||
```bash
|
||||
> history prefix list
|
||||
00:04:12.487 -> event:Added prefix:fd00:1111:2222:3333::/64 flags:paro pref:med rloc16:0x5400
|
||||
00:05:03.878 -> event:Removed prefix:fd00:dead:beef:1::/64 flags:paros pref:high rloc16:0x5400
|
||||
00:05:22.960 -> event:Added prefix:fd00:abba:cddd:0::/64 flags:paos pref:med rloc16:0x5400
|
||||
00:05:46.968 -> event:Added prefix:fd00:dead:beef:1::/64 flags:paros pref:high rloc16:0x3c00
|
||||
00:05:52.768 -> event:Added prefix:fd00:dead:beef:1::/64 flags:paros pref:high rloc16:0x5400
|
||||
00:06:01.711 -> event:Added prefix:fd00:dead:beef:1::/64 flags:paros pref:med rloc16:0x8800
|
||||
```
|
||||
|
||||
### prefix
|
||||
|
||||
Usage `history route [list] [<num-entries>]`
|
||||
|
||||
Print the Network Data external route history. Each item provides:
|
||||
|
||||
- Event (`Added` or `Removed`)
|
||||
- Route
|
||||
- Flags
|
||||
- Preference (`high`, `med`, `low`)
|
||||
- RLOC16
|
||||
|
||||
The flags are as follows:
|
||||
|
||||
- `s`: Stable flag
|
||||
- `n`: NAT64 flag
|
||||
|
||||
Print the history as a table.
|
||||
|
||||
```bash
|
||||
history route
|
||||
| Age | Event | Route | Flags | Pref | RLOC16 |
|
||||
+----------------------+---------+---------------------------------------------+-----------+------+--------+
|
||||
| 00:00:05.456 | Removed | fd00:1111:0::/48 | s | med | 0x3c00 |
|
||||
| 00:00:29.310 | Added | fd00:1111:0::/48 | s | med | 0x3c00 |
|
||||
| 00:00:42.822 | Added | fd00:1111:0::/48 | s | med | 0x5400 |
|
||||
| 00:01:27.688 | Added | fd00:aaaa:bbbb:cccc::/64 | s | med | 0x8800 |
|
||||
Done
|
||||
```
|
||||
|
||||
Print the history as a list (last two entries).
|
||||
|
||||
```bash
|
||||
> history route list 2
|
||||
00:00:48.704 -> event:Removed route:fd00:1111:0::/48 flags:s pref:med rloc16:0x3c00
|
||||
00:01:12.558 -> event:Added route:fd00:1111:0::/48 flags:s pref:med rloc16:0x3c00
|
||||
Done
|
||||
```
|
||||
|
||||
### rx
|
||||
|
||||
Usage `history rx [list] [<num-entries>]`
|
||||
|
||||
+107
-7
@@ -44,6 +44,11 @@ namespace Cli {
|
||||
|
||||
constexpr History::Command History::sCommands[];
|
||||
|
||||
static const char *const kSimpleEventStrings[] = {
|
||||
"Added", // (0) OT_HISTORY_TRACKER_{NET_DATA_ENTRY/ADDRESSS_EVENT}_ADDED
|
||||
"Removed" // (1) OT_HISTORY_TRACKER_{NET_DATA_ENTRY/ADDRESS_EVENT}_REMOVED
|
||||
};
|
||||
|
||||
otError History::ProcessHelp(Arg aArgs[])
|
||||
{
|
||||
OT_UNUSED_VARIABLE(aArgs);
|
||||
@@ -82,11 +87,6 @@ otError History::ParseArgs(Arg aArgs[], bool &aIsList, uint16_t &aNumEntries) co
|
||||
|
||||
otError History::ProcessIpAddr(Arg aArgs[])
|
||||
{
|
||||
static const char *const kEventStrings[] = {
|
||||
"Added", // (0) OT_HISTORY_TRACKER_ADDRESS_EVENT_ADDED
|
||||
"Removed" // (1) OT_HISTORY_TRACKER_ADDRESS_EVENT_REMOVED
|
||||
};
|
||||
|
||||
otError error;
|
||||
bool isList;
|
||||
uint16_t numEntries;
|
||||
@@ -129,14 +129,14 @@ otError History::ProcessIpAddr(Arg aArgs[])
|
||||
sprintf(&addressString[strlen(addressString)], "/%d", info->mPrefixLength);
|
||||
|
||||
OutputLine("| %20s | %-7s | %-43s | %-6s | %3d | %c | %c | %c |", ageString,
|
||||
Stringify(info->mEvent, kEventStrings), addressString,
|
||||
Stringify(info->mEvent, kSimpleEventStrings), addressString,
|
||||
Interpreter::AddressOriginToString(info->mAddressOrigin), info->mScope,
|
||||
info->mPreferred ? 'Y' : 'N', info->mValid ? 'Y' : 'N', info->mRloc ? 'Y' : 'N');
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputLine("%s -> event:%s address:%s prefixlen:%d origin:%s scope:%d preferred:%s valid:%s rloc:%s",
|
||||
ageString, Stringify(info->mEvent, kEventStrings), addressString, info->mPrefixLength,
|
||||
ageString, Stringify(info->mEvent, kSimpleEventStrings), addressString, info->mPrefixLength,
|
||||
Interpreter::AddressOriginToString(info->mAddressOrigin), info->mScope,
|
||||
info->mPreferred ? "yes" : "no", info->mValid ? "yes" : "no", info->mRloc ? "yes" : "no");
|
||||
}
|
||||
@@ -571,6 +571,106 @@ void History::OutputRxTxEntryTableFormat(const otHistoryTrackerMessageInfo &aInf
|
||||
OutputLine("| %20s | dst: %-70s |", "", addrString);
|
||||
}
|
||||
|
||||
otError History::ProcessPrefix(Arg aArgs[])
|
||||
{
|
||||
otError error;
|
||||
bool isList;
|
||||
uint16_t numEntries;
|
||||
otHistoryTrackerIterator iterator;
|
||||
const otHistoryTrackerOnMeshPrefixInfo *info;
|
||||
uint32_t entryAge;
|
||||
char ageString[OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE];
|
||||
char prefixString[OT_IP6_PREFIX_STRING_SIZE];
|
||||
NetworkData::FlagsString flagsString;
|
||||
|
||||
static_assert(0 == OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED, "NET_DATA_ENTRY_ADDED value is incorrect");
|
||||
static_assert(1 == OT_HISTORY_TRACKER_NET_DATA_ENTRY_REMOVED, "NET_DATA_ENTRY_REMOVED value is incorrect");
|
||||
|
||||
SuccessOrExit(error = ParseArgs(aArgs, isList, numEntries));
|
||||
|
||||
if (!isList)
|
||||
{
|
||||
// | Age | Event | Prefix | Flags | Pref | RLOC16 |
|
||||
// +----------------------+---------+---------------------------------------------+-----------+------+--------+
|
||||
|
||||
static const char *const kPrefixTitles[] = {"Age", "Event", "Prefix", "Flags", "Pref", "RLOC16"};
|
||||
static const uint8_t kPrefixColumnWidths[] = {22, 9, 45, 11, 6, 8};
|
||||
|
||||
OutputTableHeader(kPrefixTitles, kPrefixColumnWidths);
|
||||
}
|
||||
|
||||
otHistoryTrackerInitIterator(&iterator);
|
||||
|
||||
for (uint16_t index = 0; (numEntries == 0) || (index < numEntries); index++)
|
||||
{
|
||||
info = otHistoryTrackerIterateOnMeshPrefixHistory(GetInstancePtr(), &iterator, &entryAge);
|
||||
VerifyOrExit(info != nullptr);
|
||||
|
||||
otHistoryTrackerEntryAgeToString(entryAge, ageString, sizeof(ageString));
|
||||
|
||||
otIp6PrefixToString(&info->mPrefix.mPrefix, prefixString, sizeof(prefixString));
|
||||
NetworkData::PrefixFlagsToString(info->mPrefix, flagsString);
|
||||
|
||||
OutputLine(isList ? "%s -> event:%s prefix:%s flags:%s pref:%s rloc16:0x%04x"
|
||||
: "| %20s | %-7s | %-43s | %-9s | %-4s | 0x%04x |",
|
||||
ageString, Stringify(info->mEvent, kSimpleEventStrings), prefixString, flagsString,
|
||||
NetworkData::PreferenceToString(info->mPrefix.mPreference), info->mPrefix.mRloc16);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError History::ProcessRoute(Arg aArgs[])
|
||||
{
|
||||
otError error;
|
||||
bool isList;
|
||||
uint16_t numEntries;
|
||||
otHistoryTrackerIterator iterator;
|
||||
const otHistoryTrackerExternalRouteInfo *info;
|
||||
uint32_t entryAge;
|
||||
char ageString[OT_HISTORY_TRACKER_ENTRY_AGE_STRING_SIZE];
|
||||
char prefixString[OT_IP6_PREFIX_STRING_SIZE];
|
||||
NetworkData::FlagsString flagsString;
|
||||
|
||||
static_assert(0 == OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED, "NET_DATA_ENTRY_ADDED value is incorrect");
|
||||
static_assert(1 == OT_HISTORY_TRACKER_NET_DATA_ENTRY_REMOVED, "NET_DATA_ENTRY_REMOVED value is incorrect");
|
||||
|
||||
SuccessOrExit(error = ParseArgs(aArgs, isList, numEntries));
|
||||
|
||||
if (!isList)
|
||||
{
|
||||
// | Age | Event | Route | Flags | Pref | RLOC16 |
|
||||
// +----------------------+---------+---------------------------------------------+-----------+------+--------+
|
||||
|
||||
static const char *const kRouteTitles[] = {"Age", "Event", "Route", "Flags", "Pref", "RLOC16"};
|
||||
static const uint8_t kRouteColumnWidths[] = {22, 9, 45, 11, 6, 8};
|
||||
|
||||
OutputTableHeader(kRouteTitles, kRouteColumnWidths);
|
||||
}
|
||||
|
||||
otHistoryTrackerInitIterator(&iterator);
|
||||
|
||||
for (uint16_t index = 0; (numEntries == 0) || (index < numEntries); index++)
|
||||
{
|
||||
info = otHistoryTrackerIterateExternalRouteHistory(GetInstancePtr(), &iterator, &entryAge);
|
||||
VerifyOrExit(info != nullptr);
|
||||
|
||||
otHistoryTrackerEntryAgeToString(entryAge, ageString, sizeof(ageString));
|
||||
|
||||
otIp6PrefixToString(&info->mRoute.mPrefix, prefixString, sizeof(prefixString));
|
||||
NetworkData::RouteFlagsToString(info->mRoute, flagsString);
|
||||
|
||||
OutputLine(isList ? "%s -> event:%s route:%s flags:%s pref:%s rloc16:0x%04x"
|
||||
: "| %20s | %-7s | %-43s | %-9s | %-4s | 0x%04x |",
|
||||
ageString, Stringify(info->mEvent, kSimpleEventStrings), prefixString, flagsString,
|
||||
NetworkData::PreferenceToString(info->mRoute.mPreference), info->mRoute.mRloc16);
|
||||
}
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
otError History::Process(Arg aArgs[])
|
||||
{
|
||||
otError error = OT_ERROR_INVALID_COMMAND;
|
||||
|
||||
@@ -93,6 +93,8 @@ private:
|
||||
otError ProcessIpMulticastAddr(Arg aArgs[]);
|
||||
otError ProcessNetInfo(Arg aArgs[]);
|
||||
otError ProcessNeighbor(Arg aArgs[]);
|
||||
otError ProcessPrefix(Arg aArgs[]);
|
||||
otError ProcessRoute(Arg aArgs[]);
|
||||
otError ProcessRx(Arg aArgs[]);
|
||||
otError ProcessRxTx(Arg aArgs[]);
|
||||
otError ProcessTx(Arg aArgs[]);
|
||||
@@ -112,6 +114,8 @@ private:
|
||||
{"ipmaddr", &History::ProcessIpMulticastAddr},
|
||||
{"neighbor", &History::ProcessNeighbor},
|
||||
{"netinfo", &History::ProcessNetInfo},
|
||||
{"prefix", &History::ProcessPrefix},
|
||||
{"route", &History::ProcessRoute},
|
||||
{"rx", &History::ProcessRx},
|
||||
{"rxtx", &History::ProcessRxTx},
|
||||
{"tx", &History::ProcessTx},
|
||||
|
||||
@@ -45,20 +45,9 @@ namespace Cli {
|
||||
|
||||
constexpr NetworkData::Command NetworkData::sCommands[];
|
||||
|
||||
void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
|
||||
void NetworkData::PrefixFlagsToString(const otBorderRouterConfig &aConfig, FlagsString &aString)
|
||||
{
|
||||
enum
|
||||
{
|
||||
// BorderRouter flag is `uint16_t` (though some of the bits are
|
||||
// reserved for future use), so we use 17 chars string (16 flags
|
||||
// plus null char at end of string).
|
||||
kMaxFlagStringSize = 17,
|
||||
};
|
||||
|
||||
char flagsString[kMaxFlagStringSize];
|
||||
char *flagsPtr = &flagsString[0];
|
||||
|
||||
OutputIp6Prefix(aConfig.mPrefix);
|
||||
char *flagsPtr = &aString[0];
|
||||
|
||||
if (aConfig.mPreferred)
|
||||
{
|
||||
@@ -106,31 +95,27 @@ void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
|
||||
}
|
||||
|
||||
*flagsPtr = '\0';
|
||||
}
|
||||
|
||||
if (flagsPtr != &flagsString[0])
|
||||
void NetworkData::OutputPrefix(const otBorderRouterConfig &aConfig)
|
||||
{
|
||||
FlagsString flagsString;
|
||||
|
||||
OutputIp6Prefix(aConfig.mPrefix);
|
||||
|
||||
PrefixFlagsToString(aConfig, flagsString);
|
||||
|
||||
if (flagsString[0] != '\0')
|
||||
{
|
||||
OutputFormat(" %s", flagsString);
|
||||
}
|
||||
|
||||
OutputPreference(aConfig.mPreference);
|
||||
|
||||
OutputLine(" %04x", aConfig.mRloc16);
|
||||
OutputLine(" %s %04x", PreferenceToString(aConfig.mPreference), aConfig.mRloc16);
|
||||
}
|
||||
|
||||
void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
|
||||
void NetworkData::RouteFlagsToString(const otExternalRouteConfig &aConfig, FlagsString &aString)
|
||||
{
|
||||
enum
|
||||
{
|
||||
// ExternalRoute flag is `uint8_t` (though some of the bits are
|
||||
// reserved for future use), so we use 9 chars string (8 flags
|
||||
// plus null char at end of string).
|
||||
kMaxFlagStringSize = 9,
|
||||
};
|
||||
|
||||
char flagsString[kMaxFlagStringSize];
|
||||
char *flagsPtr = &flagsString[0];
|
||||
|
||||
OutputIp6Prefix(aConfig.mPrefix);
|
||||
char *flagsPtr = &aString[0];
|
||||
|
||||
if (aConfig.mStable)
|
||||
{
|
||||
@@ -143,36 +128,47 @@ void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
|
||||
}
|
||||
|
||||
*flagsPtr = '\0';
|
||||
}
|
||||
|
||||
if (flagsPtr != &flagsString[0])
|
||||
void NetworkData::OutputRoute(const otExternalRouteConfig &aConfig)
|
||||
{
|
||||
FlagsString flagsString;
|
||||
|
||||
OutputIp6Prefix(aConfig.mPrefix);
|
||||
|
||||
RouteFlagsToString(aConfig, flagsString);
|
||||
|
||||
if (flagsString[0] != '\0')
|
||||
{
|
||||
OutputFormat(" %s", flagsString);
|
||||
}
|
||||
|
||||
OutputPreference(aConfig.mPreference);
|
||||
|
||||
OutputLine(" %04x", aConfig.mRloc16);
|
||||
OutputLine(" %s %04x", PreferenceToString(aConfig.mPreference), aConfig.mRloc16);
|
||||
}
|
||||
|
||||
void NetworkData::OutputPreference(signed int aPreference)
|
||||
const char *NetworkData::PreferenceToString(signed int aPreference)
|
||||
{
|
||||
const char *str = "";
|
||||
|
||||
switch (aPreference)
|
||||
{
|
||||
case OT_ROUTE_PREFERENCE_LOW:
|
||||
OutputFormat(" low");
|
||||
str = "low";
|
||||
break;
|
||||
|
||||
case OT_ROUTE_PREFERENCE_MED:
|
||||
OutputFormat(" med");
|
||||
str = "med";
|
||||
break;
|
||||
|
||||
case OT_ROUTE_PREFERENCE_HIGH:
|
||||
OutputFormat(" high");
|
||||
str = "high";
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
void NetworkData::OutputService(const otServiceConfig &aConfig)
|
||||
|
||||
@@ -52,6 +52,18 @@ class NetworkData : private OutputWrapper
|
||||
public:
|
||||
typedef Utils::CmdLineParser::Arg Arg;
|
||||
|
||||
/**
|
||||
* This constant specifies the string size for representing Network Data prefix/route entry flags.
|
||||
*
|
||||
* BorderRouter (OnMeshPrefix) TLV uses `uint16_t` for its flags and ExternalRoute uses `uint8_t`, though some of
|
||||
* the bits are not currently used and reserved for future, so 17 chars string (16 flags plus null char at end of
|
||||
* string) covers current and future flags.
|
||||
*
|
||||
*/
|
||||
static constexpr uint16_t kFlagsStringSize = 17;
|
||||
|
||||
typedef char FlagsString[kFlagsStringSize]; ///< Flags String type (char array of `kFlagsStringSize`).
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -95,6 +107,34 @@ public:
|
||||
*/
|
||||
void OutputService(const otServiceConfig &aConfig);
|
||||
|
||||
/**
|
||||
* This method converts the flags from a given prefix config to string.
|
||||
*
|
||||
* @param[in] aConfig The prefix config.
|
||||
* @param[out] aString The string to populate from @a Config flags.
|
||||
*
|
||||
*/
|
||||
static void PrefixFlagsToString(const otBorderRouterConfig &aConfig, FlagsString &aString);
|
||||
|
||||
/**
|
||||
* This method converts the flags from a given route config to string.
|
||||
*
|
||||
* @param[in] aConfig The route config.
|
||||
* @param[out] aString The string to populate from @a Config flags.
|
||||
*
|
||||
*/
|
||||
static void RouteFlagsToString(const otExternalRouteConfig &aConfig, FlagsString &aString);
|
||||
|
||||
/**
|
||||
* This static method converts a route preference value to human-readable string.
|
||||
*
|
||||
* @param[in] aPreference The preference value to convert (`OT_ROUTE_PREFERENCE_*` values).
|
||||
*
|
||||
* @returns A string representation @p aPreference.
|
||||
*
|
||||
*/
|
||||
static const char *PreferenceToString(signed int aPreference);
|
||||
|
||||
private:
|
||||
using Command = CommandEntry<NetworkData>;
|
||||
|
||||
@@ -117,7 +157,6 @@ private:
|
||||
void OutputPrefixes(bool aLocal);
|
||||
void OutputRoutes(bool aLocal);
|
||||
void OutputServices(bool aLocal);
|
||||
void OutputPreference(signed int aPreference);
|
||||
|
||||
static constexpr Command sCommands[] = {
|
||||
{"help", &NetworkData::ProcessHelp},
|
||||
|
||||
@@ -94,6 +94,23 @@ const otHistoryTrackerNeighborInfo *otHistoryTrackerIterateNeighborHistory(otIns
|
||||
return AsCoreType(aInstance).Get<Utils::HistoryTracker>().IterateNeighborHistory(AsCoreType(aIterator), *aEntryAge);
|
||||
}
|
||||
|
||||
const otHistoryTrackerOnMeshPrefixInfo *otHistoryTrackerIterateOnMeshPrefixHistory(otInstance * aInstance,
|
||||
otHistoryTrackerIterator *aIterator,
|
||||
uint32_t * aEntryAge)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Utils::HistoryTracker>().IterateOnMeshPrefixHistory(AsCoreType(aIterator),
|
||||
*aEntryAge);
|
||||
}
|
||||
|
||||
const otHistoryTrackerExternalRouteInfo *otHistoryTrackerIterateExternalRouteHistory(
|
||||
otInstance * aInstance,
|
||||
otHistoryTrackerIterator *aIterator,
|
||||
uint32_t * aEntryAge)
|
||||
{
|
||||
return AsCoreType(aInstance).Get<Utils::HistoryTracker>().IterateExternalRouteHistory(AsCoreType(aIterator),
|
||||
*aEntryAge);
|
||||
}
|
||||
|
||||
void otHistoryTrackerEntryAgeToString(uint32_t aEntryAge, char *aBuffer, uint16_t aSize)
|
||||
{
|
||||
Utils::HistoryTracker::EntryAgeToString(aEntryAge, aBuffer, aSize);
|
||||
|
||||
@@ -127,4 +127,28 @@
|
||||
#define OPENTHREAD_CONFIG_HISTORY_TRACKER_NEIGHBOR_LIST_SIZE 64
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE
|
||||
*
|
||||
* Specifies the maximum number of entries in Network Data On Mesh Prefix history list.
|
||||
*
|
||||
* Can be set to zero to configure History Tracker module not to collect prefix info.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE
|
||||
#define OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE 32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE
|
||||
*
|
||||
* Specifies the maximum number of entries in Network Data External Route history list.
|
||||
*
|
||||
* Can be set to zero to configure History Tracker module not to collect route info.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE
|
||||
#define OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE 32
|
||||
#endif
|
||||
|
||||
#endif // CONFIG_HISTORY_TRACKER_H_
|
||||
|
||||
@@ -52,6 +52,9 @@ namespace Utils {
|
||||
HistoryTracker::HistoryTracker(Instance &aInstance)
|
||||
: InstanceLocator(aInstance)
|
||||
, mTimer(aInstance, HandleTimer)
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
|
||||
, mPreviousNetworkData(aInstance, mNetworkDataTlvBuffer, 0, sizeof(mNetworkDataTlvBuffer))
|
||||
#endif
|
||||
{
|
||||
mTimer.Start(kAgeCheckPeriod);
|
||||
}
|
||||
@@ -291,6 +294,86 @@ exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
|
||||
void HistoryTracker::RecordNetworkDataChange(void)
|
||||
{
|
||||
NetworkData::Iterator iterator;
|
||||
NetworkData::OnMeshPrefixConfig prefix;
|
||||
NetworkData::ExternalRouteConfig route;
|
||||
|
||||
// On mesh prefix entries
|
||||
|
||||
iterator = NetworkData::kIteratorInit;
|
||||
|
||||
while (mPreviousNetworkData.GetNextOnMeshPrefix(iterator, prefix) == kErrorNone)
|
||||
{
|
||||
if (!Get<NetworkData::Leader>().ContainsOnMeshPrefix(prefix))
|
||||
{
|
||||
RecordOnMeshPrefixEvent(kNetDataEntryRemoved, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
iterator = NetworkData::kIteratorInit;
|
||||
|
||||
while (Get<NetworkData::Leader>().GetNextOnMeshPrefix(iterator, prefix) == kErrorNone)
|
||||
{
|
||||
if (!mPreviousNetworkData.ContainsOnMeshPrefix(prefix))
|
||||
{
|
||||
RecordOnMeshPrefixEvent(kNetDataEntryAdded, prefix);
|
||||
}
|
||||
}
|
||||
|
||||
// External route entries
|
||||
|
||||
iterator = NetworkData::kIteratorInit;
|
||||
|
||||
while (mPreviousNetworkData.GetNextExternalRoute(iterator, route) == kErrorNone)
|
||||
{
|
||||
if (!Get<NetworkData::Leader>().ContainsExternalRoute(route))
|
||||
{
|
||||
RecordExternalRouteEvent(kNetDataEntryRemoved, route);
|
||||
}
|
||||
}
|
||||
|
||||
iterator = NetworkData::kIteratorInit;
|
||||
|
||||
while (Get<NetworkData::Leader>().GetNextExternalRoute(iterator, route) == kErrorNone)
|
||||
{
|
||||
if (!mPreviousNetworkData.ContainsExternalRoute(route))
|
||||
{
|
||||
RecordExternalRouteEvent(kNetDataEntryAdded, route);
|
||||
}
|
||||
}
|
||||
|
||||
SuccessOrAssert(Get<NetworkData::Leader>().CopyNetworkData(/* aSatble */ false, mPreviousNetworkData));
|
||||
}
|
||||
|
||||
void HistoryTracker::RecordOnMeshPrefixEvent(NetDataEvent aEvent, const NetworkData::OnMeshPrefixConfig &aPrefix)
|
||||
{
|
||||
OnMeshPrefixInfo *entry = mOnMeshPrefixHistory.AddNewEntry();
|
||||
|
||||
VerifyOrExit(entry != nullptr);
|
||||
entry->mPrefix = aPrefix;
|
||||
entry->mEvent = aEvent;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
void HistoryTracker::RecordExternalRouteEvent(NetDataEvent aEvent, const NetworkData::ExternalRouteConfig &aRoute)
|
||||
{
|
||||
ExternalRouteInfo *entry = mExternalRouteHistory.AddNewEntry();
|
||||
|
||||
VerifyOrExit(entry != nullptr);
|
||||
entry->mRoute = aRoute;
|
||||
entry->mEvent = aEvent;
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
|
||||
|
||||
void HistoryTracker::HandleNotifierEvents(Events aEvents)
|
||||
{
|
||||
if (aEvents.ContainsAny(kEventThreadRoleChanged | kEventThreadRlocAdded | kEventThreadRlocRemoved |
|
||||
@@ -298,6 +381,13 @@ void HistoryTracker::HandleNotifierEvents(Events aEvents)
|
||||
{
|
||||
RecordNetworkInfo();
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
|
||||
if (aEvents.Contains(kEventThreadNetdataChanged))
|
||||
{
|
||||
RecordNetworkDataChange();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void HistoryTracker::HandleTimer(Timer &aTimer)
|
||||
@@ -313,6 +403,8 @@ void HistoryTracker::HandleTimer(void)
|
||||
mRxHistory.UpdateAgedEntries();
|
||||
mTxHistory.UpdateAgedEntries();
|
||||
mNeighborHistory.UpdateAgedEntries();
|
||||
mOnMeshPrefixHistory.UpdateAgedEntries();
|
||||
mExternalRouteHistory.UpdateAgedEntries();
|
||||
|
||||
mTimer.Start(kAgeCheckPeriod);
|
||||
}
|
||||
|
||||
@@ -53,10 +53,20 @@
|
||||
#include "thread/mle.hpp"
|
||||
#include "thread/mle_types.hpp"
|
||||
#include "thread/neighbor_table.hpp"
|
||||
#include "thread/network_data.hpp"
|
||||
|
||||
namespace ot {
|
||||
namespace Utils {
|
||||
|
||||
#ifdef OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
|
||||
#error "OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA should not be defined directly." \
|
||||
"It is derived from other configs: on-mesh prefix and external route history list sizes"
|
||||
#endif
|
||||
|
||||
#define OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA \
|
||||
((OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE > 0) || \
|
||||
(OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE > 0))
|
||||
|
||||
/**
|
||||
* This class implements History Tracker.
|
||||
*
|
||||
@@ -110,35 +120,13 @@ public:
|
||||
void SetInitTime(void) { mData32 = TimerMilli::GetNow().GetValue(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* This type represents Thread network info.
|
||||
*
|
||||
*/
|
||||
typedef otHistoryTrackerNetworkInfo NetworkInfo;
|
||||
|
||||
/**
|
||||
* This structure represents a unicast IPv6 address info.
|
||||
*
|
||||
*/
|
||||
typedef otHistoryTrackerUnicastAddressInfo UnicastAddressInfo;
|
||||
|
||||
/**
|
||||
* This structure represent a multicast IPv6 address info.
|
||||
*
|
||||
*/
|
||||
typedef otHistoryTrackerMulticastAddressInfo MulticastAddressInfo;
|
||||
|
||||
/**
|
||||
* This type represents a RX/TX IPv6 message info.
|
||||
*
|
||||
*/
|
||||
typedef otHistoryTrackerMessageInfo MessageInfo;
|
||||
|
||||
/**
|
||||
* This type represents a neighbor info.
|
||||
*
|
||||
*/
|
||||
typedef otHistoryTrackerNeighborInfo NeighborInfo;
|
||||
typedef otHistoryTrackerNetworkInfo NetworkInfo; ///< Thread network info.
|
||||
typedef otHistoryTrackerUnicastAddressInfo UnicastAddressInfo; ///< Unicast IPv6 address info.
|
||||
typedef otHistoryTrackerMulticastAddressInfo MulticastAddressInfo; ///< Multicast IPv6 address info.
|
||||
typedef otHistoryTrackerMessageInfo MessageInfo; ///< RX/TX IPv6 message info.
|
||||
typedef otHistoryTrackerNeighborInfo NeighborInfo; ///< Neighbor info.
|
||||
typedef otHistoryTrackerOnMeshPrefixInfo OnMeshPrefixInfo; ///< Network Data on mesh prefix info.
|
||||
typedef otHistoryTrackerExternalRouteInfo ExternalRouteInfo; ///< Network Data external route info
|
||||
|
||||
/**
|
||||
* This constructor initializes the `HistoryTracker`.
|
||||
@@ -233,6 +221,16 @@ public:
|
||||
return mNeighborHistory.Iterate(aIterator, aEntryAge);
|
||||
}
|
||||
|
||||
const OnMeshPrefixInfo *IterateOnMeshPrefixHistory(Iterator &aIterator, uint32_t &aEntryAge) const
|
||||
{
|
||||
return mOnMeshPrefixHistory.Iterate(aIterator, aEntryAge);
|
||||
}
|
||||
|
||||
const ExternalRouteInfo *IterateExternalRouteHistory(Iterator &aIterator, uint32_t &aEntryAge) const
|
||||
{
|
||||
return mExternalRouteHistory.Iterate(aIterator, aEntryAge);
|
||||
}
|
||||
|
||||
/**
|
||||
* This static method converts a given entry age to a human-readable string.
|
||||
*
|
||||
@@ -262,6 +260,8 @@ 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 kOnMeshPrefixListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_ON_MESH_PREFIX_LIST_SIZE;
|
||||
static constexpr uint16_t kExternalRouteListSize = OPENTHREAD_CONFIG_HISTORY_TRACKER_EXTERNAL_ROUTE_LIST_SIZE;
|
||||
|
||||
typedef otHistoryTrackerAddressEvent AddressEvent;
|
||||
|
||||
@@ -278,6 +278,11 @@ private:
|
||||
static constexpr NeighborEvent kNeighborChanged = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_CHANGED;
|
||||
static constexpr NeighborEvent kNeighborRestoring = OT_HISTORY_TRACKER_NEIGHBOR_EVENT_RESTORING;
|
||||
|
||||
typedef otHistoryTrackerNetDataEvent NetDataEvent;
|
||||
|
||||
static constexpr NetDataEvent kNetDataEntryAdded = OT_HISTORY_TRACKER_NET_DATA_ENTRY_ADDED;
|
||||
static constexpr NetDataEvent kNetDataEntryRemoved = OT_HISTORY_TRACKER_NET_DATA_ENTRY_REMOVED;
|
||||
|
||||
class Timestamp
|
||||
{
|
||||
public:
|
||||
@@ -379,6 +384,11 @@ private:
|
||||
void HandleNotifierEvents(Events aEvents);
|
||||
static void HandleTimer(Timer &aTimer);
|
||||
void HandleTimer(void);
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
|
||||
void RecordNetworkDataChange(void);
|
||||
void RecordOnMeshPrefixEvent(NetDataEvent aEvent, const NetworkData::OnMeshPrefixConfig &aPrefix);
|
||||
void RecordExternalRouteEvent(NetDataEvent aEvent, const NetworkData::ExternalRouteConfig &aRoute);
|
||||
#endif
|
||||
|
||||
EntryList<NetworkInfo, kNetInfoListSize> mNetInfoHistory;
|
||||
EntryList<UnicastAddressInfo, kUnicastAddrListSize> mUnicastAddressHistory;
|
||||
@@ -386,8 +396,16 @@ private:
|
||||
EntryList<MessageInfo, kRxListSize> mRxHistory;
|
||||
EntryList<MessageInfo, kTxListSize> mTxHistory;
|
||||
EntryList<NeighborInfo, kNeighborListSize> mNeighborHistory;
|
||||
EntryList<OnMeshPrefixInfo, kOnMeshPrefixListSize> mOnMeshPrefixHistory;
|
||||
EntryList<ExternalRouteInfo, kExternalRouteListSize> mExternalRouteHistory;
|
||||
|
||||
TimerMilli mTimer;
|
||||
|
||||
#if OPENTHREAD_CONFIG_HISTORY_TRACKER_NET_DATA
|
||||
NetworkData::MutableNetworkData mPreviousNetworkData;
|
||||
|
||||
uint8_t mNetworkDataTlvBuffer[NetworkData::NetworkData::kMaxSize];
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace Utils
|
||||
@@ -396,6 +414,8 @@ DefineCoreType(otHistoryTrackerIterator, Utils::HistoryTracker::Iterator);
|
||||
DefineCoreType(otHistoryTrackerNetworkInfo, Utils::HistoryTracker::NetworkInfo);
|
||||
DefineCoreType(otHistoryTrackerMessageInfo, Utils::HistoryTracker::MessageInfo);
|
||||
DefineCoreType(otHistoryTrackerNeighborInfo, Utils::HistoryTracker::NeighborInfo);
|
||||
DefineCoreType(otHistoryTrackerOnMeshPrefixInfo, Utils::HistoryTracker::OnMeshPrefixInfo);
|
||||
DefineCoreType(otHistoryTrackerExternalRouteInfo, Utils::HistoryTracker::ExternalRouteInfo);
|
||||
|
||||
} // namespace ot
|
||||
|
||||
|
||||
Reference in New Issue
Block a user