diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 9060bbb415d..ed0a3d97529 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -146,3 +146,10 @@ if (OTBR_DHCP6_PD) else() target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_DHCP6_PD=0) endif() + +option(OTBR_LINK_METRICS_TELEMETRY "Enable Link Metrics Telemetry Upload" OFF) +if (OTBR_LINK_METRICS_TELEMETRY) + target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_LINK_METRICS_TELEMETRY=1) +else() + target_compile_definitions(otbr-config INTERFACE OTBR_ENABLE_LINK_METRICS_TELEMETRY=0) +endif() diff --git a/script/test b/script/test index f5b955cbe92..93f642cb530 100755 --- a/script/test +++ b/script/test @@ -135,6 +135,7 @@ do_build() "-DOTBR_WEB=ON" "-DOTBR_UNSECURE_JOIN=ON" "-DOTBR_TREL=ON" + "-DOTBR_LINK_METRICS_TELEMETRY=ON" ${otbr_options[@]+"${otbr_options[@]}"} ) diff --git a/src/proto/thread_telemetry.proto b/src/proto/thread_telemetry.proto index 8ffcadf91e0..2cc2851ee6a 100644 --- a/src/proto/thread_telemetry.proto +++ b/src/proto/thread_telemetry.proto @@ -478,6 +478,15 @@ message TelemetryData { optional uint32 rx_average_request_to_grant_time_us = 15; } + message LinkMetricsEntry { + optional int32 link_margin = 1; + optional int32 rssi = 2; + } + + message LowPowerMetrics { + repeated LinkMetricsEntry link_metrics_entries = 1; + } + optional WpanStats wpan_stats = 1; optional WpanTopoFull wpan_topo_full = 2; repeated TopoEntry topo_entries = 3; @@ -486,4 +495,5 @@ message TelemetryData { // Deprecate CoexMetrics with int64 as its fields types to save storage. reserved 6; optional CoexMetrics coex_metrics = 7; + optional LowPowerMetrics low_power_metrics = 8; } diff --git a/src/utils/thread_helper.cpp b/src/utils/thread_helper.cpp index 1fcca2a6820..ddd6de65a90 100644 --- a/src/utils/thread_helper.cpp +++ b/src/utils/thread_helper.cpp @@ -50,6 +50,9 @@ #include #include "utils/sha256.hpp" #endif +#if OTBR_ENABLE_LINK_METRICS_TELEMETRY +#include +#endif #if OTBR_ENABLE_SRP_ADVERTISING_PROXY #include #endif @@ -890,7 +893,8 @@ void ThreadHelper::DetachGracefullyCallback(void) #if OTBR_ENABLE_TELEMETRY_DATA_API otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher &aPublisher, threadnetwork::TelemetryData &telemetryData) { - otError error = OT_ERROR_NONE; + otError error = OT_ERROR_NONE; + std::vector neighborTable; // Begin of WpanStats section. auto wpanStats = telemetryData.mutable_wpan_stats(); @@ -973,9 +977,8 @@ otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher &aPublisher, threadn VerifyOrExit(otThreadGetRouterInfo(mInstance, rloc16, &info) == OT_ERROR_NONE, error = OT_ERROR_INVALID_STATE); wpanTopoFull->set_router_id(info.mRouterId); - otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; - otNeighborInfo neighborInfo; - std::vector neighborTable; + otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; + otNeighborInfo neighborInfo; while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighborInfo) == OT_ERROR_NONE) { @@ -1382,6 +1385,28 @@ otError ThreadHelper::RetrieveTelemetryData(Mdns::Publisher &aPublisher, threadn // End of CoexMetrics section. } +#if OTBR_ENABLE_LINK_METRICS_TELEMETRY + { + auto lowPowerMetrics = telemetryData.mutable_low_power_metrics(); + // Begin of Link Metrics section. + for (const otNeighborInfo &neighborInfo : neighborTable) + { + otError query_error; + otLinkMetricsValues values; + + query_error = otLinkMetricsManagerGetMetricsValueByExtAddr(mInstance, &neighborInfo.mExtAddress, &values); + // Some neighbors don't support Link Metrics Subject feature. So it's expected that some other errors + // are returned. + if (query_error == OT_ERROR_NONE) + { + auto linkMetricsStats = lowPowerMetrics->add_link_metrics_entries(); + linkMetricsStats->set_link_margin(values.mLinkMarginValue); + linkMetricsStats->set_rssi(values.mRssiValue); + } + } + } +#endif // OTBR_ENABLE_LINK_METRICS_TELEMETRY + exit: return error; } diff --git a/tests/dbus/test_dbus_client.cpp b/tests/dbus/test_dbus_client.cpp index bca057b1e23..7b493f1cc4f 100644 --- a/tests/dbus/test_dbus_client.cpp +++ b/tests/dbus/test_dbus_client.cpp @@ -288,6 +288,9 @@ void CheckTelemetryData(ThreadApiDBus *aApi) #endif TEST_ASSERT(telemetryData.wpan_rcp().rcp_interface_statistics().transferred_frames_count() > 0); TEST_ASSERT(telemetryData.coex_metrics().count_tx_request() > 0); +#if OTBR_ENABLE_LINK_METRICS_TELEMETRY + TEST_ASSERT(telemetryData.low_power_metrics().link_metrics_entries_size() >= 0); +#endif } #endif diff --git a/third_party/openthread/CMakeLists.txt b/third_party/openthread/CMakeLists.txt index 03ad863352d..f07625da96b 100644 --- a/third_party/openthread/CMakeLists.txt +++ b/third_party/openthread/CMakeLists.txt @@ -51,6 +51,8 @@ set(OT_ECDSA ON CACHE STRING "enable ECDSA" FORCE) set(OT_FIREWALL ON CACHE STRING "enable firewall feature") set(OT_HISTORY_TRACKER ON CACHE STRING "enable history tracker" FORCE) set(OT_JOINER ON CACHE STRING "enable joiner" FORCE) +set(OT_LINK_METRICS_INITIATOR ${OTBR_LINK_METRICS_TELEMETRY} CACHE STRING "enable link metrics initiator" FORCE) +set(OT_LINK_METRICS_MANAGER ${OTBR_LINK_METRICS_TELEMETRY} CACHE STRING "enable link metrics manager" FORCE) set(OT_LOG_LEVEL_DYNAMIC ON CACHE STRING "enable dynamic log level control" FORCE) set(OT_MAC_FILTER ON CACHE STRING "enable MAC filter" FORCE) set(OT_NAT64_BORDER_ROUTING ${OTBR_NAT64} CACHE STRING "enable NAT64 in border routing manager" FORCE)