[netdiag] add support for new BR Diagnostic TLVs (#11951)

This commit introduces new Network Diagnostic TLVs to report Border
Router information. It implements the server and client side logic to
support these new TLVs:

- BR state (38) - `uint8` value as `otBorderRoutingState`.
- BR Infra Interface Addresses (39) - list of IPv6 addresses
- BR Local OMR Prefix (40) - local (ULA) OMR prefix
- BR DHCPv6-PD OMR prefix (41) - DHCPv6-PD prefix (if any)
- BR Local On-link Prefix (42) - local on-link prefix
- BR Favored On-link Prefix (43) -favored discovered on-link on AIL

The various BR prefix TLV values are encoded as a fixed 8 bytes value
corresponding to the IPv6 prefix bytes (`/64`) in big-endian order.

This commit updates the `networkdiagnostic get` CLI command to display
the information from these new TLVs.

It also includes a test (added in `test-503-peer-tbr-discovery.py`) to
verify the new TLVs and the CLI commands.
This commit is contained in:
Abtin Keshavarzian
2025-10-08 19:11:44 -07:00
committed by GitHub
parent af6279f606
commit 2176ef719b
14 changed files with 363 additions and 79 deletions
+4 -4
View File
@@ -191,10 +191,10 @@ typedef enum
*/
typedef enum
{
OT_BORDER_ROUTING_STATE_UNINITIALIZED, ///< Routing Manager is uninitialized.
OT_BORDER_ROUTING_STATE_DISABLED, ///< Routing Manager is initialized but disabled.
OT_BORDER_ROUTING_STATE_STOPPED, ///< Routing Manager in initialized and enabled but currently stopped.
OT_BORDER_ROUTING_STATE_RUNNING, ///< Routing Manager is initialized, enabled, and running.
OT_BORDER_ROUTING_STATE_UNINITIALIZED = 0, ///< Routing Manager is uninitialized.
OT_BORDER_ROUTING_STATE_DISABLED = 1, ///< Routing Manager is initialized but disabled.
OT_BORDER_ROUTING_STATE_STOPPED = 2, ///< Routing Manager in initialized and enabled but currently stopped.
OT_BORDER_ROUTING_STATE_RUNNING = 3, ///< Routing Manager is initialized, enabled, and running.
} otBorderRoutingState;
/**
+1 -1
View File
@@ -52,7 +52,7 @@ extern "C" {
*
* @note This number versions both OpenThread platform and user APIs.
*/
#define OPENTHREAD_API_VERSION (540)
#define OPENTHREAD_API_VERSION (541)
/**
* @addtogroup api-instance
+15
View File
@@ -38,6 +38,7 @@
#include <stdbool.h>
#include <stdint.h>
#include <openthread/border_routing.h>
#include <openthread/dataset.h>
#include <openthread/error.h>
#include <openthread/instance.h>
@@ -87,6 +88,12 @@ extern "C" {
#define OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL 35 ///< Vendor App URL TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_NON_PREFERRED_CHANNELS 36 ///< Non-Preferred Channels Mask TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_ENHANCED_ROUTE 37 ///< Enhanced Route TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_BR_STATE 38 ///< Border Router State TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_BR_IF_ADDRS 39 ///< Border Router Infra Interface Addresses TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_BR_LOCAL_OMR_PREFIX 40 ///< Border Router Local OMR Prefix TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_BR_DHCP6_PD_OMR_PREFIX 41 ///< Border Router DHCPv6-PD OMR Prefix TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_BR_LOCAL_OL_PREFIX 42 ///< Border Router Local On-link Prefix TLV
#define OT_NETWORK_DIAGNOSTIC_TLV_BR_FAVORED_OL_PREFIX 43 ///< Border Router Favored On-link Prefix TLV
#define OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_NAME_TLV_LENGTH 32 ///< Max length of Vendor Name TLV.
#define OT_NETWORK_DIAGNOSTIC_MAX_VENDOR_MODEL_TLV_LENGTH 32 ///< Max length of Vendor Model TLV.
@@ -261,6 +268,11 @@ typedef struct otNetworkDiagChildTable
otNetworkDiagChildEntry mTable[OT_NETWORK_BASE_TLV_MAX_LENGTH / sizeof(otNetworkDiagChildEntry)]; ///< Child table.
} otNetworkDiagChildTable;
/**
* Represents a Border Router State TLV value.
*/
typedef otBorderRoutingState otNetworkDiagBrState;
/**
* Represents a Network Diagnostic TLV.
*/
@@ -295,6 +307,9 @@ typedef struct otNetworkDiagTlv
otChannelMask mNonPreferredChannels;
otNetworkDiagData mChannelPages;
otNetworkDiagChildTable mChildTable;
otNetworkDiagBrState mBrState;
otNetworkDiagIp6AddrList mBrIfAddrList;
otIp6NetworkPrefix mBrPrefix; // This field is shared for various BR prefix TLV (OMR, on-link).
} mData;
} otNetworkDiagTlv;
+40 -5
View File
@@ -7864,6 +7864,13 @@ template <> otError Interpreter::Process<Cmd("networkdiagnostic")>(Arg aArgs[])
* - `34`: MLE Counters TLV
* - `35`: Vendor App URL TLV
* - `37`: Enhanced Route TLV
* - `38`: Border Router State TLV
* - `39`: Border Router Infra Interface Addresses TLV
* - `40`: Border Router Local OMR Prefix TLV
* - `41`: Border Router DHCPv6-PD OMR Prefix TLV
* - `42`: Border Router Local On-link Prefix TLV
* - `43`: Border Router Favored On-link Prefix TLV
*
* @par
* Sends a network diagnostic request to retrieve specified Type Length Values (TLVs)
* for the specified addresses(es).
@@ -7986,11 +7993,7 @@ void Interpreter::HandleDiagnosticGetResponse(otError aError,
break;
case OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST:
OutputLine("IP6 Address List:");
for (uint16_t i = 0; i < diagTlv.mData.mIp6AddrList.mCount; ++i)
{
OutputFormat(kIndentSize, "- ");
OutputIp6AddressLine(diagTlv.mData.mIp6AddrList.mList[i]);
}
OutputIp6AddrList(kIndentSize, diagTlv.mData.mIp6AddrList);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS:
OutputLine("MAC Counters:");
@@ -8044,6 +8047,29 @@ void Interpreter::HandleDiagnosticGetResponse(otError aError,
case OT_NETWORK_DIAGNOSTIC_TLV_NON_PREFERRED_CHANNELS:
OutputLine("Non-preferred Channels Mask: 0x%lx", ToUlong(diagTlv.mData.mNonPreferredChannels));
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BR_STATE:
OutputLine("BR State: %s", BorderRoutingStateToString(diagTlv.mData.mBrState));
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BR_IF_ADDRS:
OutputLine("BR Infra-if IP6 Address List:");
OutputIp6AddrList(kIndentSize, diagTlv.mData.mBrIfAddrList);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BR_LOCAL_OMR_PREFIX:
OutputFormat("BR Local OMR Prefix: ");
OutputIp6PrefixLine(diagTlv.mData.mBrPrefix);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BR_DHCP6_PD_OMR_PREFIX:
OutputFormat("BR DHCPv6-PD OMR Prefix: ");
OutputIp6PrefixLine(diagTlv.mData.mBrPrefix);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BR_LOCAL_OL_PREFIX:
OutputFormat("BR Local On-link Prefix: ");
OutputIp6PrefixLine(diagTlv.mData.mBrPrefix);
break;
case OT_NETWORK_DIAGNOSTIC_TLV_BR_FAVORED_OL_PREFIX:
OutputFormat("BR Favored On-link Prefix: ");
OutputIp6PrefixLine(diagTlv.mData.mBrPrefix);
break;
default:
break;
}
@@ -8134,6 +8160,15 @@ void Interpreter::OutputLeaderData(uint8_t aIndentSize, const otLeaderData &aLea
OutputLine(aIndentSize, "LeaderRouterId: 0x%02x", aLeaderData.mLeaderRouterId);
}
void Interpreter::OutputIp6AddrList(uint8_t aIndentSize, const otNetworkDiagIp6AddrList &aIp6Addrs)
{
for (uint8_t i = 0; i < aIp6Addrs.mCount; ++i)
{
OutputFormat(aIndentSize, "- ");
OutputIp6AddressLine(aIp6Addrs.mList[i]);
}
}
void Interpreter::OutputNetworkDiagMacCounters(uint8_t aIndentSize, const otNetworkDiagMacCounters &aMacCounters)
{
struct CounterName
+1
View File
@@ -264,6 +264,7 @@ private:
void OutputRouteData(uint8_t aIndentSize, const otNetworkDiagRouteData &aRouteData);
void OutputEnhRoute(uint8_t aIndentSize, const otNetworkDiagEnhRoute &aEnhRoute);
void OutputLeaderData(uint8_t aIndentSize, const otLeaderData &aLeaderData);
void OutputIp6AddrList(uint8_t aIndentSize, const otNetworkDiagIp6AddrList &aIp6Addrs);
void OutputNetworkDiagMacCounters(uint8_t aIndentSize, const otNetworkDiagMacCounters &aMacCounters);
void OutputNetworkDiagMleCounters(uint8_t aIndentSize, const otNetworkDiagMleCounters &aMleCounters);
void OutputChildTableEntry(uint8_t aIndentSize, const otNetworkDiagChildEntry &aChildEntry);
+1 -14
View File
@@ -145,23 +145,10 @@ exit:
*/
template <> otError Br::Process<Cmd("state")>(Arg aArgs[])
{
static const char *const kStateStrings[] = {
"uninitialized", // (0) OT_BORDER_ROUTING_STATE_UNINITIALIZED
"disabled", // (1) OT_BORDER_ROUTING_STATE_DISABLED
"stopped", // (2) OT_BORDER_ROUTING_STATE_STOPPED
"running", // (3) OT_BORDER_ROUTING_STATE_RUNNING
};
otError error = OT_ERROR_NONE;
static_assert(0 == OT_BORDER_ROUTING_STATE_UNINITIALIZED, "STATE_UNINITIALIZED value is incorrect");
static_assert(1 == OT_BORDER_ROUTING_STATE_DISABLED, "STATE_DISABLED value is incorrect");
static_assert(2 == OT_BORDER_ROUTING_STATE_STOPPED, "STATE_STOPPED value is incorrect");
static_assert(3 == OT_BORDER_ROUTING_STATE_RUNNING, "STATE_RUNNING value is incorrect");
VerifyOrExit(aArgs[0].IsEmpty(), error = OT_ERROR_INVALID_ARGS);
OutputLine("%s", Stringify(otBorderRoutingGetState(GetInstancePtr()), kStateStrings));
OutputLine("%s", BorderRoutingStateToString(otBorderRoutingGetState(GetInstancePtr())));
exit:
return error;
+17
View File
@@ -810,5 +810,22 @@ const char *Utils::AddressOriginToString(uint8_t aOrigin)
return Stringify(aOrigin, kOriginStrings);
}
const char *Utils::BorderRoutingStateToString(otBorderRoutingState aState)
{
static const char *const kStateStrings[] = {
"uninitialized", // (0) OT_BORDER_ROUTING_STATE_UNINITIALIZED
"disabled", // (1) OT_BORDER_ROUTING_STATE_DISABLED
"stopped", // (2) OT_BORDER_ROUTING_STATE_STOPPED
"running", // (3) OT_BORDER_ROUTING_STATE_RUNNING
};
static_assert(0 == OT_BORDER_ROUTING_STATE_UNINITIALIZED, "STATE_UNINITIALIZED value is incorrect");
static_assert(1 == OT_BORDER_ROUTING_STATE_DISABLED, "STATE_DISABLED value is incorrect");
static_assert(2 == OT_BORDER_ROUTING_STATE_STOPPED, "STATE_STOPPED value is incorrect");
static_assert(3 == OT_BORDER_ROUTING_STATE_RUNNING, "STATE_RUNNING value is incorrect");
return Stringify(aState, kStateStrings);
}
} // namespace Cli
} // namespace ot
+9
View File
@@ -718,6 +718,15 @@ public:
*/
static const char *AddressOriginToString(uint8_t aOrigin);
/**
* Converts a given `otBorderRoutingState` value (`OT_BORDER_ROUTING_STATE_*`) to human-readable string.
*
* @param[in] aState The BR state to convert.
*
* @returns A human-readable string representation of @p aState.
*/
static const char *BorderRoutingStateToString(otBorderRoutingState aState);
protected:
void OutputFormatV(const char *aFormat, va_list aArguments);
+11
View File
@@ -48,6 +48,17 @@ Error NetworkPrefix::GenerateRandomUla(void)
return Random::Crypto::FillBuffer(&m8[1], kSize - 1);
}
Error NetworkPrefix::SetFrom(const Prefix &aPrefix)
{
Error error = kErrorNone;
VerifyOrExit(aPrefix.GetLength() == kLength, error = kErrorInvalidArgs);
memcpy(m8, aPrefix.GetBytes(), kSize);
exit:
return error;
}
//---------------------------------------------------------------------------------------------------------------------
// Prefix methods
+12
View File
@@ -61,6 +61,8 @@ namespace Ip6 {
* @{
*/
class Prefix;
/**
* Represents the Network Prefix of an IPv6 address (most significant 64 bits of the address).
*/
@@ -80,6 +82,16 @@ public:
*/
Error GenerateRandomUla(void);
/**
* Sets the Network Prefix from a given `Prefix`.
*
* @param[in] aPrefix The prefix to use to set the Network Prefix.
*
* @retval kErrorNone Successfully set the Network Prefix from @p aPrefix.
* @retval kErrorInvalidArgs The @p aPrefix length is not valid (must be `kLength`).
*/
Error SetFrom(const Prefix &aPrefix);
} OT_TOOL_PACKED_END;
/**
+130 -23
View File
@@ -327,6 +327,82 @@ Error Server::AppendMacCounters(Message &aMessage)
return tlv.AppendTo(aMessage);
}
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
Error Server::AppendBorderRouterIfAddrs(Message &aMessage)
{
Error error;
Tlv tlv;
uint16_t offset;
uint16_t length = 0;
BorderRouter::PrefixTableIterator iterator;
BorderRouter::IfAddrEntry ifAddr;
tlv.SetType(Tlv::kBrIfAddrs);
offset = aMessage.GetLength();
SuccessOrExit(error = aMessage.Append(tlv));
Get<BorderRouter::RoutingManager>().InitPrefixTableIterator(iterator);
while (Get<BorderRouter::RoutingManager>().GetNextIfAddrEntry(iterator, ifAddr) == kErrorNone)
{
if (length + sizeof(Ip6::Address) > Tlv::kBaseTlvMaxLength)
{
break;
}
SuccessOrExit(error = aMessage.Append(ifAddr.mAddress));
length += sizeof(Ip6::Address);
}
tlv.SetLength(ClampToUint8(length));
aMessage.Write(offset, tlv);
exit:
return error;
}
Error Server::AppendBrPrefixTlv(uint8_t aTlvType, Message &aMessage)
{
Ip6::Prefix prefix;
Ip6::NetworkPrefix netPrefix;
netPrefix.Clear();
switch (aTlvType)
{
case Tlv::kBrLocalOmrPrefix:
SuccessOrExit(Get<BorderRouter::RoutingManager>().GetOmrPrefix(prefix));
break;
case Tlv::kBrLocalOnlinkPrefix:
SuccessOrExit(Get<BorderRouter::RoutingManager>().GetOnLinkPrefix(prefix));
break;
case Tlv::kBrFavoredOnLinkPrefix:
SuccessOrExit(Get<BorderRouter::RoutingManager>().GetFavoredOnLinkPrefix(prefix));
break;
#if OPENTHREAD_CONFIG_BORDER_ROUTING_DHCP6_PD_ENABLE
case Tlv::kBrDhcp6PdOmrPrefix:
{
BorderRouter::Dhcp6PdPrefix pdPrefix;
SuccessOrExit(Get<BorderRouter::RoutingManager>().GetDhcp6PdOmrPrefix(pdPrefix));
prefix = AsCoreType(&pdPrefix.mPrefix);
break;
}
#endif
default:
ExitNow();
}
IgnoreError(netPrefix.SetFrom(prefix));
exit:
return Tlv::AppendTlv(aMessage, aTlvType, &netPrefix, sizeof(netPrefix));
}
#endif // OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
Error Server::AppendRequestedTlvs(const Message &aRequest, Message &aResponse)
{
Error error;
@@ -566,6 +642,25 @@ Error Server::AppendDiagTlv(uint8_t aTlvType, Message &aMessage)
#endif // OPENTHREAD_FTD
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
case Tlv::kBrState:
error = Tlv::Append<BrStateTlv>(aMessage, Get<BorderRouter::RoutingManager>().GetState());
break;
case Tlv::kBrIfAddrs:
error = AppendBorderRouterIfAddrs(aMessage);
break;
case Tlv::kBrLocalOmrPrefix:
case Tlv::kBrDhcp6PdOmrPrefix:
case Tlv::kBrLocalOnlinkPrefix:
case Tlv::kBrFavoredOnLinkPrefix:
error = AppendBrPrefixTlv(aTlvType, aMessage);
break;
#endif
default:
break;
}
@@ -1232,7 +1327,7 @@ exit:
return error;
}
static inline void ParseMacCounters(const MacCountersTlv &aMacCountersTlv, otNetworkDiagMacCounters &aMacCounters)
void Client::ParseMacCounters(const MacCountersTlv &aMacCountersTlv, otNetworkDiagMacCounters &aMacCounters)
{
aMacCounters.mIfInUnknownProtos = aMacCountersTlv.GetIfInUnknownProtos();
aMacCounters.mIfInErrors = aMacCountersTlv.GetIfInErrors();
@@ -1245,6 +1340,19 @@ static inline void ParseMacCounters(const MacCountersTlv &aMacCountersTlv, otNet
aMacCounters.mIfOutDiscards = aMacCountersTlv.GetIfOutDiscards();
}
void Client::ParseIp6AddrList(Ip6AddrList &aIp6Addrs, const Message &aMessage, OffsetRange aOffsetRange)
{
aIp6Addrs.mCount = 0;
while (aOffsetRange.Contains(sizeof(Ip6::Address)) && (aIp6Addrs.mCount < GetArrayLength(aIp6Addrs.mList)))
{
IgnoreError(aMessage.Read(aOffsetRange, aIp6Addrs.mList[aIp6Addrs.mCount]));
aOffsetRange.AdvanceOffset(sizeof(Ip6::Address));
aIp6Addrs.mCount++;
}
}
Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator, TlvInfo &aTlvInfo)
{
Error error;
@@ -1346,29 +1454,8 @@ Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator,
break;
case Tlv::kIp6AddressList:
{
uint16_t addrListLength = GetArrayLength(aTlvInfo.mData.mIp6AddrList.mList);
Ip6::Address *addrEntry = AsCoreTypePtr(&aTlvInfo.mData.mIp6AddrList.mList[0]);
uint8_t &addrCount = aTlvInfo.mData.mIp6AddrList.mCount;
VerifyOrExit((valueOffsetRange.GetLength() % Ip6::Address::kSize) == 0, error = kErrorParse);
// `TlvInfo` has a fixed array for IPv6 addresses. If there
// are more addresses in the message, we read and return as
// many as can fit in array and ignore the rest.
addrCount = 0;
while (!valueOffsetRange.IsEmpty() && (addrCount < addrListLength))
{
SuccessOrExit(error = aMessage.Read(valueOffsetRange, *addrEntry));
addrCount++;
addrEntry++;
valueOffsetRange.AdvanceOffset(Ip6::Address::kSize);
}
ParseIp6AddrList(aTlvInfo.mData.mIp6AddrList, aMessage, valueOffsetRange);
break;
}
case Tlv::kMacCounters:
{
@@ -1476,6 +1563,26 @@ Error Client::GetNextDiagTlv(const Coap::Message &aMessage, Iterator &aIterator,
aTlvInfo.mData.mNonPreferredChannels));
break;
case Tlv::kBrState:
{
uint8_t state;
SuccessOrExit(error = Tlv::Read<BrStateTlv>(aMessage, offset, state));
aTlvInfo.mData.mBrState = static_cast<BrState>(state);
break;
}
case Tlv::kBrIfAddrs:
ParseIp6AddrList(aTlvInfo.mData.mBrIfAddrList, aMessage, valueOffsetRange);
break;
case Tlv::kBrLocalOmrPrefix:
case Tlv::kBrLocalOnlinkPrefix:
case Tlv::kBrFavoredOnLinkPrefix:
case Tlv::kBrDhcp6PdOmrPrefix:
SuccessOrExit(error = aMessage.Read(valueOffsetRange, aTlvInfo.mData.mBrPrefix));
break;
default:
// Skip unrecognized TLVs.
skipTlv = true;
+10
View File
@@ -265,6 +265,10 @@ private:
const Ip6::MessageInfo *aMessageInfo,
Error aResult);
#endif
#if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE
Error AppendBorderRouterIfAddrs(Message &aMessage);
Error AppendBrPrefixTlv(uint8_t aTlvType, Message &aMessage);
#endif
template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
@@ -357,6 +361,9 @@ public:
uint16_t GetLastQueryId(void) const { return mQueryId; }
private:
typedef otNetworkDiagIp6AddrList Ip6AddrList;
typedef otNetworkDiagMacCounters MacCounters;
Error SendCommand(Uri aUri,
Message::Priority aPriority,
const Ip6::Address &aDestination,
@@ -373,6 +380,9 @@ private:
template <Uri kUri> void HandleTmf(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void ParseIp6AddrList(Ip6AddrList &aIp6Addrs, const Message &aMessage, OffsetRange aOffsetRange);
static void ParseMacCounters(const MacCountersTlv &aMacCountersTlv, MacCounters &aMacCounters);
#if OT_SHOULD_LOG_AT(OT_LOG_LEVEL_INFO)
static const char *UriToString(Uri aUri);
#endif
+72 -31
View File
@@ -66,37 +66,43 @@ public:
*/
enum Type : uint8_t
{
kExtMacAddress = OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS,
kAddress16 = OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS,
kMode = OT_NETWORK_DIAGNOSTIC_TLV_MODE,
kTimeout = OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT,
kConnectivity = OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY,
kRoute = OT_NETWORK_DIAGNOSTIC_TLV_ROUTE,
kLeaderData = OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA,
kNetworkData = OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA,
kIp6AddressList = OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST,
kMacCounters = OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS,
kBatteryLevel = OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL,
kSupplyVoltage = OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE,
kChildTable = OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE,
kChannelPages = OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES,
kTypeList = OT_NETWORK_DIAGNOSTIC_TLV_TYPE_LIST,
kMaxChildTimeout = OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT,
kEui64 = OT_NETWORK_DIAGNOSTIC_TLV_EUI64,
kVersion = OT_NETWORK_DIAGNOSTIC_TLV_VERSION,
kVendorName = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_NAME,
kVendorModel = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_MODEL,
kVendorSwVersion = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_SW_VERSION,
kThreadStackVersion = OT_NETWORK_DIAGNOSTIC_TLV_THREAD_STACK_VERSION,
kChild = OT_NETWORK_DIAGNOSTIC_TLV_CHILD,
kChildIp6AddressList = OT_NETWORK_DIAGNOSTIC_TLV_CHILD_IP6_ADDR_LIST,
kRouterNeighbor = OT_NETWORK_DIAGNOSTIC_TLV_ROUTER_NEIGHBOR,
kAnswer = OT_NETWORK_DIAGNOSTIC_TLV_ANSWER,
kQueryId = OT_NETWORK_DIAGNOSTIC_TLV_QUERY_ID,
kMleCounters = OT_NETWORK_DIAGNOSTIC_TLV_MLE_COUNTERS,
kVendorAppUrl = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL,
kNonPreferredChannels = OT_NETWORK_DIAGNOSTIC_TLV_NON_PREFERRED_CHANNELS,
kEnhancedRoute = OT_NETWORK_DIAGNOSTIC_TLV_ENHANCED_ROUTE,
kExtMacAddress = OT_NETWORK_DIAGNOSTIC_TLV_EXT_ADDRESS,
kAddress16 = OT_NETWORK_DIAGNOSTIC_TLV_SHORT_ADDRESS,
kMode = OT_NETWORK_DIAGNOSTIC_TLV_MODE,
kTimeout = OT_NETWORK_DIAGNOSTIC_TLV_TIMEOUT,
kConnectivity = OT_NETWORK_DIAGNOSTIC_TLV_CONNECTIVITY,
kRoute = OT_NETWORK_DIAGNOSTIC_TLV_ROUTE,
kLeaderData = OT_NETWORK_DIAGNOSTIC_TLV_LEADER_DATA,
kNetworkData = OT_NETWORK_DIAGNOSTIC_TLV_NETWORK_DATA,
kIp6AddressList = OT_NETWORK_DIAGNOSTIC_TLV_IP6_ADDR_LIST,
kMacCounters = OT_NETWORK_DIAGNOSTIC_TLV_MAC_COUNTERS,
kBatteryLevel = OT_NETWORK_DIAGNOSTIC_TLV_BATTERY_LEVEL,
kSupplyVoltage = OT_NETWORK_DIAGNOSTIC_TLV_SUPPLY_VOLTAGE,
kChildTable = OT_NETWORK_DIAGNOSTIC_TLV_CHILD_TABLE,
kChannelPages = OT_NETWORK_DIAGNOSTIC_TLV_CHANNEL_PAGES,
kTypeList = OT_NETWORK_DIAGNOSTIC_TLV_TYPE_LIST,
kMaxChildTimeout = OT_NETWORK_DIAGNOSTIC_TLV_MAX_CHILD_TIMEOUT,
kEui64 = OT_NETWORK_DIAGNOSTIC_TLV_EUI64,
kVersion = OT_NETWORK_DIAGNOSTIC_TLV_VERSION,
kVendorName = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_NAME,
kVendorModel = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_MODEL,
kVendorSwVersion = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_SW_VERSION,
kThreadStackVersion = OT_NETWORK_DIAGNOSTIC_TLV_THREAD_STACK_VERSION,
kChild = OT_NETWORK_DIAGNOSTIC_TLV_CHILD,
kChildIp6AddressList = OT_NETWORK_DIAGNOSTIC_TLV_CHILD_IP6_ADDR_LIST,
kRouterNeighbor = OT_NETWORK_DIAGNOSTIC_TLV_ROUTER_NEIGHBOR,
kAnswer = OT_NETWORK_DIAGNOSTIC_TLV_ANSWER,
kQueryId = OT_NETWORK_DIAGNOSTIC_TLV_QUERY_ID,
kMleCounters = OT_NETWORK_DIAGNOSTIC_TLV_MLE_COUNTERS,
kVendorAppUrl = OT_NETWORK_DIAGNOSTIC_TLV_VENDOR_APP_URL,
kNonPreferredChannels = OT_NETWORK_DIAGNOSTIC_TLV_NON_PREFERRED_CHANNELS,
kEnhancedRoute = OT_NETWORK_DIAGNOSTIC_TLV_ENHANCED_ROUTE,
kBrState = OT_NETWORK_DIAGNOSTIC_TLV_BR_STATE,
kBrIfAddrs = OT_NETWORK_DIAGNOSTIC_TLV_BR_IF_ADDRS,
kBrLocalOmrPrefix = OT_NETWORK_DIAGNOSTIC_TLV_BR_LOCAL_OMR_PREFIX,
kBrDhcp6PdOmrPrefix = OT_NETWORK_DIAGNOSTIC_TLV_BR_DHCP6_PD_OMR_PREFIX,
kBrLocalOnlinkPrefix = OT_NETWORK_DIAGNOSTIC_TLV_BR_LOCAL_OL_PREFIX,
kBrFavoredOnLinkPrefix = OT_NETWORK_DIAGNOSTIC_TLV_BR_FAVORED_OL_PREFIX,
};
/**
@@ -235,6 +241,41 @@ typedef TlvInfo<Tlv::kChildIp6AddressList> ChildIp6AddressListTlv;
*/
typedef UintTlvInfo<Tlv::kQueryId, uint16_t> QueryIdTlv;
/**
* Defines BR State TLV constants and types.
*/
typedef UintTlvInfo<Tlv::kBrState, uint8_t> BrStateTlv;
/**
* Represents a BR State TLV value.
*/
typedef otNetworkDiagBrState BrState;
/**
* Defines BR Infra-if Address List TLV constants and types.
*/
typedef TlvInfo<Tlv::kBrIfAddrs> BrIfAddrsTlv;
/**
* Defines BR Local OMR Prefix TLV constants and types.
*/
typedef SimpleTlvInfo<Tlv::kBrLocalOmrPrefix, Ip6::NetworkPrefix> BrLocalOmrPrefixTlv;
/**
* Defines BR DHCPv6-PD Prefix TLV constants and types.
*/
typedef SimpleTlvInfo<Tlv::kBrDhcp6PdOmrPrefix, Ip6::NetworkPrefix> BrDhcp6PdOmrPrefixTlv;
/**
* Defines BR Local On-link Prefix TLV constants and types.
*/
typedef SimpleTlvInfo<Tlv::kBrLocalOnlinkPrefix, Ip6::NetworkPrefix> BrLocalOnlinkPrefixTlv;
/**
* Defines BR Favored On-link Prefix TLV constants and types.
*/
typedef SimpleTlvInfo<Tlv::kBrFavoredOnLinkPrefix, Ip6::NetworkPrefix> BrFavoredOnLinkPrefixTlv;
typedef otNetworkDiagConnectivity Connectivity; ///< Network Diagnostic Connectivity value.
/**
@@ -71,6 +71,13 @@ verify(br3.get_state() == 'router')
# -----------------------------------------------------------------------------------------------------------------------
# Test implementation
BR_STATE_TLV = 38
BR_IF_ADDRS_TLV = 39
BR_LOCAL_OMR_PREFIX_TLV = 40
BR_DHCP6_PD_OMR_PREFIX_TLV = 41
BR_LOCAL_OL_PREFIX_TLV = 42
BR_FAVORED_OL_PREFIX_TLV = 43
# Start first border router `br1`
br1.srp_server_set_addr_mode('unicast')
@@ -114,7 +121,7 @@ for br in all_brs:
verify(int(br.br_count_peers().split()[0]) == 2)
peers = br.br_get_peer_brs()
verify(len(peers) == 2)
other_brs = all_brs
other_brs = [br1, br2, br3]
other_brs.remove(br)
for other_br in other_brs:
rloc16 = other_br.get_rloc16()
@@ -123,6 +130,38 @@ for br in all_brs:
verify(len(ifaddrs) == 1)
verify(ifaddrs[0].startswith('fe80:'))
# Validate network diagnostic BR TLVs, query BR2 from BR1.
br2_rloc = br2.get_rloc_ip_addr()
result = br1.cli('networkdiagnostic get', br2_rloc, BR_STATE_TLV)
verify(len(result) == 2)
verify(result[1] == 'BR State: running')
result = br1.cli('networkdiagnostic get', br2_rloc, BR_IF_ADDRS_TLV)
verify(len(result) > 2)
verify(result[1] == 'BR Infra-if IP6 Address List:')
verify(result[2].startswith(' - fe80:'))
result = br1.cli('networkdiagnostic get', br2_rloc, BR_LOCAL_OMR_PREFIX_TLV)
verify(len(result) == 2)
verify(result[1].startswith('BR Local OMR Prefix: '))
verify(result[1].split(': ')[1].strip() == br2.br_get_local_omrprefix())
result = br1.cli('networkdiagnostic get', br2_rloc, BR_DHCP6_PD_OMR_PREFIX_TLV)
verify(len(result) == 2)
verify(result[1].startswith('BR DHCPv6-PD OMR Prefix:'))
verify(result[1].split(': ')[1].strip() == '0:0:0:0::/64')
result = br1.cli('networkdiagnostic get', br2_rloc, BR_LOCAL_OL_PREFIX_TLV)
verify(len(result) == 2)
verify(result[1].startswith('BR Local On-link Prefix: '))
verify(result[1].split(': ')[1].strip() == br2.br_get_local_onlinkprefix())
result = br1.cli('networkdiagnostic get', br2_rloc, BR_FAVORED_OL_PREFIX_TLV)
verify(len(result) == 2)
verify(result[1].startswith('BR Favored On-link Prefix: '))
verify(result[1].split(': ')[1].strip() == br2.br_get_favored_onlinkprefix())
# Disable BR3 and validate that BR1 and BR2 detect this.
# BR3 itself should continue to detect BR1 and BR2