From eda07d58043749f40f00233639a1c5b68777bca5 Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Fri, 10 Sep 2021 13:39:19 -0700 Subject: [PATCH] [TE6] Read Ethernet Network Diagnostic attributes from platform at run-time (#9587) * Read ethernet network diagnostic attributes from platform at run-time * Update zap file for lighting-app * Update gen folder --- .../lighting-common/lighting-app.zap | 13 ++- examples/lighting-app/linux/main.cpp | 99 +++++++++++++++++ src/include/platform/CHIPDeviceConfig.h | 12 ++ src/include/platform/ConnectivityManager.h | 32 ++++++ .../GenericConnectivityManagerImpl_NoWiFi.h | 35 ++++++ .../GenericConnectivityManagerImpl_WiFi.h | 35 ++++++ .../Linux/ConnectivityManagerImpl.cpp | 105 +++++++++++++++++- src/platform/Linux/ConnectivityManagerImpl.h | 6 + .../zap-generated/endpoint_config.h | 16 ++- 9 files changed, 339 insertions(+), 14 deletions(-) diff --git a/examples/lighting-app/lighting-common/lighting-app.zap b/examples/lighting-app/lighting-common/lighting-app.zap index 6029fd790c5349..00b1d1c5f1cf73 100644 --- a/examples/lighting-app/lighting-common/lighting-app.zap +++ b/examples/lighting-app/lighting-common/lighting-app.zap @@ -2810,7 +2810,7 @@ "mfgCode": null, "side": "server", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "0x0000000000000000", @@ -2825,7 +2825,7 @@ "mfgCode": null, "side": "server", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "0x0000000000000000", @@ -2840,7 +2840,7 @@ "mfgCode": null, "side": "server", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "0x0000000000000000", @@ -2855,7 +2855,7 @@ "mfgCode": null, "side": "server", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "0x0000000000000000", @@ -2870,7 +2870,7 @@ "mfgCode": null, "side": "server", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "0x0000000000000000", @@ -5490,5 +5490,6 @@ "endpointVersion": 1, "deviceIdentifier": 259 } - ] + ], + "log": [] } \ No newline at end of file diff --git a/examples/lighting-app/linux/main.cpp b/examples/lighting-app/linux/main.cpp index 3bd618d0b42502..a0e88791bc0ac9 100644 --- a/examples/lighting-app/linux/main.cpp +++ b/examples/lighting-app/linux/main.cpp @@ -19,6 +19,8 @@ #include #include +#include +#include #include #include #include @@ -87,6 +89,103 @@ void emberAfOnOffClusterInitCallback(EndpointId endpoint) // TODO: implement any additional Cluster Server init actions } +EmberAfStatus HandleReadEthernetNetworkDiagnosticsAttribute(chip::AttributeId attributeId, uint8_t * buffer, uint16_t maxReadLength) +{ + EmberAfStatus ret = EMBER_ZCL_STATUS_FAILURE; + + switch (attributeId) + { + case ZCL_PACKET_RX_COUNT_ATTRIBUTE_ID: + if (maxReadLength == sizeof(uint64_t)) + { + uint64_t packetRxCount; + + if (ConnectivityMgr().GetEthPacketRxCount(packetRxCount) == CHIP_NO_ERROR) + { + memcpy(buffer, &packetRxCount, maxReadLength); + ret = EMBER_ZCL_STATUS_SUCCESS; + } + } + break; + case ZCL_PACKET_TX_COUNT_ATTRIBUTE_ID: + if (maxReadLength == sizeof(uint64_t)) + { + uint64_t packetTxCount; + + if (ConnectivityMgr().GetEthPacketTxCount(packetTxCount) == CHIP_NO_ERROR) + { + memcpy(buffer, &packetTxCount, maxReadLength); + ret = EMBER_ZCL_STATUS_SUCCESS; + } + } + break; + case ZCL_TX_ERR_COUNT_ATTRIBUTE_ID: + if (maxReadLength == sizeof(uint64_t)) + { + uint64_t txErrCount; + + if (ConnectivityMgr().GetEthTxErrCount(txErrCount) == CHIP_NO_ERROR) + { + memcpy(buffer, &txErrCount, maxReadLength); + ret = EMBER_ZCL_STATUS_SUCCESS; + } + } + break; + case ZCL_COLLISION_COUNT_ATTRIBUTE_ID: + if (maxReadLength == sizeof(uint64_t)) + { + uint64_t collisionCount; + + if (ConnectivityMgr().GetEthCollisionCount(collisionCount) == CHIP_NO_ERROR) + { + memcpy(buffer, &collisionCount, maxReadLength); + ret = EMBER_ZCL_STATUS_SUCCESS; + } + } + break; + case ZCL_ETHERNET_OVERRUN_COUNT_ATTRIBUTE_ID: + if (maxReadLength == sizeof(uint64_t)) + { + uint64_t overrunCount; + + if (ConnectivityMgr().GetEthOverrunCount(overrunCount) == CHIP_NO_ERROR) + { + memcpy(buffer, &overrunCount, maxReadLength); + ret = EMBER_ZCL_STATUS_SUCCESS; + } + } + break; + default: + ChipLogProgress(Zcl, "Unhandled attribute ID: %d", attributeId); + break; + } + + return ret; +} + +EmberAfStatus emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, + EmberAfAttributeMetadata * attributeMetadata, uint16_t manufacturerCode, + uint8_t * buffer, uint16_t maxReadLength, int32_t index) +{ + EmberAfStatus ret = EMBER_ZCL_STATUS_FAILURE; + + ChipLogProgress(Zcl, + "emberAfExternalAttributeReadCallback - Cluster ID: '0x%04x', EndPoint ID: '0x%02x', Attribute ID: '0x%04x'", + clusterId, endpoint, attributeMetadata->attributeId); + + switch (clusterId) + { + case ZCL_ETHERNET_NETWORK_DIAGNOSTICS_CLUSTER_ID: + ret = HandleReadEthernetNetworkDiagnosticsAttribute(attributeMetadata->attributeId, buffer, maxReadLength); + break; + default: + ChipLogError(Zcl, "Unhandled cluster ID: %d", clusterId); + break; + } + + return ret; +} + int main(int argc, char * argv[]) { if (ChipLinuxAppInit(argc, argv) != 0) diff --git a/src/include/platform/CHIPDeviceConfig.h b/src/include/platform/CHIPDeviceConfig.h index f0a80ab3c2a161..a0dec8aa5c0a42 100644 --- a/src/include/platform/CHIPDeviceConfig.h +++ b/src/include/platform/CHIPDeviceConfig.h @@ -826,6 +826,18 @@ #define CHIP_DEVICE_CONFIG_DEFAULT_TELEMETRY_INTERVAL_MS 90000 #endif +/** + * @def CHIP_DEVICE_CONFIG_ETHERNET_IF_NAME + * + * @brief + * Default ethernet network interface name used to centralize all metrics that are + * relevant to a potential Ethernet connection to a Node. + * + */ +#ifndef CHIP_DEVICE_CONFIG_ETHERNET_IF_NAME +#define CHIP_DEVICE_CONFIG_ETHERNET_IF_NAME "enp0s25" +#endif + // -------------------- Event Logging Configuration -------------------- /** diff --git a/src/include/platform/ConnectivityManager.h b/src/include/platform/ConnectivityManager.h index 27c72643bc82e3..042940b993d01d 100644 --- a/src/include/platform/ConnectivityManager.h +++ b/src/include/platform/ConnectivityManager.h @@ -170,6 +170,13 @@ class ConnectivityManager // Service connectivity methods bool HaveServiceConnectivity(); + // Ethernet network diagnostics methods + CHIP_ERROR GetEthPacketRxCount(uint64_t & packetRxCount); + CHIP_ERROR GetEthPacketTxCount(uint64_t & packetTxCount); + CHIP_ERROR GetEthTxErrCount(uint64_t & txErrCount); + CHIP_ERROR GetEthCollisionCount(uint64_t & collisionCount); + CHIP_ERROR GetEthOverrunCount(uint64_t & overrunCount); + // CHIPoBLE service methods Ble::BleLayer * GetBleLayer(); CHIPoBLEServiceMode GetCHIPoBLEServiceMode(); @@ -381,6 +388,31 @@ inline bool ConnectivityManager::HaveServiceConnectivity() return static_cast(this)->_HaveServiceConnectivity(); } +inline CHIP_ERROR ConnectivityManager::GetEthPacketRxCount(uint64_t & packetRxCount) +{ + return static_cast(this)->_GetEthPacketRxCount(packetRxCount); +} + +inline CHIP_ERROR ConnectivityManager::GetEthPacketTxCount(uint64_t & packetTxCount) +{ + return static_cast(this)->_GetEthPacketTxCount(packetTxCount); +} + +inline CHIP_ERROR ConnectivityManager::GetEthTxErrCount(uint64_t & txErrCount) +{ + return static_cast(this)->_GetEthTxErrCount(txErrCount); +} + +inline CHIP_ERROR ConnectivityManager::GetEthCollisionCount(uint64_t & collisionCount) +{ + return static_cast(this)->_GetEthCollisionCount(collisionCount); +} + +inline CHIP_ERROR ConnectivityManager::GetEthOverrunCount(uint64_t & overrunCount) +{ + return static_cast(this)->_GetEthOverrunCount(overrunCount); +} + inline ConnectivityManager::ThreadMode ConnectivityManager::GetThreadMode() { return static_cast(this)->_GetThreadMode(); diff --git a/src/include/platform/internal/GenericConnectivityManagerImpl_NoWiFi.h b/src/include/platform/internal/GenericConnectivityManagerImpl_NoWiFi.h index af744bbf4da9fd..33b5e1405d908d 100644 --- a/src/include/platform/internal/GenericConnectivityManagerImpl_NoWiFi.h +++ b/src/include/platform/internal/GenericConnectivityManagerImpl_NoWiFi.h @@ -73,6 +73,11 @@ class GenericConnectivityManagerImpl_NoWiFi uint32_t _GetWiFiAPIdleTimeoutMS(void); void _SetWiFiAPIdleTimeoutMS(uint32_t val); CHIP_ERROR _GetAndLogWifiStatsCounters(void); + CHIP_ERROR _GetEthPacketRxCount(uint64_t & packetRxCount); + CHIP_ERROR _GetEthPacketTxCount(uint64_t & packetTxCount); + CHIP_ERROR _GetEthTxErrCount(uint64_t & txErrCount); + CHIP_ERROR _GetEthCollisionCount(uint64_t & collisionCount); + CHIP_ERROR _GetEthOverrunCount(uint64_t & overrunCount); bool _CanStartWiFiScan(); void _OnWiFiScanDone(); void _OnWiFiStationProvisionChange(); @@ -235,6 +240,36 @@ inline const char * GenericConnectivityManagerImpl_NoWiFi::_WiFiAPSta return NULL; } +template +inline CHIP_ERROR GenericConnectivityManagerImpl_NoWiFi::_GetEthPacketRxCount(uint64_t & packetRxCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_NoWiFi::_GetEthPacketTxCount(uint64_t & packetTxCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_NoWiFi::_GetEthTxErrCount(uint64_t & txErrCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_NoWiFi::_GetEthCollisionCount(uint64_t & collisionCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_NoWiFi::_GetEthOverrunCount(uint64_t & overrunCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/include/platform/internal/GenericConnectivityManagerImpl_WiFi.h b/src/include/platform/internal/GenericConnectivityManagerImpl_WiFi.h index 9fe2fd66437050..36431caa1b41e5 100644 --- a/src/include/platform/internal/GenericConnectivityManagerImpl_WiFi.h +++ b/src/include/platform/internal/GenericConnectivityManagerImpl_WiFi.h @@ -73,6 +73,11 @@ class GenericConnectivityManagerImpl_WiFi uint32_t _GetWiFiAPIdleTimeoutMS(); void _SetWiFiAPIdleTimeoutMS(uint32_t val); CHIP_ERROR _GetAndLogWifiStatsCounters(); + CHIP_ERROR _GetEthPacketRxCount(uint64_t & packetRxCount); + CHIP_ERROR _GetEthPacketTxCount(uint64_t & packetTxCount); + CHIP_ERROR _GetEthTxErrCount(uint64_t & txErrCount); + CHIP_ERROR _GetEthCollisionCount(uint64_t & collisionCount); + CHIP_ERROR _GetEthOverrunCount(uint64_t & overrunCount); bool _CanStartWiFiScan(); void _OnWiFiScanDone(); void _OnWiFiStationProvisionChange(); @@ -181,6 +186,36 @@ template inline void GenericConnectivityManagerImpl_WiFi::_OnWiFiStationProvisionChange() {} +template +inline CHIP_ERROR GenericConnectivityManagerImpl_WiFi::_GetEthPacketRxCount(uint64_t & packetRxCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_WiFi::_GetEthPacketTxCount(uint64_t & packetTxCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_WiFi::_GetEthTxErrCount(uint64_t & txErrCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_WiFi::_GetEthCollisionCount(uint64_t & collisionCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + +template +inline CHIP_ERROR GenericConnectivityManagerImpl_WiFi::_GetEthOverrunCount(uint64_t & overrunCount) +{ + return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE; +} + } // namespace Internal } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Linux/ConnectivityManagerImpl.cpp b/src/platform/Linux/ConnectivityManagerImpl.cpp index f2a82511b0dc64..1aa807a8802c8e 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.cpp +++ b/src/platform/Linux/ConnectivityManagerImpl.cpp @@ -24,6 +24,10 @@ #include #include +#include +#include +#include + #include #include @@ -47,8 +51,18 @@ using namespace ::chip; using namespace ::chip::TLV; using namespace ::chip::DeviceLayer::Internal; -#if CHIP_DEVICE_CONFIG_ENABLE_WPA namespace { + +enum class EthernetStatsCountType +{ + kEthPacketRxCount, + kEthPacketTxCount, + kEthTxErrCount, + kEthCollisionCount, + kEthOverrunCount +}; + +#if CHIP_DEVICE_CONFIG_ENABLE_WPA const char kWpaSupplicantServiceName[] = "fi.w1.wpa_supplicant1"; const char kWpaSupplicantObjectPath[] = "/fi/w1/wpa_supplicant1"; @@ -224,9 +238,71 @@ static uint16_t MapFrequency(const uint16_t inBand, const uint8_t inChannel) return frequency; } -} // namespace #endif +CHIP_ERROR GetEthernetStatsCount(EthernetStatsCountType type, uint64_t & count) +{ + CHIP_ERROR ret = CHIP_ERROR_READ_FAILED; + struct ifaddrs * ifaddr = nullptr; + + if (getifaddrs(&ifaddr) == -1) + { + ChipLogError(DeviceLayer, "Failed to get network interfaces"); + } + else + { + struct ifaddrs * ifa = nullptr; + + /* Walk through linked list, maintaining head pointer so we + can free list later */ + for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) + { + if (strcmp(ifa->ifa_name, CHIP_DEVICE_CONFIG_ETHERNET_IF_NAME) == 0) + break; + } + + if (ifa != nullptr) + { + if (ifa->ifa_addr->sa_family == AF_PACKET && ifa->ifa_data != nullptr) + { + struct rtnl_link_stats * stats = (struct rtnl_link_stats *) ifa->ifa_data; + switch (type) + { + case EthernetStatsCountType::kEthPacketRxCount: + count = stats->rx_packets; + ret = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthPacketTxCount: + count = stats->tx_packets; + ret = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthTxErrCount: + count = stats->tx_errors; + ret = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthCollisionCount: + count = stats->collisions; + ret = CHIP_NO_ERROR; + break; + case EthernetStatsCountType::kEthOverrunCount: + count = stats->rx_over_errors; + ret = CHIP_NO_ERROR; + break; + default: + ChipLogError(DeviceLayer, "Unknown Ethernet statistic metric type"); + break; + } + } + } + + freeifaddrs(ifaddr); + } + + return ret; +} + +} // namespace + namespace chip { namespace DeviceLayer { @@ -456,6 +532,31 @@ void ConnectivityManagerImpl::_SetWiFiAPIdleTimeoutMS(uint32_t val) DeviceLayer::SystemLayer().ScheduleWork(DriveAPState, NULL); } +CHIP_ERROR ConnectivityManagerImpl::_GetEthPacketRxCount(uint64_t & packetRxCount) +{ + return GetEthernetStatsCount(EthernetStatsCountType::kEthPacketRxCount, packetRxCount); +} + +CHIP_ERROR ConnectivityManagerImpl::_GetEthPacketTxCount(uint64_t & packetTxCount) +{ + return GetEthernetStatsCount(EthernetStatsCountType::kEthPacketTxCount, packetTxCount); +} + +CHIP_ERROR ConnectivityManagerImpl::_GetEthTxErrCount(uint64_t & txErrCount) +{ + return GetEthernetStatsCount(EthernetStatsCountType::kEthTxErrCount, txErrCount); +} + +CHIP_ERROR ConnectivityManagerImpl::_GetEthCollisionCount(uint64_t & collisionCount) +{ + return GetEthernetStatsCount(EthernetStatsCountType::kEthCollisionCount, collisionCount); +} + +CHIP_ERROR ConnectivityManagerImpl::_GetEthOverrunCount(uint64_t & overrunCount) +{ + return GetEthernetStatsCount(EthernetStatsCountType::kEthOverrunCount, overrunCount); +} + void ConnectivityManagerImpl::_OnWpaInterfaceProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data) { GError * err = nullptr; diff --git a/src/platform/Linux/ConnectivityManagerImpl.h b/src/platform/Linux/ConnectivityManagerImpl.h index e2ef99d64b0438..a6b48d57489bf5 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.h +++ b/src/platform/Linux/ConnectivityManagerImpl.h @@ -142,6 +142,12 @@ class ConnectivityManagerImpl final : public ConnectivityManager, uint32_t _GetWiFiAPIdleTimeoutMS(); void _SetWiFiAPIdleTimeoutMS(uint32_t val); + CHIP_ERROR _GetEthPacketRxCount(uint64_t & packetRxCount); + CHIP_ERROR _GetEthPacketTxCount(uint64_t & packetTxCount); + CHIP_ERROR _GetEthTxErrCount(uint64_t & txErrCount); + CHIP_ERROR _GetEthCollisionCount(uint64_t & collisionCount); + CHIP_ERROR _GetEthOverrunCount(uint64_t & overrunCount); + static void _OnWpaProxyReady(GObject * source_object, GAsyncResult * res, gpointer user_data); static void _OnWpaInterfaceRemoved(WpaFiW1Wpa_supplicant1 * proxy, const gchar * path, GVariant * properties, gpointer user_data); diff --git a/zzz_generated/lighting-app/zap-generated/endpoint_config.h b/zzz_generated/lighting-app/zap-generated/endpoint_config.h index 6ddd9854c45eac..805d390c358ba3 100644 --- a/zzz_generated/lighting-app/zap-generated/endpoint_config.h +++ b/zzz_generated/lighting-app/zap-generated/endpoint_config.h @@ -849,12 +849,16 @@ { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* ClusterRevision */ \ \ /* Endpoint: 0, Cluster: Ethernet Network Diagnostics (server) */ \ - { 0x0002, ZAP_TYPE(INT64U), 8, 0, ZAP_LONG_DEFAULTS_INDEX(1891) }, /* PacketRxCount */ \ - { 0x0003, ZAP_TYPE(INT64U), 8, 0, ZAP_LONG_DEFAULTS_INDEX(1899) }, /* PacketTxCount */ \ - { 0x0004, ZAP_TYPE(INT64U), 8, 0, ZAP_LONG_DEFAULTS_INDEX(1907) }, /* TxErrCount */ \ - { 0x0005, ZAP_TYPE(INT64U), 8, 0, ZAP_LONG_DEFAULTS_INDEX(1915) }, /* CollisionCount */ \ - { 0x0006, ZAP_TYPE(INT64U), 8, 0, ZAP_LONG_DEFAULTS_INDEX(1923) }, /* OverrunCount */ \ - { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* ClusterRevision */ \ + { 0x0002, ZAP_TYPE(INT64U), 8, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), \ + ZAP_LONG_DEFAULTS_INDEX(1891) }, /* PacketRxCount */ \ + { 0x0003, ZAP_TYPE(INT64U), 8, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), \ + ZAP_LONG_DEFAULTS_INDEX(1899) }, /* PacketTxCount */ \ + { 0x0004, ZAP_TYPE(INT64U), 8, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_LONG_DEFAULTS_INDEX(1907) }, /* TxErrCount */ \ + { 0x0005, ZAP_TYPE(INT64U), 8, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), \ + ZAP_LONG_DEFAULTS_INDEX(1915) }, /* CollisionCount */ \ + { 0x0006, ZAP_TYPE(INT64U), 8, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), \ + ZAP_LONG_DEFAULTS_INDEX(1923) }, /* OverrunCount */ \ + { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* ClusterRevision */ \ \ /* Endpoint: 0, Cluster: AdministratorCommissioning (server) */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(0x0001) }, /* ClusterRevision */ \