diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 387bc4b4fdc462..3af6aeb13b89ff 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -2419,3 +2419,10 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET_SECONDS_WITH_POWER 10 #define CHIP_COMMISSIONING_HINT_INDEX_PRESS_RESET_UNTIL_BLINK_WITH_POWER 11 #endif + +#ifndef CHIP_CONFIG_IPCACHE_SIZE +#define CHIP_CONFIG_IPCACHE_SIZE 20 +#endif +#ifndef CHIP_CONFIG_TTL_MS +#define CHIP_CONFIG_TTL_MS 200000 +#endif diff --git a/src/lib/mdns/BUILD.gn b/src/lib/mdns/BUILD.gn index 7d1111f4766b52..a766c27605701f 100644 --- a/src/lib/mdns/BUILD.gn +++ b/src/lib/mdns/BUILD.gn @@ -33,6 +33,7 @@ static_library("mdns") { "ServiceNaming.h", "TxtFields.cpp", "TxtFields.h", + "IPCache.h", ] if (chip_mdns == "none") { diff --git a/src/lib/mdns/Discovery_ImplPlatform.cpp b/src/lib/mdns/Discovery_ImplPlatform.cpp index 1f81775e548e38..a7e6c54ceb7e19 100644 --- a/src/lib/mdns/Discovery_ImplPlatform.cpp +++ b/src/lib/mdns/Discovery_ImplPlatform.cpp @@ -36,6 +36,7 @@ namespace chip { namespace Mdns { DiscoveryImplPlatform DiscoveryImplPlatform::sManager; +IPCache DiscoveryImplPlatform::sIPCache; DiscoveryImplPlatform::DiscoveryImplPlatform() = default; @@ -424,6 +425,26 @@ CHIP_ERROR DiscoveryImplPlatform::ResolveNodeId(const PeerId & peerId, Inet::IPA { ReturnErrorOnFailure(Init()); + FabricId fabricId; + Inet::IPAddress addr; + uint16_t port; + Inet::InterfaceId iface; + + if (sIPCache.Lookup(peerId.GetNodeId(), fabricId, addr, port, iface) == CHIP_NO_ERROR) + { + ResolvedNodeData nodeData; + + nodeData.mInterfaceId = iface; + nodeData.mPort = port; + nodeData.mAddress = addr; + nodeData.mPeerId.SetNodeId(peerId.GetNodeId()); + nodeData.mPeerId.SetFabricId(fabricId); + + mResolverDelegate->OnNodeIdResolved(nodeData); + + return CHIP_NO_ERROR; + } + MdnsService service; ReturnErrorOnFailure(MakeInstanceName(service.mName, sizeof(service.mName), peerId)); @@ -509,6 +530,19 @@ void DiscoveryImplPlatform::HandleNodeIdResolve(void * context, MdnsService * re return; } + error = mgr->sIPCache.Insert( + nodeData.mPeerId.GetNodeId(), + nodeData.mPeerId.GetFabricId(), + result->mAddress.Value(), + result->mPort, + result->mInterface + ); + + if (error != CHIP_NO_ERROR) + { + ChipLogError(Discovery, "IPCache insert failed with %s", chip::ErrorStr(error)); + } + nodeData.mInterfaceId = result->mInterface; nodeData.mAddress = result->mAddress.ValueOr({}); nodeData.mPort = result->mPort; diff --git a/src/lib/mdns/Discovery_ImplPlatform.h b/src/lib/mdns/Discovery_ImplPlatform.h index 7ee4c8447bf229..bb38e26dc9518b 100644 --- a/src/lib/mdns/Discovery_ImplPlatform.h +++ b/src/lib/mdns/Discovery_ImplPlatform.h @@ -17,9 +17,11 @@ #pragma once +#include #include #include #include +#include #include #include #include @@ -90,6 +92,7 @@ class DiscoveryImplPlatform : public ServiceAdvertiser, public Resolver bool mMdnsInitialized = false; ResolverDelegate * mResolverDelegate = nullptr; + static IPCache sIPCache; static DiscoveryImplPlatform sManager; }; diff --git a/src/lib/mdns/IPCache.h b/src/lib/mdns/IPCache.h new file mode 100644 index 00000000000000..7254dea2ea77f1 --- /dev/null +++ b/src/lib/mdns/IPCache.h @@ -0,0 +1,128 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace Mdns { + +template +class IPCache +{ +public: + IPCache() : mOccupancy(0) + { + for (IPCacheEntry & e: mLookupTable) + { + e.nodeId = kUndefinedNodeId; + } + } + + CHIP_ERROR Insert(NodeId nodeId, FabricId fabricId, const Inet::IPAddress & addr, uint16_t port, Inet::InterfaceId iface) + { + const uint64_t currentTime = mTimeSource.GetCurrentMonotonicTimeMs(); + + IPCacheEntry * entry = LookupEntry(nodeId, currentTime); + if (!entry) entry = LookupAvailableEntry(currentTime); + if (!entry) return CHIP_ERROR_TOO_MANY_KEYS; + + if (entry->nodeId == kUndefinedNodeId) + { + mOccupancy++; + } + + entry->nodeId = nodeId; + entry->fabricId = fabricId; + entry->ipAddr = addr; + entry->port = port; + entry->ifaceId = iface; + + entry->expiry = currentTime + IPCACHE_TTL_MS; + + return CHIP_NO_ERROR; + } + + CHIP_ERROR Delete(NodeId nodeId) + { + const uint64_t currentTime = mTimeSource.GetCurrentMonotonicTimeMs(); + + IPCacheEntry * entry = LookupEntry(nodeId, currentTime); + if (!entry) return CHIP_ERROR_KEY_NOT_FOUND; + + entry->nodeId = kUndefinedNodeId; + mOccupancy--; + + return CHIP_NO_ERROR; + } + + size_t GetOccupancy() { return mOccupancy; } + + CHIP_ERROR Lookup(NodeId nodeId, FabricId & fabricId, Inet::IPAddress & addr, uint16_t & port, Inet::InterfaceId & iface) + { + const uint64_t currentTime = mTimeSource.GetCurrentMonotonicTimeMs(); + + IPCacheEntry * entry = LookupEntry(nodeId, currentTime); + if (!entry) return CHIP_ERROR_KEY_NOT_FOUND; + + fabricId = entry->fabricId; + addr = entry->ipAddr; + port = entry->port; + iface = entry->ifaceId; + + return CHIP_NO_ERROR; + } + +private: + struct IPCacheEntry + { + NodeId nodeId; + FabricId fabricId; + Inet::IPAddress ipAddr; + uint16_t port; + Inet::InterfaceId ifaceId; + uint64_t expiry; + }; + + IPCacheEntry * LookupEntry(NodeId nodeId, uint64_t currentTime) + { + NodeId idx = nodeId % IPCACHE_SIZE; + for (auto & _: mLookupTable) + { + (void) _; + + IPCacheEntry *entry = &mLookupTable[idx]; + + if (entry->nodeId == nodeId && entry->expiry >= currentTime) + return entry; + + idx++; + idx %= IPCACHE_SIZE; + } + return nullptr; + } + + IPCacheEntry * LookupAvailableEntry(uint64_t currentTime) + { + for (IPCacheEntry & entry: mLookupTable) + { + if (entry.nodeId == kUndefinedNodeId || entry.expiry < currentTime) + return &entry; + } + return nullptr; + } + + IPCacheEntry mLookupTable[IPCACHE_SIZE]; + size_t mOccupancy; + Time::TimeSource mTimeSource; +}; + +} // namespace mdns +} // namespace chip diff --git a/src/lib/mdns/Resolver_ImplMinimalMdns.cpp b/src/lib/mdns/Resolver_ImplMinimalMdns.cpp index 26a33faec498bd..d2134558033651 100644 --- a/src/lib/mdns/Resolver_ImplMinimalMdns.cpp +++ b/src/lib/mdns/Resolver_ImplMinimalMdns.cpp @@ -15,6 +15,7 @@ * limitations under the License. */ +#include "IPCache.h" #include "Resolver.h" #include @@ -22,6 +23,8 @@ #include "MinimalMdnsServer.h" #include "ServiceNaming.h" +#include + #include #include #include @@ -82,9 +85,9 @@ class PacketDataReporter : public ParserDelegate { public: PacketDataReporter(ResolverDelegate * delegate, chip::Inet::InterfaceId interfaceId, DiscoveryType discoveryType, - const BytesRange & packet) : + const BytesRange & packet, Mdns::IPCache & ipCache) : mDelegate(delegate), - mDiscoveryType(discoveryType), mPacketRange(packet) + mDiscoveryType(discoveryType), mPacketRange(packet), mIPCache(ipCache) { mNodeData.mInterfaceId = interfaceId; } @@ -105,6 +108,8 @@ class PacketDataReporter : public ParserDelegate DiscoveredNodeData mDiscoveredNodeData; BytesRange mPacketRange; + Mdns::IPCache & mIPCache; + bool mValid = false; bool mHasNodePort = false; bool mHasIP = false; @@ -310,6 +315,19 @@ void PacketDataReporter::OnComplete() { mDelegate->OnNodeIdResolved(mNodeData); } + + CHIP_ERROR error = mIPCache.Insert( + mNodeData.mPeerId.GetNodeId(), + mNodeData.mPeerId.GetFabricId(), + mNodeData.mAddress, + mNodeData.mPort, + mNodeData.mInterfaceId + ); + + if (error != CHIP_NO_ERROR) + { + ChipLogError(Discovery, "IPCache insert failed with %s", chip::ErrorStr(error)); + } } class MinMdnsResolver : public Resolver, public MdnsPacketDelegate @@ -345,8 +363,12 @@ class MinMdnsResolver : public Resolver, public MdnsPacketDelegate } static constexpr int kMaxQnameSize = 100; char qnameStorage[kMaxQnameSize]; + + static Mdns::IPCache sIPCache; }; +Mdns::IPCache MinMdnsResolver::sIPCache; + void MinMdnsResolver::OnMdnsPacketData(const BytesRange & data, const chip::Inet::IPPacketInfo * info) { if (mDelegate == nullptr) @@ -354,7 +376,7 @@ void MinMdnsResolver::OnMdnsPacketData(const BytesRange & data, const chip::Inet return; } - PacketDataReporter reporter(mDelegate, info->Interface, mDiscoveryType, data); + PacketDataReporter reporter(mDelegate, info->Interface, mDiscoveryType, data, sIPCache); if (!ParsePacket(data, &reporter)) { @@ -467,6 +489,26 @@ CHIP_ERROR MinMdnsResolver::BrowseNodes(DiscoveryType type, DiscoveryFilter filt CHIP_ERROR MinMdnsResolver::ResolveNodeId(const PeerId & peerId, Inet::IPAddressType type) { mDiscoveryType = DiscoveryType::kOperational; + + FabricId fabricId; + Inet::IPAddress addr; + uint16_t port; + Inet::InterfaceId iface; + + if (sIPCache.Lookup(peerId.GetNodeId(), fabricId, addr, port, iface) == CHIP_NO_ERROR) + { + ResolvedNodeData mNodeData; + + mNodeData.mPeerId.SetNodeId(peerId.GetNodeId()); + mNodeData.mPeerId.SetFabricId(fabricId); + mNodeData.mAddress = addr; + mNodeData.mPort = port; + mNodeData.mInterfaceId = iface; + + mDelegate->OnNodeIdResolved(mNodeData); + return CHIP_NO_ERROR; + } + System::PacketBufferHandle buffer = System::PacketBufferHandle::New(kMdnsMaxPacketSize); ReturnErrorCodeIf(buffer.IsNull(), CHIP_ERROR_NO_MEMORY);