From 451a72f750a0e4c8ad50cdd91b623d7d8e1b5d07 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Fri, 21 Feb 2020 12:55:08 -0800 Subject: [PATCH] [address-resolver] update public OT API for getting cache table (#4599) This commit updates the public OpenThread APIs to get the address cache table. The new APIs allows to iterate through all entries (including in query or retry mode) and provides more info about the entries, e.g., current timeout, retry delay (if entry is in query/retry state), or the mesh-local EID, last transaction time (if entry is in cached state). --- include/openthread/thread_ftd.h | 57 +++++++++++++++----- src/cli/cli.cpp | 12 ++--- src/core/api/thread_ftd_api.cpp | 7 +-- src/core/thread/address_resolver.cpp | 81 ++++++++++++++++++++++------ src/core/thread/address_resolver.hpp | 28 +++++++--- src/ncp/ncp_base_ftd.cpp | 16 +++--- 6 files changed, 148 insertions(+), 53 deletions(-) diff --git a/include/openthread/thread_ftd.h b/include/openthread/thread_ftd.h index c27a9483c..d9db8624e 100644 --- a/include/openthread/thread_ftd.h +++ b/include/openthread/thread_ftd.h @@ -78,17 +78,46 @@ typedef struct typedef uint16_t otChildIp6AddressIterator; ///< Used to iterate through IPv6 addresses of a Thread Child entry. +/** + * This enumeration defines the EID cache entry state. + * + */ +typedef enum otCacheEntryState +{ + OT_CACHE_ENTRY_STATE_CACHED = 0, // Entry is cached and in-use. + OT_CACHE_ENTRY_STATE_SNOOPED = 1, // Entry is created by snoop optimization (inspection of received msg). + OT_CACHE_ENTRY_STATE_QUERY = 2, // Entry represents an ongoing query for the EID. + OT_CACHE_ENTRY_STATE_RETRY_QUERY = 3, // Entry is in retry wait mode (a prior query did not get a response). +} otCacheEntryState; + /** * This structure represents an EID cache entry. * */ -typedef struct otEidCacheEntry +typedef struct otCacheEntryInfo { - otIp6Address mTarget; ///< Target - otShortAddress mRloc16; ///< RLOC16 - uint8_t mAge; ///< Age (order of use, 0 indicates most recently used entry) - bool mValid : 1; ///< Indicates whether or not the cache entry is valid -} otEidCacheEntry; + otIp6Address mTarget; ///< Target EID + otShortAddress mRloc16; ///< RLOC16 + otCacheEntryState mState; ///< Entry state + bool mCanEvict : 1; ///< Indicates whether the entry can be evicted. + bool mValidLastTrans : 1; ///< Indicates whether last transaction time and ML-EID are valid. + uint32_t mLastTransTime; ///< Last transaction time (applicable in cached state). + otIp6Address mMeshLocalEid; ///< Mesh Local EID (applicable if entry in cached state). + uint16_t mTimeout; ///< Timeout in seconds (applicable if in snooped/query/retry-query states). + uint16_t mRetryDelay; ///< Retry delay in seconds (applicable if in query-retry state). +} otCacheEntryInfo; + +/** + * This type represents an iterator used for iterating through the EID cache table entries. + * + * To initialize the iterator and start from the first entry in the cache table, set all its fields in the structure to + * zero (e.g., `memset` the iterator to zero). + * + */ +typedef struct otCacheEntryIterator +{ + const void *mData[2]; ///< Opaque data used by the core implementation. Should not be changed by user. +} otCacheEntryIterator; /** * Get the maximum number of children currently allowed. @@ -507,17 +536,19 @@ uint8_t otThreadGetMaxRouterId(otInstance *aInstance); otError otThreadGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRouterInfo *aRouterInfo); /** - * This function gets an EID cache entry. + * This function gets the next EID cache entry (using an iterator). * - * @param[in] aInstance A pointer to an OpenThread instance. - * @param[in] aIndex An index into the EID cache table. - * @param[out] aEntry A pointer to where the EID information is placed. + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[out] aEntryInfo A pointer to where the EID cache entry information is placed. + * @param[inout] aIterator A pointer to an iterator. It will be updated to point to next entry on success. To get the + * first entry, initialize the iterator by setting all its fields to zero (e.g., `memset` the + * the iterator structure to zero). * - * @retval OT_ERROR_NONE Successfully retrieved the EID cache entry. - * @retval OT_ERROR_INVALID_ARGS @p aIndex was out of bounds or @p aEntry was NULL. + * @retval OT_ERROR_NONE Successfully populated @p aEntryInfo for next EID cache entry. + * @retval OT_ERROR_NOT_FOUND No more entries in the address cache table. * */ -otError otThreadGetEidCacheEntry(otInstance *aInstance, uint8_t aIndex, otEidCacheEntry *aEntry); +otError otThreadGetNextCacheEntry(otInstance *aInstance, otCacheEntryInfo *aEntryInfo, otCacheEntryIterator *aIterator); /** * Get the Thread PSKc diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index e3746a33c..bfe4b3ced 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -1294,16 +1294,14 @@ void Interpreter::ProcessEidCache(uint8_t aArgsLength, char *aArgs[]) OT_UNUSED_VARIABLE(aArgsLength); OT_UNUSED_VARIABLE(aArgs); - otEidCacheEntry entry; + otCacheEntryIterator iterator; + otCacheEntryInfo entry; + + memset(&iterator, 0, sizeof(iterator)); for (uint8_t i = 0;; i++) { - SuccessOrExit(otThreadGetEidCacheEntry(mInstance, i, &entry)); - - if (!entry.mValid) - { - continue; - } + SuccessOrExit(otThreadGetNextCacheEntry(mInstance, &entry, &iterator)); OutputIp6Address(entry.mTarget); mServer->OutputFormat(" %04x\r\n", entry.mRloc16); diff --git a/src/core/api/thread_ftd_api.cpp b/src/core/api/thread_ftd_api.cpp index c102e84f3..cc564dedd 100644 --- a/src/core/api/thread_ftd_api.cpp +++ b/src/core/api/thread_ftd_api.cpp @@ -316,12 +316,13 @@ otError otThreadGetRouterInfo(otInstance *aInstance, uint16_t aRouterId, otRoute return instance.Get().GetRouterInfo(aRouterId, *aRouterInfo); } -otError otThreadGetEidCacheEntry(otInstance *aInstance, uint8_t aIndex, otEidCacheEntry *aEntry) +otError otThreadGetNextCacheEntry(otInstance *aInstance, otCacheEntryInfo *aEntryInfo, otCacheEntryIterator *aIterator) { Instance &instance = *static_cast(aInstance); - OT_ASSERT(aEntry != NULL); - return instance.Get().GetEntry(aIndex, *aEntry); + OT_ASSERT((aIterator != NULL) && (aEntryInfo != NULL)); + + return instance.Get().GetNextCacheEntry(*aEntryInfo, *aIterator); } #if OPENTHREAD_CONFIG_MLE_STEERING_DATA_SET_OOB_ENABLE diff --git a/src/core/thread/address_resolver.cpp b/src/core/thread/address_resolver.cpp index f50a12807..23876d1d2 100644 --- a/src/core/thread/address_resolver.cpp +++ b/src/core/thread/address_resolver.cpp @@ -99,30 +99,81 @@ void AddressResolver::Clear(void) } } -otError AddressResolver::GetEntry(uint8_t aIndex, otEidCacheEntry &aEntry) const +otError AddressResolver::GetNextCacheEntry(EntryInfo &aInfo, Iterator &aIterator) const { - otError error = OT_ERROR_NONE; - uint8_t age = aIndex; - const CacheEntryList *lists[] = {&mCachedList, &mSnoopedList}; + otError error = OT_ERROR_NONE; + const CacheEntryList *list; const CacheEntry * entry; - for (uint8_t index = 0; index < OT_ARRAY_LENGTH(lists); index++) - { - for (entry = lists[index]->GetHead(); (aIndex != 0) && (entry != NULL); aIndex--, entry = entry->GetNext()) - ; + list = reinterpret_cast(aIterator.mData[kIteratorListIndex]); + entry = reinterpret_cast(aIterator.mData[kIteratorEntryIndex]); - if (entry != NULL) + while (entry == NULL) + { + if (list == NULL) { - break; + list = &mCachedList; } + else if (list == &mCachedList) + { + list = &mSnoopedList; + } + else if (list == &mSnoopedList) + { + list = &mQueryList; + } + else if (list == &mQueryList) + { + list = &mQueryRetryList; + } + else + { + ExitNow(error = OT_ERROR_NOT_FOUND); + } + + entry = list->GetHead(); } - VerifyOrExit(entry != NULL, error = OT_ERROR_NOT_FOUND); + // Update the iterator then populate the `aInfo`. - aEntry.mTarget = entry->GetTarget(); - aEntry.mRloc16 = entry->GetRloc16(); - aEntry.mAge = age; - aEntry.mValid = true; + aIterator.mData[kIteratorEntryIndex] = entry->GetNext(); + aIterator.mData[kIteratorListIndex] = list; + + memset(&aInfo, 0, sizeof(aInfo)); + aInfo.mTarget = entry->GetTarget(); + aInfo.mRloc16 = entry->GetRloc16(); + + if (list == &mCachedList) + { + aInfo.mState = OT_CACHE_ENTRY_STATE_CACHED; + aInfo.mCanEvict = true; + aInfo.mValidLastTrans = entry->IsLastTransactionTimeValid(); + + VerifyOrExit(entry->IsLastTransactionTimeValid()); + + aInfo.mLastTransTime = entry->GetLastTransactionTime(); + static_cast(aInfo.mMeshLocalEid).SetPrefix(Get().GetMeshLocalPrefix()); + static_cast(aInfo.mMeshLocalEid).SetIid(entry->GetMeshLocalIid()); + + ExitNow(); + } + + if (list == &mSnoopedList) + { + aInfo.mState = OT_CACHE_ENTRY_STATE_SNOOPED; + } + else if (list == &mQueryList) + { + aInfo.mState = OT_CACHE_ENTRY_STATE_QUERY; + } + else + { + aInfo.mState = OT_CACHE_ENTRY_STATE_RETRY_QUERY; + } + + aInfo.mCanEvict = entry->CanEvict(); + aInfo.mTimeout = entry->GetTimeout(); + aInfo.mRetryDelay = entry->GetRetryDelay(); exit: return error; diff --git a/src/core/thread/address_resolver.hpp b/src/core/thread/address_resolver.hpp index eba518359..759fc7045 100644 --- a/src/core/thread/address_resolver.hpp +++ b/src/core/thread/address_resolver.hpp @@ -63,6 +63,18 @@ namespace ot { class AddressResolver : public InstanceLocator { public: + /** + * This type represents an iterator used for iterating through the EID cache table entries. + * + */ + typedef otCacheEntryIterator Iterator; + + /** + * This type represents an EID cache entry. + * + */ + typedef otCacheEntryInfo EntryInfo; + /** * This constructor initializes the object. * @@ -76,16 +88,18 @@ public: void Clear(void); /** - * This method gets an EID cache entry. + * This method gets the information about the next EID cache entry (using an iterator). * - * @param[in] aIndex An index into the EID cache table. - * @param[out] aEntry A reference to where the EID information is placed. + * @param[out] aInfo An `EntryInfo` where the EID cache entry information is placed. + * @param[inout] aIterator An iterator. It will be updated to point to the next entry on success. + * To get the first entry, initialize the iterator by setting all its fields to zero. + * e.g., `memset` the the iterator structure to zero. * - * @retval OT_ERROR_NONE Successfully retrieved the EID cache entry. - * @retval OT_ERROR_INVALID_ARGS @p aIndex was out of bounds. + * @retval OT_ERROR_NONE Successfully populated @p aInfo with the info for the next EID cache entry. + * @retval OT_ERROR_NOT_FOUND No more entries in the address cache table. * */ - otError GetEntry(uint8_t aIndex, otEidCacheEntry &aEntry) const; + otError GetNextCacheEntry(EntryInfo &aInfo, Iterator &aIterator) const; /** * This method removes the EID-to-RLOC cache entries corresponding to an RLOC16. @@ -170,6 +184,8 @@ private: kAddressQueryMaxRetryDelay = OPENTHREAD_CONFIG_TMF_ADDRESS_QUERY_MAX_RETRY_DELAY, // in seconds kSnoopBlockEvictionTimeout = OPENTHREAD_CONFIG_TMF_SNOOP_CACHE_ENTRY_TIMEOUT, // in seconds kStateUpdatePeriod = 1000u, // in milliseconds + kIteratorListIndex = 0, + kIteratorEntryIndex = 1, }; class CacheEntry : public InstanceLocatorInit diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index dde5c9d0e..3422684b0 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -911,22 +911,20 @@ exit: template <> otError NcpBase::HandlePropertyGet(void) { - otError error = OT_ERROR_NONE; - otEidCacheEntry entry; + otError error = OT_ERROR_NONE; + otCacheEntryIterator iterator; + otCacheEntryInfo entry; + + memset(&iterator, 0, sizeof(iterator)); for (uint8_t index = 0;; index++) { - SuccessOrExit(otThreadGetEidCacheEntry(mInstance, index, &entry)); - - if (!entry.mValid) - { - continue; - } + SuccessOrExit(otThreadGetNextCacheEntry(mInstance, &entry, &iterator)); SuccessOrExit(error = mEncoder.OpenStruct()); SuccessOrExit(error = mEncoder.WriteIp6Address(entry.mTarget)); SuccessOrExit(error = mEncoder.WriteUint16(entry.mRloc16)); - SuccessOrExit(error = mEncoder.WriteUint8(entry.mAge)); + SuccessOrExit(error = mEncoder.WriteUint8(index)); SuccessOrExit(error = mEncoder.CloseStruct()); }