/* * Copyright (c) 2023, 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. */ #include "android/otdaemon_telemetry.hpp" #include #include #include #include #include #include #include #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY #include #endif #if OTBR_ENABLE_SRP_ADVERTISING_PROXY #include #endif #include "statslog_threadnetwork.h" #include "common/code_utils.hpp" #include "mdns/mdns.hpp" #include "proto/threadnetwork_atoms.pb.h" namespace otbr { namespace Android { using android::os::statsd::threadnetwork::ThreadnetworkDeviceInfoReported; using android::os::statsd::threadnetwork::ThreadnetworkTelemetryDataReported; using android::os::statsd::threadnetwork::ThreadnetworkTopoEntryRepeated; using TelemetryData = android::os::statsd::threadnetwork::ThreadnetworkTelemetryDataReported; static uint32_t TelemetryNodeTypeFromRoleAndLinkMode(const otDeviceRole &aRole, const otLinkModeConfig &aLinkModeCfg) { uint32_t nodeType; switch (aRole) { case OT_DEVICE_ROLE_DISABLED: nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_DISABLED; break; case OT_DEVICE_ROLE_DETACHED: nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_DETACHED; break; case OT_DEVICE_ROLE_ROUTER: nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_ROUTER; break; case OT_DEVICE_ROLE_LEADER: nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_LEADER; break; case OT_DEVICE_ROLE_CHILD: if (!aLinkModeCfg.mRxOnWhenIdle) { nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_SLEEPY_END; } else if (!aLinkModeCfg.mDeviceType) { // If it's not an FTD, return as minimal end device. nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_MINIMAL_END; } else { nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_END; } break; default: nodeType = ThreadnetworkTelemetryDataReported::NODE_TYPE_UNSPECIFIED; } return nodeType; } #if OTBR_ENABLE_SRP_ADVERTISING_PROXY ThreadnetworkTelemetryDataReported::SrpServerState SrpServerStateFromOtSrpServerState(otSrpServerState aSrpServerState) { ThreadnetworkTelemetryDataReported::SrpServerState srpServerState; switch (aSrpServerState) { case OT_SRP_SERVER_STATE_DISABLED: srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_DISABLED; break; case OT_SRP_SERVER_STATE_RUNNING: srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_RUNNING; break; case OT_SRP_SERVER_STATE_STOPPED: srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_STOPPED; break; default: srpServerState = ThreadnetworkTelemetryDataReported::SRP_SERVER_STATE_UNSPECIFIED; } return srpServerState; } ThreadnetworkTelemetryDataReported::SrpServerAddressMode SrpServerAddressModeFromOtSrpServerAddressMode( otSrpServerAddressMode aSrpServerAddressMode) { ThreadnetworkTelemetryDataReported::SrpServerAddressMode srpServerAddressMode; switch (aSrpServerAddressMode) { case OT_SRP_SERVER_ADDRESS_MODE_ANYCAST: srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_STATE_ANYCAST; break; case OT_SRP_SERVER_ADDRESS_MODE_UNICAST: srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_UNICAST; break; default: srpServerAddressMode = ThreadnetworkTelemetryDataReported::SRP_SERVER_ADDRESS_MODE_UNSPECIFIED; } return srpServerAddressMode; } #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY void CopyMdnsResponseCounters(const MdnsResponseCounters &from, ThreadnetworkTelemetryDataReported::MdnsResponseCounters *to) { to->set_success_count(from.mSuccess); to->set_not_found_count(from.mNotFound); to->set_invalid_args_count(from.mInvalidArgs); to->set_duplicated_count(from.mDuplicated); to->set_not_implemented_count(from.mNotImplemented); to->set_unknown_error_count(from.mUnknownError); to->set_aborted_count(from.mAborted); to->set_invalid_state_count(from.mInvalidState); } TelemetryData::Nat64State Nat64StateFromOtNat64State(otNat64State aNat64State) { TelemetryData::Nat64State nat64State; switch (aNat64State) { case OT_NAT64_STATE_DISABLED: nat64State = TelemetryData::NAT64_STATE_DISABLED; break; case OT_NAT64_STATE_NOT_RUNNING: nat64State = TelemetryData::NAT64_STATE_NOT_RUNNING; break; case OT_NAT64_STATE_IDLE: nat64State = TelemetryData::NAT64_STATE_IDLE; break; case OT_NAT64_STATE_ACTIVE: nat64State = TelemetryData::NAT64_STATE_ACTIVE; break; default: nat64State = TelemetryData::NAT64_STATE_UNSPECIFIED; } return nat64State; } void RetrieveNat64State(otInstance *aInstance, TelemetryData::WpanBorderRouter *aWpanBorderRouter) { auto nat64State = aWpanBorderRouter->mutable_nat64_state(); nat64State->set_prefix_manager_state(Nat64StateFromOtNat64State(otNat64GetPrefixManagerState(aInstance))); nat64State->set_translator_state(Nat64StateFromOtNat64State(otNat64GetTranslatorState(aInstance))); } void RetrieveNat64Counters(otInstance *aInstance, TelemetryData::BorderRoutingCounters *aBorderRoutingCounters) { { auto nat64IcmpCounters = aBorderRoutingCounters->mutable_nat64_protocol_counters()->mutable_icmp(); auto nat64UdpCounters = aBorderRoutingCounters->mutable_nat64_protocol_counters()->mutable_udp(); auto nat64TcpCounters = aBorderRoutingCounters->mutable_nat64_protocol_counters()->mutable_tcp(); otNat64ProtocolCounters otCounters; otNat64GetCounters(aInstance, &otCounters); nat64IcmpCounters->set_ipv4_to_ipv6_packets(otCounters.mIcmp.m4To6Packets); nat64IcmpCounters->set_ipv4_to_ipv6_bytes(otCounters.mIcmp.m4To6Bytes); nat64IcmpCounters->set_ipv6_to_ipv4_packets(otCounters.mIcmp.m6To4Packets); nat64IcmpCounters->set_ipv6_to_ipv4_bytes(otCounters.mIcmp.m6To4Bytes); nat64UdpCounters->set_ipv4_to_ipv6_packets(otCounters.mUdp.m4To6Packets); nat64UdpCounters->set_ipv4_to_ipv6_bytes(otCounters.mUdp.m4To6Bytes); nat64UdpCounters->set_ipv6_to_ipv4_packets(otCounters.mUdp.m6To4Packets); nat64UdpCounters->set_ipv6_to_ipv4_bytes(otCounters.mUdp.m6To4Bytes); nat64TcpCounters->set_ipv4_to_ipv6_packets(otCounters.mTcp.m4To6Packets); nat64TcpCounters->set_ipv4_to_ipv6_bytes(otCounters.mTcp.m4To6Bytes); nat64TcpCounters->set_ipv6_to_ipv4_packets(otCounters.mTcp.m6To4Packets); nat64TcpCounters->set_ipv6_to_ipv4_bytes(otCounters.mTcp.m6To4Bytes); } { auto errorCounters = aBorderRoutingCounters->mutable_nat64_error_counters(); otNat64ErrorCounters otCounters; otNat64GetErrorCounters(aInstance, &otCounters); errorCounters->mutable_unknown()->set_ipv4_to_ipv6_packets(otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNKNOWN]); errorCounters->mutable_unknown()->set_ipv6_to_ipv4_packets(otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNKNOWN]); errorCounters->mutable_illegal_packet()->set_ipv4_to_ipv6_packets( otCounters.mCount4To6[OT_NAT64_DROP_REASON_ILLEGAL_PACKET]); errorCounters->mutable_illegal_packet()->set_ipv6_to_ipv4_packets( otCounters.mCount6To4[OT_NAT64_DROP_REASON_ILLEGAL_PACKET]); errorCounters->mutable_unsupported_protocol()->set_ipv4_to_ipv6_packets( otCounters.mCount4To6[OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO]); errorCounters->mutable_unsupported_protocol()->set_ipv6_to_ipv4_packets( otCounters.mCount6To4[OT_NAT64_DROP_REASON_UNSUPPORTED_PROTO]); errorCounters->mutable_no_mapping()->set_ipv4_to_ipv6_packets( otCounters.mCount4To6[OT_NAT64_DROP_REASON_NO_MAPPING]); errorCounters->mutable_no_mapping()->set_ipv6_to_ipv4_packets( otCounters.mCount6To4[OT_NAT64_DROP_REASON_NO_MAPPING]); } } void RetrieveBorderAgentInfo(otInstance *aInstance, TelemetryData::BorderAgentInfo *aBorderAgentInfo) { auto baCounters = aBorderAgentInfo->mutable_border_agent_counters(); auto otBorderAgentCounters = *otBorderAgentGetCounters(aInstance); baCounters->set_epskc_activations(otBorderAgentCounters.mEpskcActivations); baCounters->set_epskc_deactivation_clears(otBorderAgentCounters.mEpskcDeactivationClears); baCounters->set_epskc_deactivation_timeouts(otBorderAgentCounters.mEpskcDeactivationTimeouts); baCounters->set_epskc_deactivation_max_attempts(otBorderAgentCounters.mEpskcDeactivationMaxAttempts); baCounters->set_epskc_deactivation_disconnects(otBorderAgentCounters.mEpskcDeactivationDisconnects); baCounters->set_epskc_invalid_ba_state_errors(otBorderAgentCounters.mEpskcInvalidBaStateErrors); baCounters->set_epskc_invalid_args_errors(otBorderAgentCounters.mEpskcInvalidArgsErrors); baCounters->set_epskc_start_secure_session_errors(otBorderAgentCounters.mEpskcStartSecureSessionErrors); baCounters->set_epskc_secure_session_successes(otBorderAgentCounters.mEpskcSecureSessionSuccesses); baCounters->set_epskc_secure_session_failures(otBorderAgentCounters.mEpskcSecureSessionFailures); baCounters->set_epskc_commissioner_petitions(otBorderAgentCounters.mEpskcCommissionerPetitions); baCounters->set_pskc_secure_session_successes(otBorderAgentCounters.mPskcSecureSessionSuccesses); baCounters->set_pskc_secure_session_failures(otBorderAgentCounters.mPskcSecureSessionFailures); baCounters->set_pskc_commissioner_petitions(otBorderAgentCounters.mPskcCommissionerPetitions); baCounters->set_mgmt_active_get_reqs(otBorderAgentCounters.mMgmtActiveGets); baCounters->set_mgmt_pending_get_reqs(otBorderAgentCounters.mMgmtPendingGets); } void RetrieveTrelInfo(otInstance *aInstance, TelemetryData::TrelInfo *aTrelInfo) { auto otTrelCounters = otTrelGetCounters(aInstance); auto trelCounters = aTrelInfo->mutable_counters(); aTrelInfo->set_is_trel_enabled(otTrelIsEnabled(aInstance)); aTrelInfo->set_num_trel_peers(otTrelGetNumberOfPeers(aInstance)); trelCounters->set_trel_tx_packets(otTrelCounters->mTxPackets); trelCounters->set_trel_tx_bytes(otTrelCounters->mTxBytes); trelCounters->set_trel_tx_packets_failed(otTrelCounters->mTxFailure); trelCounters->set_trel_rx_packets(otTrelCounters->mRxPackets); trelCounters->set_trel_rx_bytes(otTrelCounters->mRxBytes); } otError RetrieveTelemetryAtom(otInstance *otInstance, Mdns::Publisher *aPublisher, ThreadnetworkTelemetryDataReported &telemetryDataReported, ThreadnetworkTopoEntryRepeated &topoEntryRepeated, ThreadnetworkDeviceInfoReported &deviceInfoReported) { otError error = OT_ERROR_NONE; std::vector neighborTable; // Begin of ThreadnetworkDeviceInfoReported section. deviceInfoReported.set_thread_version(otThreadGetVersion()); deviceInfoReported.set_ot_rcp_version(otGetRadioVersionString(otInstance)); // TODO: populate ot_host_version, thread_daemon_version. // End of ThreadnetworkDeviceInfoReported section. // Begin of WpanStats section. auto wpanStats = telemetryDataReported.mutable_wpan_stats(); { otDeviceRole role = otThreadGetDeviceRole(otInstance); otLinkModeConfig otCfg = otThreadGetLinkMode(otInstance); wpanStats->set_node_type(TelemetryNodeTypeFromRoleAndLinkMode(role, otCfg)); } // Disable telemetry retrieval when Thread stack is disabled. DeviceInfo section above is // always uploaded to understand the device count. if (wpanStats->node_type() == ThreadnetworkTelemetryDataReported::NODE_TYPE_DISABLED) { otbrLogDebug("Skip telemetry retrieval since Thread stack is disabled."); // Return error that only partial telemetries are populated. // TODO: refine the error code name to mean: partial data are populated. return OT_ERROR_FAILED; } wpanStats->set_channel(otLinkGetChannel(otInstance)); { uint16_t ccaFailureRate = otLinkGetCcaFailureRate(otInstance); wpanStats->set_mac_cca_fail_rate(static_cast(ccaFailureRate) / 0xffff); } { int8_t radioTxPower; if (otPlatRadioGetTransmitPower(otInstance, &radioTxPower) == OT_ERROR_NONE) { wpanStats->set_radio_tx_power(radioTxPower); } else { error = OT_ERROR_FAILED; } } { const otMacCounters *linkCounters = otLinkGetCounters(otInstance); wpanStats->set_phy_rx(linkCounters->mRxTotal); wpanStats->set_phy_tx(linkCounters->mTxTotal); wpanStats->set_mac_unicast_rx(linkCounters->mRxUnicast); wpanStats->set_mac_unicast_tx(linkCounters->mTxUnicast); wpanStats->set_mac_broadcast_rx(linkCounters->mRxBroadcast); wpanStats->set_mac_broadcast_tx(linkCounters->mTxBroadcast); wpanStats->set_mac_tx_ack_req(linkCounters->mTxAckRequested); wpanStats->set_mac_tx_no_ack_req(linkCounters->mTxNoAckRequested); wpanStats->set_mac_tx_acked(linkCounters->mTxAcked); wpanStats->set_mac_tx_data(linkCounters->mTxData); wpanStats->set_mac_tx_data_poll(linkCounters->mTxDataPoll); wpanStats->set_mac_tx_beacon(linkCounters->mTxBeacon); wpanStats->set_mac_tx_beacon_req(linkCounters->mTxBeaconRequest); wpanStats->set_mac_tx_other_pkt(linkCounters->mTxOther); wpanStats->set_mac_tx_retry(linkCounters->mTxRetry); wpanStats->set_mac_rx_data(linkCounters->mRxData); wpanStats->set_mac_rx_data_poll(linkCounters->mRxDataPoll); wpanStats->set_mac_rx_beacon(linkCounters->mRxBeacon); wpanStats->set_mac_rx_beacon_req(linkCounters->mRxBeaconRequest); wpanStats->set_mac_rx_other_pkt(linkCounters->mRxOther); wpanStats->set_mac_rx_filter_whitelist(linkCounters->mRxAddressFiltered); wpanStats->set_mac_rx_filter_dest_addr(linkCounters->mRxDestAddrFiltered); wpanStats->set_mac_tx_fail_cca(linkCounters->mTxErrCca); wpanStats->set_mac_rx_fail_decrypt(linkCounters->mRxErrSec); wpanStats->set_mac_rx_fail_no_frame(linkCounters->mRxErrNoFrame); wpanStats->set_mac_rx_fail_unknown_neighbor(linkCounters->mRxErrUnknownNeighbor); wpanStats->set_mac_rx_fail_invalid_src_addr(linkCounters->mRxErrInvalidSrcAddr); wpanStats->set_mac_rx_fail_fcs(linkCounters->mRxErrFcs); wpanStats->set_mac_rx_fail_other(linkCounters->mRxErrOther); } { const otIpCounters *ipCounters = otThreadGetIp6Counters(otInstance); wpanStats->set_ip_tx_success(ipCounters->mTxSuccess); wpanStats->set_ip_rx_success(ipCounters->mRxSuccess); wpanStats->set_ip_tx_failure(ipCounters->mTxFailure); wpanStats->set_ip_rx_failure(ipCounters->mRxFailure); } // End of WpanStats section. { // Begin of WpanTopoFull section. auto wpanTopoFull = telemetryDataReported.mutable_wpan_topo_full(); uint16_t rloc16 = otThreadGetRloc16(otInstance); wpanTopoFull->set_rloc16(rloc16); { otRouterInfo info; if (otThreadGetRouterInfo(otInstance, rloc16, &info) == OT_ERROR_NONE) { wpanTopoFull->set_router_id(info.mRouterId); } else { error = OT_ERROR_FAILED; } } { otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; otNeighborInfo neighborInfo; while (otThreadGetNextNeighborInfo(otInstance, &iter, &neighborInfo) == OT_ERROR_NONE) { neighborTable.push_back(neighborInfo); } } wpanTopoFull->set_neighbor_table_size(neighborTable.size()); uint16_t childIndex = 0; otChildInfo childInfo; std::vector childTable; while (otThreadGetChildInfoByIndex(otInstance, childIndex, &childInfo) == OT_ERROR_NONE) { childTable.push_back(childInfo); childIndex++; } wpanTopoFull->set_child_table_size(childTable.size()); { struct otLeaderData leaderData; if (otThreadGetLeaderData(otInstance, &leaderData) == OT_ERROR_NONE) { wpanTopoFull->set_leader_router_id(leaderData.mLeaderRouterId); wpanTopoFull->set_leader_weight(leaderData.mWeighting); // Do not log network_data_version. } else { error = OT_ERROR_FAILED; } } uint8_t weight = otThreadGetLocalLeaderWeight(otInstance); wpanTopoFull->set_leader_local_weight(weight); int8_t rssi = otPlatRadioGetRssi(otInstance); wpanTopoFull->set_instant_rssi(rssi); const otExtendedPanId *extPanId = otThreadGetExtendedPanId(otInstance); uint64_t extPanIdVal; extPanIdVal = ConvertOpenThreadUint64(extPanId->m8); wpanTopoFull->set_has_extended_pan_id(extPanIdVal != 0); // Note: Used leader_router_id instead of leader_rloc16. // Note: Network level info (e.g., extended_pan_id, partition_id, is_active_br) is not logged. // TODO: populate is_active_srp_server, sum_on_link_prefix_changes, preferred_router_id // if needed. // End of WpanTopoFull section. // Begin of TopoEntry section. std::map childMap; for (const otChildInfo &childInfo : childTable) { auto pair = childMap.insert({childInfo.mRloc16, &childInfo}); if (!pair.second) { // This shouldn't happen, so log an error. It doesn't matter which // duplicate is kept. otbrLogErr("Children with duplicate RLOC16 found: 0x%04x", static_cast(childInfo.mRloc16)); } } for (const otNeighborInfo &neighborInfo : neighborTable) { auto topoEntry = topoEntryRepeated.mutable_topo_entry_repeated()->add_topo_entries(); // 0~15: uint16_t rloc_16 // 16~31: uint16_t version Thread version of the neighbor uint32_t comboTelemetry1 = 0; comboTelemetry1 |= (((uint32_t)neighborInfo.mRloc16) & 0x0000FFFF); comboTelemetry1 |= ((((uint32_t)neighborInfo.mVersion) & 0x0000FFFF) << 16); topoEntry->set_combo_telemetry1(comboTelemetry1); topoEntry->set_age_sec(neighborInfo.mAge); // 0~7: uint8_t link_quality_in // 8~15: int8_t average_rssi // 16~23: int8_t last_rssi // 24~31: uint8_t network_data_version uint32_t comboTelemetry2 = 0; comboTelemetry2 |= (((uint32_t)neighborInfo.mLinkQualityIn) & 0x000000FF); comboTelemetry2 |= ((((uint32_t)neighborInfo.mAverageRssi) & 0x000000FF) << 8); comboTelemetry2 |= ((((uint32_t)neighborInfo.mLastRssi) & 0x000000FF) << 16); // network_data_version is populated in the next section. topoEntry->set_combo_telemetry2(comboTelemetry2); // Each bit on the flag represents a bool flag // 0: rx_on_when_idle // 1: full_function // 2: secure_data_request // 3: full_network_data // 4: is_child uint32_t topoEntryFlags = 0; topoEntryFlags |= (neighborInfo.mRxOnWhenIdle ? 1 : 0); topoEntryFlags |= ((neighborInfo.mFullThreadDevice ? 1 : 0) << 1); topoEntryFlags |= ((/* secure_data_request */ true ? 1 : 0) << 2); topoEntryFlags |= ((neighborInfo.mFullNetworkData ? 1 : 0) << 3); topoEntry->set_topo_entry_flags(topoEntryFlags); topoEntry->set_link_frame_counter(neighborInfo.mLinkFrameCounter); topoEntry->set_mle_frame_counter(neighborInfo.mMleFrameCounter); // 0~15: uint16_t mac_frame_error_rate. Frame error rate (0xffff->100%). Requires error tracking feature. // 16~31: uint16_t ip_message_error_rate. (IPv6) msg error rate (0xffff->100%). Requires error tracking // feature. uint32_t comboTelemetry3 = 0; comboTelemetry3 |= ((uint32_t)(neighborInfo.mFrameErrorRate) & 0x0000FFFF); comboTelemetry3 |= ((((uint32_t)neighborInfo.mMessageErrorRate) & 0x0000FFFF) << 16); topoEntry->set_combo_telemetry3(comboTelemetry3); if (!neighborInfo.mIsChild) { continue; } auto it = childMap.find(neighborInfo.mRloc16); if (it == childMap.end()) { otbrLogErr("Neighbor 0x%04x not found in child table", static_cast(neighborInfo.mRloc16)); continue; } const otChildInfo *childInfo = it->second; comboTelemetry2 |= ((((uint32_t)childInfo->mNetworkDataVersion) & 0x000000FF) << 24); topoEntry->set_combo_telemetry2(comboTelemetry2); topoEntryFlags |= ((/* is_child */ true ? 1 : 0) << 4); topoEntry->set_topo_entry_flags(topoEntryFlags); topoEntry->set_timeout_sec(childInfo->mTimeout); } // End of TopoEntry section. } { // Begin of WpanBorderRouter section. auto wpanBorderRouter = telemetryDataReported.mutable_wpan_border_router(); // Begin of BorderRoutingCounters section. { auto borderRoutingCouters = wpanBorderRouter->mutable_border_routing_counters(); const otBorderRoutingCounters *otBorderRoutingCounters = otIp6GetBorderRoutingCounters(otInstance); borderRoutingCouters->mutable_inbound_unicast()->set_packet_count( otBorderRoutingCounters->mInboundUnicast.mPackets); borderRoutingCouters->mutable_inbound_unicast()->set_byte_count( otBorderRoutingCounters->mInboundUnicast.mBytes); borderRoutingCouters->mutable_inbound_multicast()->set_packet_count( otBorderRoutingCounters->mInboundMulticast.mPackets); borderRoutingCouters->mutable_inbound_multicast()->set_byte_count( otBorderRoutingCounters->mInboundMulticast.mBytes); borderRoutingCouters->mutable_outbound_unicast()->set_packet_count( otBorderRoutingCounters->mOutboundUnicast.mPackets); borderRoutingCouters->mutable_outbound_unicast()->set_byte_count( otBorderRoutingCounters->mOutboundUnicast.mBytes); borderRoutingCouters->mutable_outbound_multicast()->set_packet_count( otBorderRoutingCounters->mOutboundMulticast.mPackets); borderRoutingCouters->mutable_outbound_multicast()->set_byte_count( otBorderRoutingCounters->mOutboundMulticast.mBytes); borderRoutingCouters->set_ra_rx(otBorderRoutingCounters->mRaRx); borderRoutingCouters->set_ra_tx_success(otBorderRoutingCounters->mRaTxSuccess); borderRoutingCouters->set_ra_tx_failure(otBorderRoutingCounters->mRaTxFailure); borderRoutingCouters->set_rs_rx(otBorderRoutingCounters->mRsRx); borderRoutingCouters->set_rs_tx_success(otBorderRoutingCounters->mRsTxSuccess); borderRoutingCouters->set_rs_tx_failure(otBorderRoutingCounters->mRsTxFailure); RetrieveNat64Counters(otInstance, borderRoutingCouters); } // End of BorderRoutingCounters section. #if OTBR_ENABLE_SRP_ADVERTISING_PROXY // Begin of SrpServerInfo section. { auto srpServer = wpanBorderRouter->mutable_srp_server(); otSrpServerLeaseInfo leaseInfo; const otSrpServerHost *host = nullptr; const otSrpServerResponseCounters *responseCounters = otSrpServerGetResponseCounters(otInstance); srpServer->set_state(SrpServerStateFromOtSrpServerState(otSrpServerGetState(otInstance))); srpServer->set_port(otSrpServerGetPort(otInstance)); srpServer->set_address_mode( SrpServerAddressModeFromOtSrpServerAddressMode(otSrpServerGetAddressMode(otInstance))); auto srpServerHosts = srpServer->mutable_hosts(); auto srpServerServices = srpServer->mutable_services(); auto srpServerResponseCounters = srpServer->mutable_response_counters(); while ((host = otSrpServerGetNextHost(otInstance, host))) { const otSrpServerService *service = nullptr; if (otSrpServerHostIsDeleted(host)) { srpServerHosts->set_deleted_count(srpServerHosts->deleted_count() + 1); } else { srpServerHosts->set_fresh_count(srpServerHosts->fresh_count() + 1); otSrpServerHostGetLeaseInfo(host, &leaseInfo); srpServerHosts->set_lease_time_total_ms(srpServerHosts->lease_time_total_ms() + leaseInfo.mLease); srpServerHosts->set_key_lease_time_total_ms(srpServerHosts->key_lease_time_total_ms() + leaseInfo.mKeyLease); srpServerHosts->set_remaining_lease_time_total_ms(srpServerHosts->remaining_lease_time_total_ms() + leaseInfo.mRemainingLease); srpServerHosts->set_remaining_key_lease_time_total_ms( srpServerHosts->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease); } while ((service = otSrpServerHostGetNextService(host, service))) { if (otSrpServerServiceIsDeleted(service)) { srpServerServices->set_deleted_count(srpServerServices->deleted_count() + 1); } else { srpServerServices->set_fresh_count(srpServerServices->fresh_count() + 1); otSrpServerServiceGetLeaseInfo(service, &leaseInfo); srpServerServices->set_lease_time_total_ms(srpServerServices->lease_time_total_ms() + leaseInfo.mLease); srpServerServices->set_key_lease_time_total_ms(srpServerServices->key_lease_time_total_ms() + leaseInfo.mKeyLease); srpServerServices->set_remaining_lease_time_total_ms( srpServerServices->remaining_lease_time_total_ms() + leaseInfo.mRemainingLease); srpServerServices->set_remaining_key_lease_time_total_ms( srpServerServices->remaining_key_lease_time_total_ms() + leaseInfo.mRemainingKeyLease); } } } srpServerResponseCounters->set_success_count(responseCounters->mSuccess); srpServerResponseCounters->set_server_failure_count(responseCounters->mServerFailure); srpServerResponseCounters->set_format_error_count(responseCounters->mFormatError); srpServerResponseCounters->set_name_exists_count(responseCounters->mNameExists); srpServerResponseCounters->set_refused_count(responseCounters->mRefused); srpServerResponseCounters->set_other_count(responseCounters->mOther); } // End of SrpServerInfo section. #endif // OTBR_ENABLE_SRP_ADVERTISING_PROXY #if OTBR_ENABLE_DNSSD_DISCOVERY_PROXY // Begin of DnsServerInfo section. { auto dnsServer = wpanBorderRouter->mutable_dns_server(); auto dnsServerResponseCounters = dnsServer->mutable_response_counters(); otDnssdCounters otDnssdCounters = *otDnssdGetCounters(otInstance); dnsServerResponseCounters->set_success_count(otDnssdCounters.mSuccessResponse); dnsServerResponseCounters->set_server_failure_count(otDnssdCounters.mServerFailureResponse); dnsServerResponseCounters->set_format_error_count(otDnssdCounters.mFormatErrorResponse); dnsServerResponseCounters->set_name_error_count(otDnssdCounters.mNameErrorResponse); dnsServerResponseCounters->set_not_implemented_count(otDnssdCounters.mNotImplementedResponse); dnsServerResponseCounters->set_other_count(otDnssdCounters.mOtherResponse); // The counters of queries, responses, failures handled by upstream DNS server. dnsServerResponseCounters->set_upstream_dns_queries(otDnssdCounters.mUpstreamDnsCounters.mQueries); dnsServerResponseCounters->set_upstream_dns_responses(otDnssdCounters.mUpstreamDnsCounters.mResponses); dnsServerResponseCounters->set_upstream_dns_failures(otDnssdCounters.mUpstreamDnsCounters.mFailures); dnsServer->set_resolved_by_local_srp_count(otDnssdCounters.mResolvedBySrp); dnsServer->set_upstream_dns_query_state( otDnssdUpstreamQueryIsEnabled(otInstance) ? ThreadnetworkTelemetryDataReported::UPSTREAMDNS_QUERY_STATE_ENABLED : ThreadnetworkTelemetryDataReported::UPSTREAMDNS_QUERY_STATE_DISABLED); } // End of DnsServerInfo section. #endif // OTBR_ENABLE_DNSSD_DISCOVERY_PROXY // Start of MdnsInfo section. if (aPublisher != nullptr) { auto mdns = wpanBorderRouter->mutable_mdns(); const MdnsTelemetryInfo &mdnsInfo = aPublisher->GetMdnsTelemetryInfo(); CopyMdnsResponseCounters(mdnsInfo.mHostRegistrations, mdns->mutable_host_registration_responses()); CopyMdnsResponseCounters(mdnsInfo.mServiceRegistrations, mdns->mutable_service_registration_responses()); CopyMdnsResponseCounters(mdnsInfo.mHostResolutions, mdns->mutable_host_resolution_responses()); CopyMdnsResponseCounters(mdnsInfo.mServiceResolutions, mdns->mutable_service_resolution_responses()); mdns->set_host_registration_ema_latency_ms(mdnsInfo.mHostRegistrationEmaLatency); mdns->set_service_registration_ema_latency_ms(mdnsInfo.mServiceRegistrationEmaLatency); mdns->set_host_resolution_ema_latency_ms(mdnsInfo.mHostResolutionEmaLatency); mdns->set_service_resolution_ema_latency_ms(mdnsInfo.mServiceResolutionEmaLatency); } // End of MdnsInfo section. // End of WpanBorderRouter section. // Start of WpanRcp section. { auto wpanRcp = telemetryDataReported.mutable_wpan_rcp(); const otRadioSpinelMetrics *otRadioSpinelMetrics = otSysGetRadioSpinelMetrics(); auto rcpStabilityStatistics = wpanRcp->mutable_rcp_stability_statistics(); if (otRadioSpinelMetrics != nullptr) { rcpStabilityStatistics->set_rcp_timeout_count(otRadioSpinelMetrics->mRcpTimeoutCount); rcpStabilityStatistics->set_rcp_reset_count(otRadioSpinelMetrics->mRcpUnexpectedResetCount); rcpStabilityStatistics->set_rcp_restoration_count(otRadioSpinelMetrics->mRcpRestorationCount); rcpStabilityStatistics->set_spinel_parse_error_count(otRadioSpinelMetrics->mSpinelParseErrorCount); } // TODO: provide rcp_firmware_update_count info. rcpStabilityStatistics->set_thread_stack_uptime(otInstanceGetUptime(otInstance)); const otRcpInterfaceMetrics *otRcpInterfaceMetrics = otSysGetRcpInterfaceMetrics(); if (otRcpInterfaceMetrics != nullptr) { auto rcpInterfaceStatistics = wpanRcp->mutable_rcp_interface_statistics(); rcpInterfaceStatistics->set_rcp_interface_type(otRcpInterfaceMetrics->mRcpInterfaceType); rcpInterfaceStatistics->set_transferred_frames_count(otRcpInterfaceMetrics->mTransferredFrameCount); rcpInterfaceStatistics->set_transferred_valid_frames_count( otRcpInterfaceMetrics->mTransferredValidFrameCount); rcpInterfaceStatistics->set_transferred_garbage_frames_count( otRcpInterfaceMetrics->mTransferredGarbageFrameCount); rcpInterfaceStatistics->set_rx_frames_count(otRcpInterfaceMetrics->mRxFrameCount); rcpInterfaceStatistics->set_rx_bytes_count(otRcpInterfaceMetrics->mRxFrameByteCount); rcpInterfaceStatistics->set_tx_frames_count(otRcpInterfaceMetrics->mTxFrameCount); rcpInterfaceStatistics->set_tx_bytes_count(otRcpInterfaceMetrics->mTxFrameByteCount); } } // End of WpanRcp section. // Start of CoexMetrics section. { auto coexMetrics = telemetryDataReported.mutable_coex_metrics(); otRadioCoexMetrics otRadioCoexMetrics; if (otPlatRadioGetCoexMetrics(otInstance, &otRadioCoexMetrics) == OT_ERROR_NONE) { coexMetrics->set_count_tx_request(otRadioCoexMetrics.mNumTxRequest); coexMetrics->set_count_tx_grant_immediate(otRadioCoexMetrics.mNumTxGrantImmediate); coexMetrics->set_count_tx_grant_wait(otRadioCoexMetrics.mNumTxGrantWait); coexMetrics->set_count_tx_grant_wait_activated(otRadioCoexMetrics.mNumTxGrantWaitActivated); coexMetrics->set_count_tx_grant_wait_timeout(otRadioCoexMetrics.mNumTxGrantWaitTimeout); coexMetrics->set_count_tx_grant_deactivated_during_request( otRadioCoexMetrics.mNumTxGrantDeactivatedDuringRequest); coexMetrics->set_tx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgTxRequestToGrantTime); coexMetrics->set_count_rx_request(otRadioCoexMetrics.mNumRxRequest); coexMetrics->set_count_rx_grant_immediate(otRadioCoexMetrics.mNumRxGrantImmediate); coexMetrics->set_count_rx_grant_wait(otRadioCoexMetrics.mNumRxGrantWait); coexMetrics->set_count_rx_grant_wait_activated(otRadioCoexMetrics.mNumRxGrantWaitActivated); coexMetrics->set_count_rx_grant_wait_timeout(otRadioCoexMetrics.mNumRxGrantWaitTimeout); coexMetrics->set_count_rx_grant_deactivated_during_request( otRadioCoexMetrics.mNumRxGrantDeactivatedDuringRequest); coexMetrics->set_count_rx_grant_none(otRadioCoexMetrics.mNumRxGrantNone); coexMetrics->set_rx_average_request_to_grant_time_us(otRadioCoexMetrics.mAvgRxRequestToGrantTime); } else { error = OT_ERROR_FAILED; } } // End of CoexMetrics section. RetrieveNat64State(otInstance, wpanBorderRouter); RetrieveBorderAgentInfo(otInstance, wpanBorderRouter->mutable_border_agent_info()); RetrieveTrelInfo(otInstance, wpanBorderRouter->mutable_trel_info()); } return error; } int PushAtom(const ThreadnetworkTelemetryDataReported &telemetryDataReported) { const std::string &wpanStats = telemetryDataReported.wpan_stats().SerializeAsString(); const std::string &wpanTopoFull = telemetryDataReported.wpan_topo_full().SerializeAsString(); const std::string &wpanBorderRouter = telemetryDataReported.wpan_border_router().SerializeAsString(); const std::string &wpanRcp = telemetryDataReported.wpan_rcp().SerializeAsString(); const std::string &coexMetrics = telemetryDataReported.coex_metrics().SerializeAsString(); threadnetwork::BytesField wpanStatsBytesField{wpanStats.c_str(), wpanStats.size()}; threadnetwork::BytesField wpanTopoFullBytesField{wpanTopoFull.c_str(), wpanTopoFull.size()}; threadnetwork::BytesField wpanBorderRouterBytesField{wpanBorderRouter.c_str(), wpanBorderRouter.size()}; threadnetwork::BytesField wpanRcpBytesField{wpanRcp.c_str(), wpanRcp.size()}; threadnetwork::BytesField coexMetricsBytesField{coexMetrics.c_str(), coexMetrics.size()}; return threadnetwork::stats_write(threadnetwork::THREADNETWORK_TELEMETRY_DATA_REPORTED, wpanStatsBytesField, wpanTopoFullBytesField, wpanBorderRouterBytesField, wpanRcpBytesField, coexMetricsBytesField); } int PushAtom(const ThreadnetworkTopoEntryRepeated &topoEntryRepeated) { const std::string &topoEntryField = topoEntryRepeated.topo_entry_repeated().SerializeAsString(); threadnetwork::BytesField topoEntryFieldBytesField{topoEntryField.c_str(), topoEntryField.size()}; return threadnetwork::stats_write(threadnetwork::THREADNETWORK_TOPO_ENTRY_REPEATED, topoEntryFieldBytesField); } int PushAtom(const ThreadnetworkDeviceInfoReported &deviceInfoReported) { const std::string &otHostVersion = deviceInfoReported.ot_host_version(); const std::string &otRcpVersion = deviceInfoReported.ot_rcp_version(); const int32_t &threadVersion = deviceInfoReported.thread_version(); const std::string &threadDaemonVersion = deviceInfoReported.thread_daemon_version(); return threadnetwork::stats_write(threadnetwork::THREADNETWORK_DEVICE_INFO_REPORTED, otHostVersion.c_str(), otRcpVersion.c_str(), threadVersion, threadDaemonVersion.c_str()); } void RetrieveAndPushAtoms(otInstance *otInstance) { ThreadnetworkTelemetryDataReported telemetryDataReported; ThreadnetworkTopoEntryRepeated topoEntryRepeated; ThreadnetworkDeviceInfoReported deviceInfoReported; otbrLogInfo("Try to push threadnetwork ATOMs."); if (RetrieveTelemetryAtom(otInstance, nullptr, telemetryDataReported, topoEntryRepeated, deviceInfoReported) != OTBR_ERROR_NONE) { otbrLogWarning("Some telemetries are not populated"); } if (PushAtom(telemetryDataReported) <= 0) { otbrLogWarning("Failed to push ThreadnetworkTelemetryDataReported"); } if (PushAtom(topoEntryRepeated) <= 0) { otbrLogWarning("Failed to push ThreadnetworkTopoEntryRepeated"); } if (PushAtom(deviceInfoReported) <= 0) { otbrLogWarning("Failed to push ThreadnetworkDeviceInfoReported"); } otbrLogInfo("Pushed threadnetwork ATOMs."); } } // namespace Android } // namespace otbr