[dua] add NdProxy table on Backbone Router (#5422)

This commit is contained in:
Simon Lin
2020-09-08 12:34:52 +08:00
committed by GitHub
parent 2280a54064
commit 1fedcb2426
19 changed files with 726 additions and 26 deletions
+1
View File
@@ -180,6 +180,7 @@ LOCAL_SRC_FILES := \
src/core/backbone_router/bbr_local.cpp \
src/core/backbone_router/bbr_manager.cpp \
src/core/backbone_router/multicast_listeners_table.cpp \
src/core/backbone_router/ndproxy_table.cpp \
src/core/coap/coap.cpp \
src/core/coap/coap_message.cpp \
src/core/coap/coap_secure.cpp \
+2
View File
@@ -327,6 +327,8 @@ openthread_core_files = [
"backbone_router/bbr_manager.hpp",
"backbone_router/multicast_listeners_table.cpp",
"backbone_router/multicast_listeners_table.hpp",
"backbone_router/ndproxy_table.cpp",
"backbone_router/ndproxy_table.hpp",
"coap/coap.cpp",
"coap/coap.hpp",
"coap/coap_message.cpp",
+1
View File
@@ -106,6 +106,7 @@ set(COMMON_SOURCES
backbone_router/bbr_local.cpp
backbone_router/bbr_manager.cpp
backbone_router/multicast_listeners_table.cpp
backbone_router/ndproxy_table.cpp
coap/coap.cpp
coap/coap_message.cpp
coap/coap_secure.cpp
+2
View File
@@ -148,6 +148,7 @@ SOURCES_COMMON = \
backbone_router/bbr_local.cpp \
backbone_router/bbr_manager.cpp \
backbone_router/multicast_listeners_table.cpp \
backbone_router/ndproxy_table.cpp \
coap/coap.cpp \
coap/coap_message.cpp \
coap/coap_secure.cpp \
@@ -328,6 +329,7 @@ HEADERS_COMMON = \
backbone_router/bbr_local.hpp \
backbone_router/bbr_manager.hpp \
backbone_router/multicast_listeners_table.hpp \
backbone_router/ndproxy_table.hpp \
coap/coap.hpp \
coap/coap_message.hpp \
coap/coap_secure.hpp \
+1
View File
@@ -302,6 +302,7 @@ void Leader::UpdateDomainPrefixConfig(void)
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
Get<Local>().UpdateAllDomainBackboneRouters(state);
Get<NdProxyTable>().HandleDomainPrefixUpdate(state);
#endif
#if OPENTHREAD_CONFIG_DUA_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_DUA_ENABLE
+51 -8
View File
@@ -53,6 +53,7 @@ Manager::Manager(Instance &aInstance)
: InstanceLocator(aInstance)
, mMulticastListenerRegistration(UriPath::kMlr, Manager::HandleMulticastListenerRegistration, this)
, mDuaRegistration(UriPath::kDuaRegistrationRequest, Manager::HandleDuaRegistration, this)
, mNdProxyTable(aInstance)
, mMulticastListenersTable(aInstance)
, mTimer(aInstance, Manager::HandleTimer, this)
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
@@ -267,13 +268,15 @@ exit:
void Manager::HandleDuaRegistration(const Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
otError error = OT_ERROR_NONE;
ThreadStatusTlv::DuaStatus status = ThreadStatusTlv::kDuaSuccess;
bool isPrimary = Get<BackboneRouter::Local>().IsPrimary();
uint32_t lastTransactionTime = 0;
otError error = OT_ERROR_NONE;
ThreadStatusTlv::DuaStatus status = ThreadStatusTlv::kDuaSuccess;
bool isPrimary = Get<BackboneRouter::Local>().IsPrimary();
uint32_t lastTransactionTime;
bool hasLastTransactionTime;
Ip6::Address target;
Ip6::InterfaceIdentifier meshLocalIid;
VerifyOrExit(aMessageInfo.GetPeerAddr().GetIid().IsRoutingLocator(), error = OT_ERROR_DROP);
VerifyOrExit(aMessage.IsConfirmablePostRequest(), error = OT_ERROR_PARSE);
SuccessOrExit(error = Tlv::FindTlv(aMessage, ThreadTlv::kTarget, &target, sizeof(target)));
@@ -290,17 +293,31 @@ void Manager::HandleDuaRegistration(const Coap::Message &aMessage, const Ip6::Me
VerifyOrExit(isPrimary, status = ThreadStatusTlv::kDuaNotPrimary);
VerifyOrExit(Get<BackboneRouter::Leader>().IsDomainUnicast(target), status = ThreadStatusTlv::kDuaInvalid);
if (Tlv::FindUint32Tlv(aMessage, ThreadTlv::kLastTransactionTime, lastTransactionTime) == OT_ERROR_NONE)
hasLastTransactionTime =
(Tlv::FindUint32Tlv(aMessage, ThreadTlv::kLastTransactionTime, lastTransactionTime) == OT_ERROR_NONE);
switch (mNdProxyTable.Register(target.GetIid(), meshLocalIid, aMessageInfo.GetPeerAddr().GetIid().GetLocator(),
hasLastTransactionTime ? &lastTransactionTime : nullptr))
{
// TODO: (DUA) hasLastTransactionTime = true;
case OT_ERROR_NONE:
// TODO: update its EID-to-RLOC Map Cache based on the pair {DUA, RLOC16-source} which is gleaned from the
// DUA.req packet according to Thread Spec. 5.23.3.6.2
break;
case OT_ERROR_DUPLICATED:
status = ThreadStatusTlv::kDuaDuplicate;
break;
case OT_ERROR_NO_BUFS:
status = ThreadStatusTlv::kDuaNoResources;
break;
default:
status = ThreadStatusTlv::kDuaGeneralFailure;
break;
}
// TODO: (DUA) Add ND-PROXY table management
// TODO: (DUA) Add DAD process
// TODO: (DUA) Extended Address Query
exit:
otLogInfoBbr("Received DUA.req on %s: %s", (isPrimary ? "PBBR" : "SBBR"), otThreadErrorToString(error));
if (error == OT_ERROR_NONE)
@@ -361,6 +378,32 @@ void Manager::ConfigNextMulticastListenerRegistrationResponse(ThreadStatusTlv::M
}
#endif
NdProxyTable &Manager::GetNdProxyTable(void)
{
return mNdProxyTable;
}
bool Manager::ShouldForwardDuaToBackbone(const Ip6::Address &aAddress)
{
bool forwardToBackbone = false;
Mac::ShortAddress rloc16;
otError error;
VerifyOrExit(Get<Local>().IsPrimary(), OT_NOOP);
VerifyOrExit(Get<Leader>().IsDomainUnicast(aAddress), OT_NOOP);
VerifyOrExit(!mNdProxyTable.IsRegistered(aAddress.GetIid()), OT_NOOP);
error = Get<AddressResolver>().Resolve(aAddress, rloc16, /* aAllowAddressQuery */ false);
VerifyOrExit(error != OT_ERROR_NONE || rloc16 == Get<Mle::MleRouter>().GetRloc16(), OT_NOOP);
// TODO: check if the DUA is an address of any Child?
forwardToBackbone = true;
exit:
return forwardToBackbone;
}
} // namespace BackboneRouter
} // namespace ot
+22
View File
@@ -42,6 +42,7 @@
#include "backbone_router/bbr_leader.hpp"
#include "backbone_router/multicast_listeners_table.hpp"
#include "backbone_router/ndproxy_table.hpp"
#include "common/locator.hpp"
#include "net/netif.hpp"
#include "thread/network_data.hpp"
@@ -67,6 +68,14 @@ public:
*/
explicit Manager(Instance &aInstance);
/**
* This method returns the NdProxy Table.
*
* @returns The NdProxy Table.
*
*/
NdProxyTable &GetNdProxyTable(void);
#if OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE
/**
* This method configures response status for next DUA registration.
@@ -102,6 +111,18 @@ public:
*/
MulticastListenersTable &GetMulticastListenersTable(void) { return mMulticastListenersTable; }
/**
* This method returns if messages destined to a given Domain Unicast Address should be forwarded to the Backbone
* link.
*
* @param aAddress The Domain Unicast Address.
*
* @retval TRUE If messages destined to the Domain Unicast Address should be forwarded to the Backbone link.
* @retval FALSE If messages destined to the Domain Unicast Address should not be forwarded to the Backbone link.
*
*/
bool ShouldForwardDuaToBackbone(const Ip6::Address &aAddress);
private:
enum
{
@@ -140,6 +161,7 @@ private:
Coap::Resource mMulticastListenerRegistration;
Coap::Resource mDuaRegistration;
NdProxyTable mNdProxyTable;
MulticastListenersTable mMulticastListenersTable;
TimerMilli mTimer;
+232
View File
@@ -0,0 +1,232 @@
/*
* Copyright (c) 2020, 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.
*/
/**
* @file
* This file implements Thread NdProxy Table management.
*/
#include "ndproxy_table.hpp"
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
#include "common/locator-getters.hpp"
#include "common/logging.hpp"
namespace ot {
namespace BackboneRouter {
void NdProxyTable::NdProxy::Init(const Ip6::InterfaceIdentifier &aAddressIid,
const Ip6::InterfaceIdentifier &aMeshLocalIid,
uint16_t aRloc16,
uint32_t aTimeSinceLastTransaction)
{
OT_ASSERT(!mValid);
mValid = true;
mAddressIid = aAddressIid;
mMeshLocalIid = aMeshLocalIid;
Update(aRloc16, aTimeSinceLastTransaction);
}
void NdProxyTable::NdProxy::Update(uint16_t aRloc16, uint32_t aTimeSinceLastTransaction)
{
OT_ASSERT(mValid);
mRloc16 = aRloc16;
aTimeSinceLastTransaction =
OT_MIN(aTimeSinceLastTransaction, static_cast<uint32_t>(Mle::kTimeSinceLastTransactionMax));
mLastRegistrationTime = TimerMilli::GetNow() - TimeMilli::SecToMsec(aTimeSinceLastTransaction);
}
bool NdProxyTable::MatchesFilter(const NdProxy &aProxy, Filter aFilter)
{
bool rval = false;
switch (aFilter)
{
case kFilterInvalid:
rval = !aProxy.mValid;
break;
case kFilterValid:
rval = aProxy.mValid;
break;
}
return rval;
}
NdProxyTable::Iterator::Iterator(Instance &aInstance, Filter aFilter)
: InstanceLocator(aInstance)
, mFilter(aFilter)
{
NdProxyTable &table = GetInstance().Get<BackboneRouter::NdProxyTable>();
mCurrent = &table.mProxies[0];
if (!MatchesFilter(*mCurrent, mFilter))
{
Advance();
}
}
NdProxyTable::Iterator::Iterator(Instance &aInstance, NdProxyTable::Iterator::IteratorType)
: InstanceLocator(aInstance)
{
NdProxyTable &table = GetInstance().Get<BackboneRouter::NdProxyTable>();
mCurrent = OT_ARRAY_END(table.mProxies);
}
void NdProxyTable::Iterator::Advance(void)
{
NdProxyTable &table = GetInstance().Get<BackboneRouter::NdProxyTable>();
do
{
mCurrent++;
} while (mCurrent < OT_ARRAY_END(table.mProxies) && !MatchesFilter(*mCurrent, mFilter));
}
void NdProxyTable::Erase(NdProxy &aProxy)
{
aProxy.Clear();
}
void NdProxyTable::HandleDomainPrefixUpdate(Leader::DomainPrefixState aState)
{
if (aState == Leader::kDomainPrefixAdded || aState == Leader::kDomainPrefixRemoved ||
aState == Leader::kDomainPrefixRefreshed)
{
Clear();
}
}
void NdProxyTable::Clear(void)
{
for (NdProxy &proxy : mProxies)
{
proxy.Clear();
}
otLogNoteBbr("NdProxyTable::Clear!");
}
otError NdProxyTable::Register(const Ip6::InterfaceIdentifier &aAddressIid,
const Ip6::InterfaceIdentifier &aMeshLocalIid,
uint16_t aRloc16,
const uint32_t * aTimeSinceLastTransaction)
{
otError error = OT_ERROR_NONE;
NdProxy *proxy = FindByAddressIid(aAddressIid);
uint32_t timeSinceLastTransaction = aTimeSinceLastTransaction == nullptr ? 0 : *aTimeSinceLastTransaction;
if (proxy != nullptr)
{
VerifyOrExit(proxy->mMeshLocalIid == aMeshLocalIid, error = OT_ERROR_DUPLICATED);
proxy->Update(aRloc16, timeSinceLastTransaction);
ExitNow();
}
proxy = FindByMeshLocalIid(aMeshLocalIid);
if (proxy != nullptr)
{
Erase(*proxy);
}
else
{
proxy = FindInvalid();
// TODO: evict stale DUA entries to have room for this new DUA.
VerifyOrExit(proxy != nullptr, error = OT_ERROR_NO_BUFS);
}
proxy->Init(aAddressIid, aMeshLocalIid, aRloc16, timeSinceLastTransaction);
exit:
otLogInfoBbr("NdProxyTable::Register %s MLIID %s RLOC16 %04x LTT %u => %s", aAddressIid.ToString().AsCString(),
aMeshLocalIid.ToString().AsCString(), aRloc16, timeSinceLastTransaction, otThreadErrorToString(error));
return error;
}
NdProxyTable::NdProxy *NdProxyTable::FindByAddressIid(const Ip6::InterfaceIdentifier &aAddressIid)
{
NdProxy *found = nullptr;
for (NdProxy &proxy : Iterate(kFilterValid))
{
if (proxy.mAddressIid == aAddressIid)
{
ExitNow(found = &proxy);
}
}
exit:
otLogDebgBbr("NdProxyTable::FindByAddressIid(%s) => %s", aAddressIid.ToString().AsCString(),
found ? found->mMeshLocalIid.ToString().AsCString() : "NOT_FOUND");
return found;
}
NdProxyTable::NdProxy *NdProxyTable::FindByMeshLocalIid(const Ip6::InterfaceIdentifier &aMeshLocalIid)
{
NdProxy *found = nullptr;
for (NdProxy &proxy : Iterate(kFilterValid))
{
if (proxy.mMeshLocalIid == aMeshLocalIid)
{
ExitNow(found = &proxy);
}
}
exit:
otLogDebgBbr("NdProxyTable::FindByMeshLocalIid(%s) => %s", aMeshLocalIid.ToString().AsCString(),
found ? found->mAddressIid.ToString().AsCString() : "NOT_FOUND");
return found;
}
NdProxyTable::NdProxy *NdProxyTable::FindInvalid(void)
{
NdProxy *found = nullptr;
for (NdProxy &proxy : Iterate(kFilterInvalid))
{
ExitNow(found = &proxy);
}
exit:
otLogDebgBbr("NdProxyTable::FindInvalid() => %s", found ? "OK" : "NOT_FOUND");
return found;
}
} // namespace BackboneRouter
} // namespace ot
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
+206
View File
@@ -0,0 +1,206 @@
/*
* Copyright (c) 2020, 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.
*/
/**
* @file
* This file includes definitions for NdProxy Table on Thread Backbone Border Router.
*/
#ifndef NDPROXY_TABLE_HPP_
#define NDPROXY_TABLE_HPP_
#include "openthread-core-config.h"
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
#include <openthread/backbone_router_ftd.h>
#include "backbone_router/bbr_leader.hpp"
#include "common/locator.hpp"
#include "common/non_copyable.hpp"
#include "common/time.hpp"
#include "net/ip6_address.hpp"
namespace ot {
namespace BackboneRouter {
/**
* This class implements NdProxy Table maintenance on Primary Backbone Router.
*
*/
class NdProxyTable : public InstanceLocator, private NonCopyable
{
public:
/**
* This constructor initializes the `NdProxyTable` object.
*
* @param[in] aInstance A reference to the OpenThread instance.
*
*/
explicit NdProxyTable(Instance &aInstance)
: InstanceLocator(aInstance)
{
}
/**
* This method registers a given Ip6 address IID with related information to the NdProxy table.
*
* @param[in] aAddressIid The Ip6 address IID.
* @param[in] aMeshLocalIid The Mesh-Local IID.
* @param[in] aRloc16 The RLOC16.
* @param[in] aTimeSinceLastTransaction Time since last transaction (in seconds).
*
* @retval OT_ERROR_NONE If registered successfully.
* @retval OT_ERROR_DUPLICATED If the Ip6 address IID is a duplicate.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to register.
*
*/
otError Register(const Ip6::InterfaceIdentifier &aAddressIid,
const Ip6::InterfaceIdentifier &aMeshLocalIid,
uint16_t aRloc16,
const uint32_t * aTimeSinceLastTransaction);
/**
* This method checks if a given Ip6 address IID was registered.
*
* @param[in] aAddressIid The Ip6 address IID.
*
* @retval TRUE If the Ip6 address IID was registered.
* @retval FALSE If the Ip6 address IID was not registered.
*
*/
bool IsRegistered(const Ip6::InterfaceIdentifier &aAddressIid) { return FindByAddressIid(aAddressIid) != nullptr; }
/**
* This method notifies Domain Prefix status.
*
* @param[in] aState The Domain Prefix state or state change.
*
*/
void HandleDomainPrefixUpdate(Leader::DomainPrefixState aState);
private:
enum
{
kMaxNdProxyNum = OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM,
};
enum Filter : uint8_t
{
kFilterInvalid,
kFilterValid,
};
class NdProxy : private Clearable<NdProxy>
{
friend class NdProxyTable;
private:
NdProxy(void) { Clear(); }
void Init(const Ip6::InterfaceIdentifier &aAddressIid,
const Ip6::InterfaceIdentifier &aMeshLocalIid,
uint16_t aRloc16,
uint32_t aTimeSinceLastTransaction);
void Update(uint16_t aRloc16, uint32_t aTimeSinceLastTransaction);
Ip6::InterfaceIdentifier mAddressIid;
Ip6::InterfaceIdentifier mMeshLocalIid;
TimeMilli mLastRegistrationTime; ///< in milliseconds
uint16_t mRloc16;
bool mValid : 1;
};
/**
* This class represents an iterator for iterating through the NdProxy Table.
*
*/
class Iterator : public InstanceLocator
{
friend class NdProxyTable;
friend class IteratorBuilder;
private:
enum IteratorType
{
kEndIterator,
};
Iterator(Instance &aInstance, Filter aFilter);
Iterator(Instance &aInstance, IteratorType);
bool IsDone(void) const { return (mCurrent == nullptr); }
void Advance(void);
void operator++(void) { Advance(); }
void operator++(int) { Advance(); }
const NdProxy &operator*(void)const { return *mCurrent; }
bool operator==(const Iterator &aOther) const { return mCurrent == aOther.mCurrent; }
bool operator!=(const Iterator &aOther) const { return !(*this == aOther); }
NdProxy * operator->(void) { return mCurrent; }
NdProxy & operator*(void) { return *mCurrent; }
NdProxy *mCurrent;
Filter mFilter;
};
class IteratorBuilder : public InstanceLocator
{
friend class NdProxyTable;
private:
IteratorBuilder(Instance &aInstance, Filter aFilter)
: InstanceLocator(aInstance)
, mFilter(aFilter)
{
}
Iterator begin(void) { return Iterator(GetInstance(), mFilter); }
Iterator end(void) { return Iterator(GetInstance(), Iterator::kEndIterator); }
Filter mFilter;
};
IteratorBuilder Iterate(Filter aFilter) { return IteratorBuilder(GetInstance(), aFilter); }
void Clear(void);
static bool MatchesFilter(const NdProxy &aProxy, Filter aFilter);
NdProxy * FindByAddressIid(const Ip6::InterfaceIdentifier &aAddressIid);
NdProxy * FindByMeshLocalIid(const Ip6::InterfaceIdentifier &aMeshLocalIid);
NdProxy * FindInvalid(void);
static void Erase(NdProxy &aProxy);
NdProxy mProxies[kMaxNdProxyNum];
};
} // namespace BackboneRouter
} // namespace ot
#endif // OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
#endif // NDPROXY_TABLE_HPP_
+4
View File
@@ -763,6 +763,10 @@ template <> inline BackboneRouter::MulticastListenersTable &Instance::Get(void)
{
return mThreadNetif.mBackboneRouterManager.GetMulticastListenersTable();
}
template <> inline BackboneRouter::NdProxyTable &Instance::Get(void)
{
return mThreadNetif.mBackboneRouterManager.GetNdProxyTable();
}
#endif
#if OPENTHREAD_CONFIG_MLR_ENABLE || OPENTHREAD_CONFIG_TMF_PROXY_MLR_ENABLE
+13
View File
@@ -60,4 +60,17 @@
#define OPENTHREAD_CONFIG_MAX_MULTICAST_LISTENERS 75
#endif
/**
* @def OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM
*
* The maximum number of supported DUA that Backbone Router could proxy.
*
* Note: According to Thread Conformance v1.2.0, a Thread Border Router MUST be able to hold a DUA Devices Table in
* memory with at least two hundred and fifty (250) entries.
*
*/
#ifndef OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM
#define OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM 250
#endif
#endif // CONFIG_BACKBONE_ROUTER_H_
+12 -2
View File
@@ -33,6 +33,9 @@
#include "ip6.hpp"
#include "backbone_router/bbr_leader.hpp"
#include "backbone_router/bbr_local.hpp"
#include "backbone_router/ndproxy_table.hpp"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
#include "common/instance.hpp"
@@ -1217,7 +1220,7 @@ start:
{
uint8_t hopLimit;
if (!ShouldForwardToThread(messageInfo))
if (!ShouldForwardToThread(messageInfo, aFromNcpHost))
{
// try passing to host
error = ProcessReceiveCallback(aMessage, messageInfo, nextHeader, aFromNcpHost, Message::kTakeCustody);
@@ -1267,8 +1270,10 @@ exit:
return error;
}
bool Ip6::ShouldForwardToThread(const MessageInfo &aMessageInfo) const
bool Ip6::ShouldForwardToThread(const MessageInfo &aMessageInfo, bool aFromNcpHost) const
{
OT_UNUSED_VARIABLE(aFromNcpHost);
bool rval = false;
if (aMessageInfo.GetSockAddr().IsMulticast())
@@ -1284,7 +1289,12 @@ bool Ip6::ShouldForwardToThread(const MessageInfo &aMessageInfo) const
else if (IsOnLink(aMessageInfo.GetSockAddr()))
{
// on-link global address
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
ExitNow(rval = (aFromNcpHost ||
!Get<BackboneRouter::Manager>().ShouldForwardDuaToBackbone(aMessageInfo.GetSockAddr())));
#else
ExitNow(rval = true);
#endif
}
else if (Get<ThreadNetif>().RouteLookup(aMessageInfo.GetPeerAddr(), aMessageInfo.GetSockAddr(), nullptr) ==
OT_ERROR_NONE)
+1 -1
View File
@@ -358,7 +358,7 @@ private:
otError RemoveMplOption(Message &aMessage);
otError HandleOptions(Message &aMessage, Header &aHeader, bool &aForward);
otError HandlePayload(Message &aMessage, MessageInfo &aMessageInfo, uint8_t aIpProto);
bool ShouldForwardToThread(const MessageInfo &aMessageInfo) const;
bool ShouldForwardToThread(const MessageInfo &aMessageInfo, bool aFromNcpHost) const;
bool IsOnLink(const Address &aAddress) const;
bool mForwardingEnabled;
+7 -1
View File
@@ -442,7 +442,7 @@ void AddressResolver::RestartAddressQueries(void)
}
}
otError AddressResolver::Resolve(const Ip6::Address &aEid, uint16_t &aRloc16)
otError AddressResolver::Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16, bool aAllowAddressQuery)
{
otError error = OT_ERROR_NONE;
CacheEntry * entry;
@@ -457,6 +457,7 @@ otError AddressResolver::Resolve(const Ip6::Address &aEid, uint16_t &aRloc16)
// allocate a new entry and perform address query. We do not
// allow first-time address query entries to be evicted till
// timeout.
VerifyOrExit(aAllowAddressQuery, error = OT_ERROR_NOT_FOUND);
entry = NewCacheEntry(/* aSnoopedEntry */ false);
VerifyOrExit(entry != nullptr, error = OT_ERROR_NO_BUFS);
@@ -485,6 +486,11 @@ otError AddressResolver::Resolve(const Ip6::Address &aEid, uint16_t &aRloc16)
ExitNow();
}
// Note that if `aAllowAddressQuery` is `false` then the `entry` is definitely already in a list, i.e., we cannot
// not get here with `aAllowAddressQuery` being `false` and `entry` being a newly allocated one, due to the
// `VerifyOrExit` check that `aAllowAddressQuery` is `true` before allocating a new cache entry.
VerifyOrExit(aAllowAddressQuery, error = OT_ERROR_NOT_FOUND);
if (list == &mQueryList)
{
ExitNow(error = OT_ERROR_ADDRESS_QUERY);
+8 -5
View File
@@ -153,18 +153,21 @@ public:
void AddSnoopedCacheEntry(const Ip6::Address &aEid, Mac::ShortAddress aRloc16);
/**
* This method returns the RLOC16 for a given EID, or initiates an Address Query if the mapping is not known.
* This method returns the RLOC16 for a given EID, initiates an Address Query if allowed and the mapping is not
* known.
*
* @param[in] aEid A reference to the EID.
* @param[out] aRloc16 The RLOC16 corresponding to @p aEid.
* @param[in] aEid A reference to the EID.
* @param[out] aRloc16 The RLOC16 corresponding to @p aEid.
* @param[in] aAllowAddressQuery Allow to initiate Address Query if the mapping is not known.
*
* @retval OT_ERROR_NONE Successfully provided the RLOC16.
* @retval OT_ERROR_ADDRESS_QUERY Initiated an Address Query.
* @retval OT_ERROR_ADDRESS_QUERY Initiated an Address Query if allowed.
* @retval OT_ERROR_DROP Earlier Address Query for the EID timed out. In retry timeout interval.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to send Address Query.
* @retval OT_ERROR_NOT_FOUND The mapping was not found and Address Query was not allowed.
*
*/
otError Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16);
otError Resolve(const Ip6::Address &aEid, Mac::ShortAddress &aRloc16, bool aAllowAddressQuery = true);
/**
* This method restarts any ongoing address queries.
+4
View File
@@ -268,6 +268,7 @@ enum
KResponseTimeoutDelay = 30, ///< In seconds.
kDuaDadPeriod = 100, ///< In seconds. Time period after which the address
///< becomes "Preferred" if no duplicate address error.
kTimeSinceLastTransactionMax = 10 * 86400, ///< In seconds (10 days).
};
static_assert(kMlrTimeoutDefault >= kMlrTimeoutMin && kMlrTimeoutDefault <= kMlrTimeoutMax,
@@ -276,6 +277,9 @@ static_assert(kMlrTimeoutDefault >= kMlrTimeoutMin && kMlrTimeoutDefault <= kMlr
static_assert(Mle::kParentAggregateDelay > 1, "kParentAggregateDelay should be larger than 1 second");
static_assert(kMlrTimeoutMax * 1000 > kMlrTimeoutMax, "SecToMsec(kMlrTimeoutMax) will overflow");
static_assert(kTimeSinceLastTransactionMax * 1000 > kTimeSinceLastTransactionMax,
"SecToMsec(kTimeSinceLastTransactionMax) will overflow");
/**
* State change of Child's DUA
*
+32 -9
View File
@@ -360,27 +360,50 @@ target_link_libraries(test-message-queue
add_test(NAME test-message-queue COMMAND test-message-queue)
add_executable(test-multicast-listeners-table
${COMMON_SOURCES}
test_multicast_listeners_table.cpp
)
${COMMON_SOURCES}
test_multicast_listeners_table.cpp
)
target_include_directories(test-multicast-listeners-table
PRIVATE
PRIVATE
${COMMON_INCLUDES}
)
)
target_compile_options(test-multicast-listeners-table
PRIVATE
PRIVATE
${COMMON_COMPILE_OPTIONS}
)
)
target_link_libraries(test-multicast-listeners-table
PRIVATE
${COMMON_LIBS}
)
)
add_test(NAME test-multicast-listeners-table COMMAND test-multicast-listeners-table)
add_executable(test-ndproxy-table
${COMMON_SOURCES}
test_ndproxy_table.cpp
)
target_include_directories(test-ndproxy-table
PRIVATE
${COMMON_INCLUDES}
)
target_compile_options(test-ndproxy-table
PRIVATE
${COMMON_COMPILE_OPTIONS}
)
target_link_libraries(test-ndproxy-table
PRIVATE
${COMMON_LIBS}
)
add_test(NAME test-ndproxy-table COMMAND test-ndproxy-table)
add_executable(test-netif
${COMMON_SOURCES}
@@ -559,7 +582,7 @@ target_link_libraries(test-timer
add_test(NAME test-timer COMMAND test-timer)
set_target_properties(
test-aes test-checksum test-child test-child-table test-flash test-heap test-hmac-sha256 test-ip6-address test-link-quality test-linked-list test-lowpan test-mac-frame test-message test-message-queue test-multicast-listeners-table test-netif test-network-data test-pool test-priority-queue test-pskc test-steering-data test-string test-timer
test-aes test-checksum test-child test-child-table test-flash test-heap test-hmac-sha256 test-ip6-address test-link-quality test-linked-list test-lowpan test-mac-frame test-message test-message-queue test-multicast-listeners-table test-ndproxy-table test-netif test-network-data test-pool test-priority-queue test-pskc test-steering-data test-string test-timer
PROPERTIES
C_STANDARD 99
CXX_STANDARD 11
+4
View File
@@ -121,6 +121,7 @@ check_PROGRAMS += \
test-message \
test-message-queue \
test-multicast-listeners-table \
test-ndproxy-table \
test-netif \
test-network-data \
test-pool \
@@ -220,6 +221,9 @@ test_multicast_listeners_table_SOURCES = $(COMMON_SOURCES) test_multicast_listen
test_spinel_buffer_LDADD = $(COMMON_LDADD)
test_spinel_buffer_SOURCES = $(COMMON_SOURCES) test_spinel_buffer.cpp
test_ndproxy_table_LDADD = $(COMMON_LDADD)
test_ndproxy_table_SOURCES = $(COMMON_SOURCES) test_ndproxy_table.cpp
test_netif_LDADD = $(COMMON_LDADD)
test_netif_SOURCES = $(COMMON_SOURCES) test_netif.cpp
+123
View File
@@ -0,0 +1,123 @@
/*
* Copyright (c) 2020, 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 "openthread-core-config.h"
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
#include "test_platform.h"
#include <openthread/config.h>
#include <openthread/ip6.h>
#include "test_util.h"
#include "backbone_router/ndproxy_table.hpp"
#include "common/code_utils.hpp"
#include "common/instance.hpp"
namespace ot {
static ot::Instance *sInstance;
using namespace ot::BackboneRouter;
Ip6::InterfaceIdentifier generateRandomIid(uint16_t aIndex)
{
Ip6::InterfaceIdentifier iid;
Random::NonCrypto::FillBuffer(iid.mFields.m8, sizeof(iid));
iid.mFields.m16[3] = aIndex;
return iid;
}
void TestNdProxyTable(void)
{
otError error;
sInstance = testInitInstance();
VerifyOrQuit(sInstance != nullptr, "Null OpenThread instance");
BackboneRouter::NdProxyTable &table = sInstance->Get<BackboneRouter::NdProxyTable>();
Ip6::InterfaceIdentifier existedAddressIid = generateRandomIid(0);
Ip6::InterfaceIdentifier existedMeshLocalIid = generateRandomIid(0);
Ip6::InterfaceIdentifier notExistAddressIid = generateRandomIid(OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM);
Ip6::InterfaceIdentifier notExistMeshLocalIid = generateRandomIid(OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM);
// Reregister address IID when there are enough room should succeed.
error = table.Register(existedAddressIid, existedMeshLocalIid, 0, nullptr);
VerifyOrQuit(error == OT_ERROR_NONE, "Register failed");
VerifyOrQuit(table.IsRegistered(existedAddressIid), "should be registered");
VerifyOrQuit(!table.IsRegistered(notExistAddressIid), "should not be registered");
for (uint16_t i = 1; i < OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM; i++)
{
Ip6::InterfaceIdentifier addressIid = generateRandomIid(i);
Ip6::InterfaceIdentifier meshLocalIid = generateRandomIid(i);
// Reregister address IID when there are enough room should succeed.
error = table.Register(addressIid, meshLocalIid, i, nullptr);
VerifyOrQuit(error == OT_ERROR_NONE, "Register failed");
VerifyOrQuit(table.IsRegistered(addressIid), "should be registered");
// Reregister the same address IID should always succeed.
error = table.Register(addressIid, meshLocalIid, i, nullptr);
VerifyOrQuit(error == OT_ERROR_NONE, "Register again failed");
// Register the same address IID with a different ML-IID should fail.
error = table.Register(addressIid, notExistMeshLocalIid, i, nullptr);
VerifyOrQuit(error == OT_ERROR_DUPLICATED, "Register duplicate should fail");
VerifyOrQuit(table.IsRegistered(addressIid), "should be registered");
}
// Now the table is full, registering another IID should fail.
error =
table.Register(notExistAddressIid, notExistMeshLocalIid, OPENTHREAD_CONFIG_NDPROXY_TABLE_ENTRY_NUM, nullptr);
VerifyOrQuit(error == OT_ERROR_NO_BUFS, "should fail with no bufs");
VerifyOrQuit(!table.IsRegistered(notExistAddressIid), "should not be registered");
}
} // namespace ot
int main(void)
{
ot::TestNdProxyTable();
printf("\nAll tests passed.\n");
return 0;
}
#else
int main(void)
{
return 0;
}
#endif