diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 3517b85f1fd..6cbcf9d4e91 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -52,7 +52,7 @@ extern "C" { * * @note This number versions both OpenThread platform and user APIs. */ -#define OPENTHREAD_API_VERSION (468) +#define OPENTHREAD_API_VERSION (469) /** * @addtogroup api-instance diff --git a/include/openthread/netdata_publisher.h b/include/openthread/netdata_publisher.h index ef9665cc6da..3a181cda89e 100644 --- a/include/openthread/netdata_publisher.h +++ b/include/openthread/netdata_publisher.h @@ -100,8 +100,9 @@ typedef void (*otNetDataPrefixPublisherCallback)(otNetDataPublisherEvent aEvent, * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aSequenceNUmber The sequence number of DNS/SRP Anycast Service. + * @param[in] aVersion The version number to publish. */ -void otNetDataPublishDnsSrpServiceAnycast(otInstance *aInstance, uint8_t aSequenceNUmber); +void otNetDataPublishDnsSrpServiceAnycast(otInstance *aInstance, uint8_t aSequenceNUmber, uint8_t aVersion); /** * Requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data. @@ -117,8 +118,12 @@ void otNetDataPublishDnsSrpServiceAnycast(otInstance *aInstance, uint8_t aSequen * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aAddress The DNS/SRP server address to publish (MUST NOT be NULL). * @param[in] aPort The SRP server port number to publish. + * @param[in] aVersion The version number to publish. */ -void otNetDataPublishDnsSrpServiceUnicast(otInstance *aInstance, const otIp6Address *aAddress, uint16_t aPort); +void otNetDataPublishDnsSrpServiceUnicast(otInstance *aInstance, + const otIp6Address *aAddress, + uint16_t aPort, + uint8_t aVersion); /** * Requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data. @@ -134,8 +139,9 @@ void otNetDataPublishDnsSrpServiceUnicast(otInstance *aInstance, const otIp6Addr * * @param[in] aInstance A pointer to an OpenThread instance. * @param[in] aPort The SRP server port number to publish. + * @param[in] aVersion The version number to publish. */ -void otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(otInstance *aInstance, uint16_t aPort); +void otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(otInstance *aInstance, uint16_t aPort, uint8_t aVersion); /** * Indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data. diff --git a/src/cli/README_NETDATA.md b/src/cli/README_NETDATA.md index 5deeb776298..824b548acb2 100644 --- a/src/cli/README_NETDATA.md +++ b/src/cli/README_NETDATA.md @@ -254,20 +254,20 @@ This command requires `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE`. The following formats are available: : -- `netdata publish dnssrp anycast ` to publish "DNS/SRP Service Anycast Address" with a given sequence number. -- `netdata publish dnssrp unicast
` to publish "DNS/SRP Service Unicast Address" with given address and port number info. The address/port info is included in Service TLV data. -- `netdata publish dnssrp unicast ` to publish "DNS/SRP Service Unicast Address" with given port number and the device's mesh-local EID for the address. The address and port info is included in Server TLV data. +- `netdata publish dnssrp anycast []` to publish "DNS/SRP Service Anycast Address" with a given sequence number and version. +- `netdata publish dnssrp unicast
[]` to publish "DNS/SRP Service Unicast Address" with given address, port number and version info. The address/port/version info is included in Service TLV data. +- `netdata publish dnssrp unicast []` to publish "DNS/SRP Service Unicast Address" with given port number, version, and the device's mesh-local EID for the address. The address/port/version info is included in Server TLV data. A new call to `netdata publish dnssrp [anycast|unicast] [...]` command will remove and replace any previous "DNS/SRP Service" entry that was being published (from earlier `netdata publish dnssrp [...]` commands). ```bash -> netdata publish dnssrp anycast 1 +> netdata publish dnssrp anycast 1 2 Done -> netdata publish dnssrp unicast fd00::1234 51525 +> netdata publish dnssrp unicast fd00::1234 51525 1 Done -> netdata publish dnssrp unicast 50152 +> netdata publish dnssrp unicast 50152 2 Done ``` diff --git a/src/cli/cli_network_data.cpp b/src/cli/cli_network_data.cpp index 629b59f20ef..1a85ddfcd47 100644 --- a/src/cli/cli_network_data.cpp +++ b/src/cli/cli_network_data.cpp @@ -244,17 +244,17 @@ template <> otError NetworkData::Process(Arg aArgs[]) /** * @cli netdata publish dnssrp anycast * @code - * netdata publish dnssrp anycast 1 + * netdata publish dnssrp anycast 1 1 * Done * @endcode - * @cparam netdata publish dnssrp anycast @ca{seq-num} + * @cparam netdata publish dnssrp anycast @ca{seq-num} [@ca{version}] * @par - * Publishes a DNS/SRP Service Anycast Address with a sequence number. Any current - * DNS/SRP Service entry being published from a previous `publish dnssrp{anycast|unicast}` + * Publishes a DNS/SRP Service Anycast Address with a sequence number and version. Any current + * DNS/SRP Service entry being published from a previous `publish dnssrp {anycast|unicast}` * command is removed and replaced with the new arguments. * @par * `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled. - * @csa{netdata publish dnssrp unicast (addr,port)} + * @csa{netdata publish dnssrp unicast (addr,port,version)} * @csa{netdata publish dnssrp unicast (mle)} * @sa otNetDataPublishDnsSrpServiceAnycast * @endcli @@ -262,55 +262,83 @@ template <> otError NetworkData::Process(Arg aArgs[]) if (aArgs[1] == "anycast") { uint8_t sequenceNumber; + uint8_t version = 0; SuccessOrExit(error = aArgs[2].ParseAsUint8(sequenceNumber)); - otNetDataPublishDnsSrpServiceAnycast(GetInstancePtr(), sequenceNumber); + + if (!aArgs[3].IsEmpty()) + { + SuccessOrExit(error = aArgs[3].ParseAsUint8(version)); + VerifyOrExit(aArgs[4].IsEmpty(), error = OT_ERROR_INVALID_ARGS); + } + + otNetDataPublishDnsSrpServiceAnycast(GetInstancePtr(), sequenceNumber, version); ExitNow(); } if (aArgs[1] == "unicast") { otIp6Address address; + bool hasAddress = false; uint16_t port; + uint8_t version = 0; + + aArgs += 2; + + if (aArgs->ParseAsIp6Address(address) == kErrorNone) + { + hasAddress = true; + aArgs++; + } + + SuccessOrExit(error = aArgs->ParseAsUint16(port)); + aArgs++; + + if (!aArgs->IsEmpty()) + { + SuccessOrExit(error = aArgs->ParseAsUint8(version)); + aArgs++; + } + + VerifyOrExit(aArgs->IsEmpty(), error = kErrorInvalidArgs); /** * @cli netdata publish dnssrp unicast (mle) * @code - * netdata publish dnssrp unicast 50152 + * netdata publish dnssrp unicast 50152 1 * Done * @endcode - * @cparam netdata publish dnssrp unicast @ca{port} + * @cparam netdata publish dnssrp unicast @ca{port} [@ca{version}] * @par - * Publishes the device's Mesh-Local EID with a port number. MLE and port information is - * included in the Server TLV data. To use a different Unicast address, use the - * `netdata publish dnssrp unicast (addr,port)` command. + * Publishes the device's Mesh-Local EID with a port number and given version. MLE, port and version + * information is included in the Server TLV data. To use a different Unicast address, use the + * `netdata publish dnssrp unicast (addr,port,version)` command. * @par * Any current DNS/SRP Service entry being published from a previous - * `publish dnssrp{anycast|unicast}` command is removed and replaced with the new arguments. + * `publish dnssrp {anycast|unicast}` command is removed and replaced with the new arguments. * @par * `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled. - * @csa{netdata publish dnssrp unicast (addr,port)} + * @csa{netdata publish dnssrp unicast (addr,port,version)} * @csa{netdata publish dnssrp anycast} * @sa otNetDataPublishDnsSrpServiceUnicastMeshLocalEid */ - if (aArgs[3].IsEmpty()) + if (!hasAddress) { - SuccessOrExit(error = aArgs[2].ParseAsUint16(port)); - otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(GetInstancePtr(), port); + otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(GetInstancePtr(), port, version); ExitNow(); } /** - * @cli netdata publish dnssrp unicast (addr,port) + * @cli netdata publish dnssrp unicast (addr,port,version) * @code - * netdata publish dnssrp unicast fd00::1234 51525 + * netdata publish dnssrp unicast fd00::1234 51525 1 * Done * @endcode - * @cparam netdata publish dnssrp unicast @ca{address} @ca{port} + * @cparam netdata publish dnssrp unicast @ca{address} @ca{port} [@ca{version}] * @par - * Publishes a DNS/SRP Service Unicast Address with an address and port number. The address - * and port information is included in Service TLV data. Any current DNS/SRP Service entry being - * published from a previous `publish dnssrp{anycast|unicast}` command is removed and replaced + * Publishes a DNS/SRP Service Unicast Address with an address and port and version number. The address, + * port, and version information is included in Service TLV data. Any current DNS/SRP Service entry being + * published from a previous `publish dnssrp {anycast|unicast}` command is removed and replaced * with the new arguments. * @par * `OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE` must be enabled. @@ -318,9 +346,7 @@ template <> otError NetworkData::Process(Arg aArgs[]) * @csa{netdata publish dnssrp anycast} * @sa otNetDataPublishDnsSrpServiceUnicast */ - SuccessOrExit(error = aArgs[2].ParseAsIp6Address(address)); - SuccessOrExit(error = aArgs[3].ParseAsUint16(port)); - otNetDataPublishDnsSrpServiceUnicast(GetInstancePtr(), &address, port); + otNetDataPublishDnsSrpServiceUnicast(GetInstancePtr(), &address, port, version); ExitNow(); } } diff --git a/src/core/api/netdata_publisher_api.cpp b/src/core/api/netdata_publisher_api.cpp index 92e3ad4dc1f..8da62cd6a6a 100644 --- a/src/core/api/netdata_publisher_api.cpp +++ b/src/core/api/netdata_publisher_api.cpp @@ -41,19 +41,23 @@ using namespace ot; #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE -void otNetDataPublishDnsSrpServiceAnycast(otInstance *aInstance, uint8_t aSequenceNumber) +void otNetDataPublishDnsSrpServiceAnycast(otInstance *aInstance, uint8_t aSequenceNumber, uint8_t aVersion) { - AsCoreType(aInstance).Get().PublishDnsSrpServiceAnycast(aSequenceNumber); + AsCoreType(aInstance).Get().PublishDnsSrpServiceAnycast(aSequenceNumber, aVersion); } -void otNetDataPublishDnsSrpServiceUnicast(otInstance *aInstance, const otIp6Address *aAddress, uint16_t aPort) +void otNetDataPublishDnsSrpServiceUnicast(otInstance *aInstance, + const otIp6Address *aAddress, + uint16_t aPort, + uint8_t aVersion) { - AsCoreType(aInstance).Get().PublishDnsSrpServiceUnicast(AsCoreType(aAddress), aPort); + AsCoreType(aInstance).Get().PublishDnsSrpServiceUnicast(AsCoreType(aAddress), aPort, + aVersion); } -void otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(otInstance *aInstance, uint16_t aPort) +void otNetDataPublishDnsSrpServiceUnicastMeshLocalEid(otInstance *aInstance, uint16_t aPort, uint8_t aVersion) { - AsCoreType(aInstance).Get().PublishDnsSrpServiceUnicast(aPort); + AsCoreType(aInstance).Get().PublishDnsSrpServiceUnicast(aPort, aVersion); } bool otNetDataIsDnsSrpServiceAdded(otInstance *aInstance) diff --git a/src/core/net/srp_client.cpp b/src/core/net/srp_client.cpp index 7391d0b5389..45136039214 100644 --- a/src/core/net/srp_client.cpp +++ b/src/core/net/srp_client.cpp @@ -2412,6 +2412,8 @@ Error Client::SelectUnicastEntry(DnsSrpUnicastType aType, DnsSrpUnicastInfo &aIn while (Get().GetNextDnsSrpUnicastInfo(iterator, aType, unicastInfo) == kErrorNone) { + bool preferNewEntry; + if (mAutoStart.HasSelectedServer() && (GetServerAddress() == unicastInfo.mSockAddr)) { aInfo = unicastInfo; @@ -2431,10 +2433,17 @@ Error Client::SelectUnicastEntry(DnsSrpUnicastType aType, DnsSrpUnicastInfo &aIn ExitNow(); } #endif + // Prefer the server with higher version number, if equal + // then pick the one with numerically smaller IPv6 address. + + preferNewEntry = (error == kErrorNotFound) || (unicastInfo.mVersion > aInfo.mVersion); - // Prefer the numerically lowest server address + if (!preferNewEntry && (unicastInfo.mVersion == aInfo.mVersion)) + { + preferNewEntry = (unicastInfo.mSockAddr.GetAddress() < aInfo.mSockAddr.GetAddress()); + } - if ((error == kErrorNotFound) || (unicastInfo.mSockAddr.GetAddress() < aInfo.mSockAddr.GetAddress())) + if (preferNewEntry) { aInfo = unicastInfo; error = kErrorNone; diff --git a/src/core/net/srp_server.cpp b/src/core/net/srp_server.cpp index 1501595e78b..609eeb12e1e 100644 --- a/src/core/net/srp_server.cpp +++ b/src/core/net/srp_server.cpp @@ -149,12 +149,12 @@ void Server::Enable(void) { case kAddressModeUnicast: SelectPort(); - Get().PublishDnsSrpServiceUnicast(mPort); + Get().PublishDnsSrpServiceUnicast(mPort, kSrpVersion); break; case kAddressModeAnycast: mPort = kAnycastAddressModePort; - Get().PublishDnsSrpServiceAnycast(mAnycastSequenceNumber); + Get().PublishDnsSrpServiceAnycast(mAnycastSequenceNumber, kSrpVersion); break; } diff --git a/src/core/net/srp_server.hpp b/src/core/net/srp_server.hpp index ef0ae0b969b..d77e60088ef 100644 --- a/src/core/net/srp_server.hpp +++ b/src/core/net/srp_server.hpp @@ -832,6 +832,8 @@ class Server : public InstanceLocator, private NonCopyable void HandleServiceUpdateResult(ServiceUpdateId aId, Error aError); private: + static constexpr uint8_t kSrpVersion = 0; + static constexpr uint16_t kUdpPayloadSize = Ip6::kMaxDatagramLength - sizeof(Ip6::Udp::Header); static constexpr uint32_t kDefaultMinLease = 30; // 30 seconds. diff --git a/src/core/thread/network_data_publisher.cpp b/src/core/thread/network_data_publisher.cpp index 3977ad19468..de7d67237dd 100644 --- a/src/core/thread/network_data_publisher.cpp +++ b/src/core/thread/network_data_publisher.cpp @@ -490,22 +490,23 @@ const char *Publisher::Entry::StateToString(State aState) Publisher::DnsSrpServiceEntry::DnsSrpServiceEntry(Instance &aInstance) { Init(aInstance); } -void Publisher::DnsSrpServiceEntry::PublishAnycast(uint8_t aSequenceNumber) +void Publisher::DnsSrpServiceEntry::PublishAnycast(uint8_t aSequenceNumber, uint8_t aVersion) { - LogInfo("Publishing DNS/SRP service anycast (seq-num:%d)", aSequenceNumber); - Publish(Info::InfoAnycast(aSequenceNumber)); + LogInfo("Publishing DNS/SRP service anycast (seq-num:%u, ver:%u)", aSequenceNumber, aVersion); + Publish(Info::InfoAnycast(aSequenceNumber, aVersion)); } -void Publisher::DnsSrpServiceEntry::PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort) +void Publisher::DnsSrpServiceEntry::PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) { - LogInfo("Publishing DNS/SRP service unicast (%s, port:%d)", aAddress.ToString().AsCString(), aPort); - Publish(Info::InfoUnicast(kTypeUnicast, aAddress, aPort)); + LogInfo("Publishing DNS/SRP service unicast (%s, port:%u, ver:%u)", aAddress.ToString().AsCString(), aPort, + aVersion); + Publish(Info::InfoUnicast(kTypeUnicast, aAddress, aPort, aVersion)); } -void Publisher::DnsSrpServiceEntry::PublishUnicast(uint16_t aPort) +void Publisher::DnsSrpServiceEntry::PublishUnicast(uint16_t aPort, uint8_t aVersion) { - LogInfo("Publishing DNS/SRP service unicast (ml-eid, port:%d)", aPort); - Publish(Info::InfoUnicast(kTypeUnicastMeshLocalEid, Get().GetMeshLocalEid(), aPort)); + LogInfo("Publishing DNS/SRP service unicast (ml-eid, port:%u, ver:%u)", aPort, aVersion); + Publish(Info::InfoUnicast(kTypeUnicastMeshLocalEid, Get().GetMeshLocalEid(), aPort, aVersion)); } void Publisher::DnsSrpServiceEntry::Publish(const Info &aInfo) @@ -568,17 +569,17 @@ void Publisher::DnsSrpServiceEntry::Add(void) switch (GetType()) { case kTypeAnycast: - SuccessOrExit(Get().AddDnsSrpAnycastService(mInfo.GetSequenceNumber())); + SuccessOrExit(Get().AddDnsSrpAnycastService(mInfo.GetSequenceNumber(), mInfo.GetVersion())); break; case kTypeUnicast: - SuccessOrExit( - Get().AddDnsSrpUnicastServiceWithAddrInServiceData(mInfo.GetAddress(), mInfo.GetPort())); + SuccessOrExit(Get().AddDnsSrpUnicastServiceWithAddrInServiceData( + mInfo.GetAddress(), mInfo.GetPort(), mInfo.GetVersion())); break; case kTypeUnicastMeshLocalEid: - SuccessOrExit( - Get().AddDnsSrpUnicastServiceWithAddrInServerData(mInfo.GetAddress(), mInfo.GetPort())); + SuccessOrExit(Get().AddDnsSrpUnicastServiceWithAddrInServerData( + mInfo.GetAddress(), mInfo.GetPort(), mInfo.GetVersion())); break; } @@ -603,8 +604,8 @@ void Publisher::DnsSrpServiceEntry::Remove(State aNextState) break; case kTypeUnicast: - SuccessOrExit(Get().RemoveDnsSrpUnicastServiceWithAddrInServiceData(mInfo.GetAddress(), - mInfo.GetPort())); + SuccessOrExit(Get().RemoveDnsSrpUnicastServiceWithAddrInServiceData( + mInfo.GetAddress(), mInfo.GetPort(), mInfo.GetVersion())); break; case kTypeUnicastMeshLocalEid: @@ -683,19 +684,22 @@ void Publisher::DnsSrpServiceEntry::CountAnycastEntries(uint8_t &aNumEntries, ui { // Count the number of matching "DNS/SRP Anycast" service entries // in the Network Data (the match requires the entry to use same - // "sequence number" value). We prefer the entries associated with - // smaller RLCO16. + // "sequence number" value and same or higher version value). An + // entry with higher version number is preferred. If versions + // are equal then the associated RLOC16 values are used + // (routers are preferred over end-devices. If same type, then + // the smaller RLOC16 value is preferred). Service::Manager::Iterator iterator; Service::DnsSrpAnycastInfo anycastInfo; while (Get().GetNextDnsSrpAnycastInfo(iterator, anycastInfo) == kErrorNone) { - if (anycastInfo.mSequenceNumber == mInfo.GetSequenceNumber()) + if (anycastInfo.mSequenceNumber == mInfo.GetSequenceNumber() && (anycastInfo.mVersion >= mInfo.GetVersion())) { aNumEntries++; - if (IsPreferred(anycastInfo.mRloc16)) + if ((anycastInfo.mVersion > mInfo.GetVersion()) || IsPreferred(anycastInfo.mRloc16)) { aNumPreferredEntries++; } @@ -716,17 +720,25 @@ void Publisher::DnsSrpServiceEntry::CountUnicastEntries(Service::DnsSrpUnicastTy uint8_t &aNumPreferredEntries) const { // Count the number of DNS/SRP unicast entries in the Network Data. + // Only entries with the same or higher version number are considered. + // An entry with higher version is preferred. If versions are equal + // then the associated RLOC16 values are used (routers are preferred + // over end-devices. If same type, then the smaller RLOC16 value is + // preferred). Service::Manager::Iterator iterator; Service::DnsSrpUnicastInfo unicastInfo; while (Get().GetNextDnsSrpUnicastInfo(iterator, aType, unicastInfo) == kErrorNone) { - aNumEntries++; - - if (IsPreferred(unicastInfo.mRloc16)) + if (unicastInfo.mVersion >= mInfo.GetVersion()) { - aNumPreferredEntries++; + aNumEntries++; + + if ((unicastInfo.mVersion > mInfo.GetVersion()) || IsPreferred(unicastInfo.mRloc16)) + { + aNumPreferredEntries++; + } } } } @@ -743,9 +755,10 @@ bool Publisher::DnsSrpServiceEntry::HasAnyServiceDataUnicastEntry(void) const //--------------------------------------------------------------------------------------------------------------------- // Publisher::DnsSrpServiceEntry::Info -Publisher::DnsSrpServiceEntry::Info::Info(Type aType, uint16_t aPortOrSeqNumber, const Ip6::Address *aAddress) - : mPortOrSeqNumber(aPortOrSeqNumber) - , mType(aType) +Publisher::DnsSrpServiceEntry::Info::Info(Type aType, + uint16_t aPortOrSeqNumber, + uint8_t aVersion, + const Ip6::Address *aAddress) { // It is important to `Clear()` the object since we compare all // bytes using overload of operator `==`. @@ -754,6 +767,7 @@ Publisher::DnsSrpServiceEntry::Info::Info(Type aType, uint16_t aPortOrSeqNumber, mType = aType; mPortOrSeqNumber = aPortOrSeqNumber; + mVersion = aVersion; if (aAddress != nullptr) { diff --git a/src/core/thread/network_data_publisher.hpp b/src/core/thread/network_data_publisher.hpp index 50f2d95546b..e8423372da8 100644 --- a/src/core/thread/network_data_publisher.hpp +++ b/src/core/thread/network_data_publisher.hpp @@ -131,8 +131,12 @@ class Publisher : public InstanceLocator, private NonCopyable * (from earlier call to any of `PublishDnsSrpService{Type}()` methods). * * @param[in] aSequenceNumber The sequence number of DNS/SRP Anycast Service. + * @param[in] aVersion The version number of DNS/SRP service. */ - void PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber) { mDnsSrpServiceEntry.PublishAnycast(aSequenceNumber); } + void PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber, uint8_t aVersion) + { + mDnsSrpServiceEntry.PublishAnycast(aSequenceNumber, aVersion); + } /** * Requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data. @@ -145,10 +149,11 @@ class Publisher : public InstanceLocator, private NonCopyable * * @param[in] aAddress The DNS/SRP server address to publish. * @param[in] aPort The SRP server port number to publish. + * @param[in] aVersion The SRP server version to publish. */ - void PublishDnsSrpServiceUnicast(const Ip6::Address &aAddress, uint16_t aPort) + void PublishDnsSrpServiceUnicast(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) { - mDnsSrpServiceEntry.PublishUnicast(aAddress, aPort); + mDnsSrpServiceEntry.PublishUnicast(aAddress, aPort, aVersion); } /** @@ -162,8 +167,12 @@ class Publisher : public InstanceLocator, private NonCopyable * in the Server TLV data. * * @param[in] aPort The SRP server port number to publish. + * @param[in] aVersion The SRP server version to publish. */ - void PublishDnsSrpServiceUnicast(uint16_t aPort) { mDnsSrpServiceEntry.PublishUnicast(aPort); } + void PublishDnsSrpServiceUnicast(uint16_t aPort, uint8_t aVersion) + { + mDnsSrpServiceEntry.PublishUnicast(aPort, aVersion); + } /** * Indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data. @@ -365,9 +374,9 @@ class Publisher : public InstanceLocator, private NonCopyable public: explicit DnsSrpServiceEntry(Instance &aInstance); void SetCallback(DnsSrpServiceCallback aCallback, void *aContext) { mCallback.Set(aCallback, aContext); } - void PublishAnycast(uint8_t aSequenceNumber); - void PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort); - void PublishUnicast(uint16_t aPort); + void PublishAnycast(uint8_t aSequenceNumber, uint8_t aVersion); + void PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion); + void PublishUnicast(uint16_t aPort, uint8_t aVersion); void Unpublish(void); void HandleTimer(void) { Entry::HandleTimer(); } void HandleNotifierEvents(Events aEvents); @@ -393,20 +402,25 @@ class Publisher : public InstanceLocator, private NonCopyable Type GetType(void) const { return mType; } uint8_t GetSequenceNumber(void) const { return static_cast(mPortOrSeqNumber); } uint16_t GetPort(void) const { return mPortOrSeqNumber; } + uint8_t GetVersion(void) const { return mVersion; } const Ip6::Address &GetAddress(void) const { return mAddress; } void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; } - static Info InfoAnycast(uint8_t aSequenceNumber) { return Info(kTypeAnycast, aSequenceNumber); } - static Info InfoUnicast(Type aType, const Ip6::Address &aAddress, uint16_t aPort) + static Info InfoAnycast(uint8_t aSequenceNumber, uint8_t aVersion) + { + return Info(kTypeAnycast, aSequenceNumber, aVersion); + } + static Info InfoUnicast(Type aType, const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) { - return Info(aType, aPort, &aAddress); + return Info(aType, aPort, aVersion, &aAddress); } private: - Info(Type aType, uint16_t aPortOrSeqNumber, const Ip6::Address *aAddress = nullptr); + Info(Type aType, uint16_t aPortOrSeqNumber, uint8_t aVersion, const Ip6::Address *aAddress = nullptr); Ip6::Address mAddress; uint16_t mPortOrSeqNumber; + uint8_t mVersion; Type mType; }; diff --git a/src/core/thread/network_data_service.cpp b/src/core/thread/network_data_service.cpp index 0b621cfa9f2..dc706ceabbf 100644 --- a/src/core/thread/network_data_service.cpp +++ b/src/core/thread/network_data_service.cpp @@ -41,6 +41,13 @@ namespace Service { #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE +Error Manager::AddDnsSrpAnycastService(uint8_t aSequenceNumber, uint8_t aVersion) +{ + DnsSrpAnycastServiceData anycastData(aSequenceNumber); + + return (aVersion == 0) ? AddService(anycastData) : AddService(anycastData, aVersion); +} + Error Manager::AddService(const void *aServiceData, uint8_t aServiceDataLength, const void *aServerData, @@ -163,16 +170,19 @@ Error Manager::GetNextDnsSrpAnycastInfo(Iterator &aIterator, DnsSrpAnycastInfo & if (IterateToNextServer(aIterator) == kErrorNone) { - aIterator.mServiceTlv->GetServiceData(serviceData); + uint8_t dataLength = aIterator.mServiceTlv->GetServiceDataLength(); - if (serviceData.GetLength() >= sizeof(DnsSrpAnycastServiceData)) + if (dataLength >= sizeof(DnsSrpAnycastServiceData)) { - const DnsSrpAnycastServiceData *dnsServiceData = - reinterpret_cast(serviceData.GetBytes()); + const DnsSrpAnycastServiceData *anycastData = + reinterpret_cast(aIterator.mServiceTlv->GetServiceData()); Get().GetServiceAloc(aIterator.mServiceTlv->GetServiceId(), aInfo.mAnycastAddress); - aInfo.mSequenceNumber = dnsServiceData->GetSequenceNumber(); + aInfo.mSequenceNumber = anycastData->GetSequenceNumber(); aInfo.mRloc16 = aIterator.mServerSubTlv->GetServer16(); + aInfo.mVersion = (aIterator.mServerSubTlv->GetServerDataLength() >= sizeof(uint8_t)) + ? *aIterator.mServerSubTlv->GetServerData() + : 0; ExitNow(); } } @@ -257,6 +267,34 @@ Error Manager::FindPreferredDnsSrpAnycastInfo(DnsSrpAnycastInfo &aInfo) const } } + // Determine the minimum version supported among all entries + // matching the selected `aInfo.mSequenceNumber`. + + iterator.Reset(); + + while (GetNextDnsSrpAnycastInfo(iterator, info) == kErrorNone) + { + if (info.mSequenceNumber == aInfo.mSequenceNumber) + { + aInfo.mVersion = Min(aInfo.mVersion, info.mVersion); + } + } + +exit: + return error; +} + +Error Manager::DnsSrpUnicast::AddrData::ParseFrom(const uint8_t *aData, uint8_t aLength, DnsSrpUnicastInfo &aInfo) +{ + Error error = kErrorNone; + const AddrData *addrData = reinterpret_cast(aData); + + VerifyOrExit(aLength >= kMinLength, error = kErrorParse); + + aInfo.mSockAddr.SetAddress(addrData->GetAddress()); + aInfo.mSockAddr.SetPort(addrData->GetPort()); + aInfo.mVersion = (aLength >= sizeof(AddrData)) ? addrData->GetVersion() : 0; + exit: return error; } @@ -274,26 +312,21 @@ Error Manager::GetNextDnsSrpUnicastInfo(Iterator &aIterator, DnsSrpUnicastType a while (IterateToNextServer(aIterator) == kErrorNone) { - ServerData data; + aInfo.mRloc16 = aIterator.mServerSubTlv->GetServer16(); if (aType == kAddrInServiceData) { - const DnsSrpUnicast::ServiceData *dnsServiceData; - - if (aIterator.mServiceTlv->GetServiceDataLength() < sizeof(DnsSrpUnicast::ServiceData)) + if (DnsSrpUnicast::ServiceData::ParseFrom(*aIterator.mServiceTlv, aInfo) == kErrorNone) { - // Break from `while(IterateToNextServer())` loop - // to skip over the Service TLV and all its - // sub-TLVs and go to the next one. - break; + ExitNow(); } - aIterator.mServiceTlv->GetServiceData(serviceData); - dnsServiceData = reinterpret_cast(serviceData.GetBytes()); - aInfo.mSockAddr.SetAddress(dnsServiceData->GetAddress()); - aInfo.mSockAddr.SetPort(dnsServiceData->GetPort()); - aInfo.mRloc16 = aIterator.mServerSubTlv->GetServer16(); - ExitNow(); + // If Service Data does not contain address info, we + // break from `while (IterateToNextServer())` loop + // to skip over the entire Service TLV and all its + // sub-TLVs and go to the next one. + + break; } // `aType` is `kAddrInServerData`. @@ -302,28 +335,21 @@ Error Manager::GetNextDnsSrpUnicastInfo(Iterator &aIterator, DnsSrpUnicastType a // (then we parse and return the info), or it can be // empty (then we skip over it). - aIterator.mServerSubTlv->GetServerData(data); - - if (data.GetLength() >= sizeof(DnsSrpUnicast::ServerData)) + if (DnsSrpUnicast::ServerData::ParseFrom(*aIterator.mServerSubTlv, aInfo) == kErrorNone) { - const DnsSrpUnicast::ServerData *serverData = - reinterpret_cast(data.GetBytes()); - - aInfo.mSockAddr.SetAddress(serverData->GetAddress()); - aInfo.mSockAddr.SetPort(serverData->GetPort()); - aInfo.mRloc16 = aIterator.mServerSubTlv->GetServer16(); ExitNow(); } - if (data.GetLength() == sizeof(uint16_t)) + if (aIterator.mServerSubTlv->GetServerDataLength() == sizeof(uint16_t)) { // Handle the case where the server TLV data only // contains a port number and use the RLOC as the // IPv6 address. + aInfo.mSockAddr.GetAddress().SetToRoutingLocator(Get().GetMeshLocalPrefix(), aIterator.mServerSubTlv->GetServer16()); - aInfo.mSockAddr.SetPort(BigEndian::ReadUint16(data.GetBytes())); - aInfo.mRloc16 = aIterator.mServerSubTlv->GetServer16(); + aInfo.mSockAddr.SetPort(BigEndian::ReadUint16(aIterator.mServerSubTlv->GetServerData())); + aInfo.mVersion = 0; ExitNow(); } } diff --git a/src/core/thread/network_data_service.hpp b/src/core/thread/network_data_service.hpp index f56c421b27f..7bfc324d231 100644 --- a/src/core/thread/network_data_service.hpp +++ b/src/core/thread/network_data_service.hpp @@ -59,6 +59,7 @@ struct DnsSrpAnycastInfo { Ip6::Address mAnycastAddress; ///< The anycast address associated with the DNS/SRP servers. uint8_t mSequenceNumber; ///< Sequence number used to notify SRP client if they need to re-register. + uint8_t mVersion; ///< Version number. uint16_t mRloc16; ///< The RLOC16 of the entry. }; @@ -77,6 +78,7 @@ enum DnsSrpUnicastType : uint8_t struct DnsSrpUnicastInfo { Ip6::SockAddr mSockAddr; ///< The socket address (IPv6 address and port) of the DNS/SRP server. + uint8_t mVersion; ///< Version number. uint16_t mRloc16; ///< The BR RLOC16 adding the entry. }; @@ -132,14 +134,12 @@ class Manager : public InstanceLocator, private NonCopyable * Adds a DNS/SRP Anycast Service entry to the local Thread Network Data. * * @param[in] aSequenceNumber The anycast sequence number. + * @param[in] aVersion The version number * * @retval kErrorNone Successfully added the Service entry. * @retval kErrorNoBufs Insufficient space to add the Service entry. */ - Error AddDnsSrpAnycastService(uint8_t aSequenceNumber) - { - return AddService(DnsSrpAnycastServiceData(aSequenceNumber)); - } + Error AddDnsSrpAnycastService(uint8_t aSequenceNumber, uint8_t aVersion); /** * Removes a DNS/SRP Anycast Service entry from local Thread Network Data. @@ -159,13 +159,14 @@ class Manager : public InstanceLocator, private NonCopyable * * @param[in] aAddress The unicast address. * @param[in] aPort The port number. + * @param[in] aVersion The version. * * @retval kErrorNone Successfully added the Service entry. * @retval kErrorNoBufs Insufficient space to add the Service entry. */ - Error AddDnsSrpUnicastServiceWithAddrInServiceData(const Ip6::Address &aAddress, uint16_t aPort) + Error AddDnsSrpUnicastServiceWithAddrInServiceData(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) { - return AddService(DnsSrpUnicast::ServiceData(aAddress, aPort)); + return AddService(DnsSrpUnicast::ServiceData(aAddress, aPort, aVersion)); } /** @@ -173,13 +174,16 @@ class Manager : public InstanceLocator, private NonCopyable * * @param[in] aAddress The unicast address. * @param[in] aPort The port number. + * @param[in] aVersion The version. * * @retval kErrorNone Successfully removed the Service entry. * @retval kErrorNotFound Could not find the Service entry. */ - Error RemoveDnsSrpUnicastServiceWithAddrInServiceData(const Ip6::Address &aAddress, uint16_t aPort) + Error RemoveDnsSrpUnicastServiceWithAddrInServiceData(const Ip6::Address &aAddress, + uint16_t aPort, + uint8_t aVersion) { - return RemoveService(DnsSrpUnicast::ServiceData(aAddress, aPort)); + return RemoveService(DnsSrpUnicast::ServiceData(aAddress, aPort, aVersion)); } /** @@ -187,13 +191,14 @@ class Manager : public InstanceLocator, private NonCopyable * * @param[in] aAddress The unicast address. * @param[in] aPort The port number. + * @param[in] aVersion The version. * * @retval kErrorNone Successfully added the Service entry. * @retval kErrorNoBufs Insufficient space to add the Service entry. */ - Error AddDnsSrpUnicastServiceWithAddrInServerData(const Ip6::Address &aAddress, uint16_t aPort) + Error AddDnsSrpUnicastServiceWithAddrInServerData(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) { - return AddService(kDnsSrpUnicastServiceNumber, DnsSrpUnicast::ServerData(aAddress, aPort)); + return AddServiceWithNumber(kDnsSrpUnicastServiceNumber, DnsSrpUnicast::ServerData(aAddress, aPort, aVersion)); } /** @@ -217,8 +222,8 @@ class Manager : public InstanceLocator, private NonCopyable */ Error AddBackboneRouterService(uint8_t aSequenceNumber, uint16_t aReregistrationDelay, uint32_t aMlrTimeout) { - return AddService(kBackboneRouterServiceNumber, - BbrServerData(aSequenceNumber, aReregistrationDelay, aMlrTimeout)); + return AddServiceWithNumber(kBackboneRouterServiceNumber, + BbrServerData(aSequenceNumber, aReregistrationDelay, aMlrTimeout)); } /** @@ -275,6 +280,9 @@ class Manager : public InstanceLocator, private NonCopyable * The preferred entry is determined based on the sequence number value where a larger value (in the sense * specified by Serial Number Arithmetic logic in RFC-1982) is considered more recent and therefore preferred. * + * When successfully found, the `aInfo.mVersion` is set to the minimum version among all the entries matching the + * same sequence number as the selected `aInfo.mSequenceNumber`. + * * @param[out] aInfo A reference to `DnsSrpAnycastInfo` to return the info. * * @retval kErrorNone Successfully found the preferred info. @p aInfo is updated. @@ -314,6 +322,7 @@ class Manager : public InstanceLocator, private NonCopyable } uint8_t GetSequenceNumber(void) const { return mSequenceNumber; } + uint8_t GetLength(void) const { return sizeof(DnsSrpAnycastServiceData); } private: uint8_t mServiceNumber; @@ -324,44 +333,89 @@ class Manager : public InstanceLocator, private NonCopyable { public: OT_TOOL_PACKED_BEGIN - struct ServiceData + class AddrData { public: - explicit ServiceData(const Ip6::Address &aAddress, uint16_t aPort) - : mServiceNumber(kDnsSrpUnicastServiceNumber) - , mAddress(aAddress) + static constexpr uint8_t kMinLength = sizeof(Ip6::Address) + sizeof(uint16_t); // Address and port. + + AddrData(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) + : mAddress(aAddress) , mPort(BigEndian::HostSwap16(aPort)) + , mVersion(aVersion) { - OT_UNUSED_VARIABLE(mServiceNumber); } + uint8_t GetLength(void) const { return (mVersion == 0) ? kMinLength : sizeof(AddrData); } const Ip6::Address &GetAddress(void) const { return mAddress; } uint16_t GetPort(void) const { return BigEndian::HostSwap16(mPort); } + uint8_t GetVersion(void) const { return mVersion; } + + static Error ParseFrom(const uint8_t *aData, uint8_t aLength, DnsSrpUnicastInfo &aInfo); private: - uint8_t mServiceNumber; Ip6::Address mAddress; uint16_t mPort; + uint8_t mVersion; + } OT_TOOL_PACKED_END; + + static_assert(AddrData::kMinLength + sizeof(uint8_t) == sizeof(AddrData), + "Update all methods/constants if adding new (optional) fields to `AddrData`."); + + OT_TOOL_PACKED_BEGIN + class ServiceData + { + public: + static constexpr uint8_t kMinLength = sizeof(uint8_t) + AddrData::kMinLength; + + ServiceData(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) + : mServiceNumber(kDnsSrpUnicastServiceNumber) + , mAddrData(aAddress, aPort, aVersion) + { + OT_UNUSED_VARIABLE(mServiceNumber); + } + + uint8_t GetLength(void) const { return sizeof(uint8_t) + mAddrData.GetLength(); } + + static Error ParseFrom(const ServiceTlv &aServiceTlv, DnsSrpUnicastInfo &aInfo) + { + // Skip over `mServiceNumber` field (`uint8_t`)` + return AddrData::ParseFrom(aServiceTlv.GetServiceData() + sizeof(uint8_t), + aServiceTlv.GetServiceDataLength() - sizeof(uint8_t), aInfo); + } + + private: + uint8_t mServiceNumber; + AddrData mAddrData; } OT_TOOL_PACKED_END; + static_assert(ServiceData::kMinLength + sizeof(uint8_t) == sizeof(ServiceData), + "Update all methods/constants if adding new (optional) fields to `ServiceData`."); + OT_TOOL_PACKED_BEGIN class ServerData { public: - ServerData(const Ip6::Address &aAddress, uint16_t aPort) - : mAddress(aAddress) - , mPort(BigEndian::HostSwap16(aPort)) + static constexpr uint8_t kMinLength = AddrData::kMinLength; + + ServerData(const Ip6::Address &aAddress, uint16_t aPort, uint8_t aVersion) + : mAddrData(aAddress, aPort, aVersion) { } - const Ip6::Address &GetAddress(void) const { return mAddress; } - uint16_t GetPort(void) const { return BigEndian::HostSwap16(mPort); } + uint8_t GetLength(void) const { return mAddrData.GetLength(); } + + static Error ParseFrom(const ServerTlv &aServerTlv, DnsSrpUnicastInfo &aInfo) + { + return AddrData::ParseFrom(aServerTlv.GetServerData(), aServerTlv.GetServerDataLength(), aInfo); + } private: - Ip6::Address mAddress; - uint16_t mPort; + AddrData mAddrData; } OT_TOOL_PACKED_END; + static_assert(ServerData::kMinLength + sizeof(uint8_t) == sizeof(ServerData), + "Update all methods/constants if adding new (optional) fields to `ServerData`."); + DnsSrpUnicast(void) = delete; }; @@ -380,6 +434,7 @@ class Manager : public InstanceLocator, private NonCopyable uint8_t GetSequenceNumber(void) const { return mSequenceNumber; } uint16_t GetReregistrationDelay(void) const { return BigEndian::HostSwap16(mReregDelay); } uint32_t GetMlrTimeout(void) const { return BigEndian::HostSwap32(mMlrTimeout); } + uint8_t GetLength(void) const { return sizeof(BbrServerData); } private: uint8_t mSequenceNumber; @@ -391,22 +446,29 @@ class Manager : public InstanceLocator, private NonCopyable #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE template Error AddService(const ServiceDataType &aServiceData) { - return AddService(&aServiceData, sizeof(ServiceDataType), nullptr, 0); + return AddService(&aServiceData, aServiceData.GetLength(), nullptr, 0); + } + + template + Error AddServiceWithNumber(uint8_t aServiceNumber, const ServerDataType &aServerData) + { + return AddService(&aServiceNumber, sizeof(uint8_t), &aServerData, aServerData.GetLength()); } - template Error AddService(uint8_t aServiceNumber, const ServerDataType &aServerData) + template + Error AddService(const ServiceDataType &aServiceData, const ServerDataType &aServerData) { - return AddService(&aServiceNumber, sizeof(uint8_t), &aServerData, sizeof(ServerDataType)); + return AddService(&aServiceData, aServiceData.GetLength(), &aServerData, sizeof(ServerDataType)); } Error AddService(const void *aServiceData, uint8_t aServiceDataLength, - const void *aServerData = nullptr, - uint8_t aServerDataLength = 0); + const void *aServerData, + uint8_t aServerDataLength); template Error RemoveService(const ServiceDataType &aServiceData) { - return RemoveService(&aServiceData, sizeof(ServiceDataType)); + return RemoveService(&aServiceData, aServiceData.GetLength()); } Error RemoveService(uint8_t aServiceNumber) { return RemoveService(&aServiceNumber, sizeof(uint8_t)); } diff --git a/src/core/thread/network_data_tlvs.hpp b/src/core/thread/network_data_tlvs.hpp index db5692da7e1..73fd6cd3a80 100644 --- a/src/core/thread/network_data_tlvs.hpp +++ b/src/core/thread/network_data_tlvs.hpp @@ -1244,6 +1244,17 @@ class ServiceTlv : public NetworkDataTlv aServiceData.Init(GetServiceData(), GetServiceDataLength()); } + /** + * Gets the Service Data bytes. + * + * @returns A pointer to start of the Service Data bytes. + */ + const uint8_t *GetServiceData(void) const + { + return (IsThreadEnterprise() ? &mShared.mServiceDataLengthThreadEnterprise : &mServiceDataLength) + + sizeof(uint8_t); + } + /** * Gets Service Data length. * @@ -1306,12 +1317,6 @@ class ServiceTlv : public NetworkDataTlv private: bool IsThreadEnterprise(void) const { return (mFlagsServiceId & kThreadEnterpriseFlag) != 0; } - const uint8_t *GetServiceData(void) const - { - return (IsThreadEnterprise() ? &mShared.mServiceDataLengthThreadEnterprise : &mServiceDataLength) + - sizeof(uint8_t); - } - uint8_t GetFieldsLength(void) const { // Returns the length of TLV value's common fields (flags, enterprise @@ -1392,6 +1397,13 @@ class ServerTlv : public NetworkDataTlv */ void GetServerData(ServerData &aServerData) const { aServerData.Init(GetServerData(), GetServerDataLength()); } + /** + * Gets the Server Data bytes. + * + * @returns A pointer to start of the Server Data bytes. + */ + const uint8_t *GetServerData(void) const { return reinterpret_cast(this) + sizeof(*this); } + /** * Returns the Server Data length in bytes. * @@ -1424,8 +1436,7 @@ class ServerTlv : public NetworkDataTlv static uint16_t CalculateSize(uint8_t aServerDataLength) { return sizeof(ServerTlv) + aServerDataLength; } private: - const uint8_t *GetServerData(void) const { return reinterpret_cast(this) + sizeof(*this); } - uint8_t *GetServerData(void) { return AsNonConst(AsConst(this)->GetServerData()); } + uint8_t *GetServerData(void) { return AsNonConst(AsConst(this)->GetServerData()); } uint16_t mServer16; } OT_TOOL_PACKED_END; diff --git a/tests/scripts/thread-cert/node.py b/tests/scripts/thread-cert/node.py index 1eb2ed9a380..ced19cff9e2 100755 --- a/tests/scripts/thread-cert/node.py +++ b/tests/scripts/thread-cert/node.py @@ -2515,16 +2515,16 @@ def register_netdata(self): self.send_command('netdata register') self._expect_done() - def netdata_publish_dnssrp_anycast(self, seqnum): - self.send_command(f'netdata publish dnssrp anycast {seqnum}') + def netdata_publish_dnssrp_anycast(self, seqnum, version=0): + self.send_command(f'netdata publish dnssrp anycast {seqnum} {version}') self._expect_done() - def netdata_publish_dnssrp_unicast(self, address, port): - self.send_command(f'netdata publish dnssrp unicast {address} {port}') + def netdata_publish_dnssrp_unicast(self, address, port, version=0): + self.send_command(f'netdata publish dnssrp unicast {address} {port} {version}') self._expect_done() - def netdata_publish_dnssrp_unicast_mleid(self, port): - self.send_command(f'netdata publish dnssrp unicast {port}') + def netdata_publish_dnssrp_unicast_mleid(self, port, version=0): + self.send_command(f'netdata publish dnssrp unicast {port} {version}') self._expect_done() def netdata_unpublish_dnssrp(self): diff --git a/tests/scripts/thread-cert/test_netdata_publisher.py b/tests/scripts/thread-cert/test_netdata_publisher.py index c31ac6e5298..59cdefd9987 100755 --- a/tests/scripts/thread-cert/test_netdata_publisher.py +++ b/tests/scripts/thread-cert/test_netdata_publisher.py @@ -221,7 +221,7 @@ def test(self): self.assertEqual(end_dev.get_state(), 'child') #--------------------------------------------------------------------------------- - # DNS/SRP anycast entries + # DNS/SRP anycast entries - equal version number # Publish DNS/SRP anycast on leader and all routers (6 nodes). @@ -263,7 +263,57 @@ def test(self): self.verify_anycast_services(services) #--------------------------------------------------------------------------------- - # DNS/SRP service data unicast entries + # DNS/SRP anycast entries - different version numbers + + # Publish DNS/SRP anycast on leader and all routers (6 nodes). + + version = 0 + leader.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version) + num = 1 + + for node in routers: + version += 1 + node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version) + num += 1 + + self.simulator.go(WAIT_TIME) + + # Check all entries are present in the network data + + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST)) + self.verify_anycast_services(services) + + # Publish same entry with same version on all end-devices (5 nodes). + + for node in end_devs: + node.netdata_publish_dnssrp_anycast(ANYCAST_SEQ_NUM, version) + num += 1 + print(node.name) + self.simulator.go(WAIT_TIME) + # Check number of entries in the network data is limited + # to the desired number (8 entries). All new entries use + # higher version and should be preferred. Validate that + # the 'services' list contains the new services. + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST)) + self.verify_anycast_services(services) + node_rloc16 = node.get_addr16() + self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services)) + + # Unpublish the entry from nodes one by one starting from leader + # and check that number of entries is correct in each step. + + for node in nodes: + node.netdata_unpublish_dnssrp() + self.simulator.go(WAIT_TIME) + num -= 1 + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_ANYCAST)) + self.verify_anycast_services(services) + + #--------------------------------------------------------------------------------- + # DNS/SRP service data unicast entries - equal version number num = 0 for node in routers: @@ -295,7 +345,33 @@ def test(self): self.assertEqual(node.srp_server_get_state(), 'disabled') #--------------------------------------------------------------------------------- - # DNS/SRP server data unicast entries + # DNS/SRP service data unicast entries - different version numbers + + num = 0 + for node in routers: + # Use `num` as version. + node.netdata_publish_dnssrp_unicast(DNSSRP_ADDRESS, DNSSRP_PORT, num) + self.simulator.go(WAIT_TIME) + num += 1 + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST)) + self.verify_unicast_services(services) + # The most recent service should win as it uses a higher version + # number. Validate that the 'services' list contains the service + # from this node by checking the service RLOC16. + node_rloc16 = node.get_addr16() + self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services)) + + for node in reversed(routers): + node.netdata_unpublish_dnssrp() + self.simulator.go(WAIT_TIME) + num -= 1 + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST)) + self.verify_unicast_services(services) + + #--------------------------------------------------------------------------------- + # DNS/SRP server data unicast entries - equal version number num = 0 for node in routers: @@ -325,6 +401,55 @@ def test(self): node.srp_server_set_enabled(False) self.assertEqual(node.srp_server_get_state(), 'disabled') + #--------------------------------------------------------------------------------- + # DNS/SRP server data unicast entries - different version numbers + + num = 0 + for node in routers: + node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT, num) + self.simulator.go(WAIT_TIME) + num += 1 + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST)) + self.verify_unicast_services(services) + # The most recent service should win as it uses a higher version + # number. Validate that the 'services' list contains the service + # from this node by checking the service RLOC16. + node_rloc16 = node.get_addr16() + self.assertTrue(any(int(service[4], 16) == node_rloc16 for service in services)) + + for node in reversed(routers): + node.netdata_unpublish_dnssrp() + self.simulator.go(WAIT_TIME) + num -= 1 + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST)) + self.verify_unicast_services(services) + + # Repeat the same test steps, but start with larger version + # numbers first. + + num = 0 + for node in routers: + node.netdata_publish_dnssrp_unicast_mleid(DNSSRP_PORT, 20 - num) + self.simulator.go(WAIT_TIME) + num += 1 + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST)) + self.verify_unicast_services(services) + # The service from first router should win as it uses the highest + # version number. + first_router_rloc16 = routers[0].get_addr16() + self.assertTrue(any(int(service[4], 16) == first_router_rloc16 for service in services)) + + for node in routers: + node.netdata_unpublish_dnssrp() + self.simulator.go(WAIT_TIME) + num -= 1 + services = leader.get_services() + self.assertEqual(len(services), min(num, DESIRED_NUM_DNSSRP_UNICAST)) + self.verify_unicast_services(services) + #--------------------------------------------------------------------------------- # DNS/SRP server data unicast vs anycast diff --git a/tests/unit/test_network_data.cpp b/tests/unit/test_network_data.cpp index ae7b0e78510..589e162be9a 100644 --- a/tests/unit/test_network_data.cpp +++ b/tests/unit/test_network_data.cpp @@ -635,6 +635,7 @@ void TestNetworkDataDsnSrpServices(void) { uint16_t mAloc16; uint8_t mSequenceNumber; + uint8_t mVersion; uint16_t mRloc16; bool Matches(Service::DnsSrpAnycastInfo aInfo) const @@ -642,7 +643,8 @@ void TestNetworkDataDsnSrpServices(void) VerifyOrQuit(aInfo.mAnycastAddress.GetIid().IsAnycastServiceLocator()); return (aInfo.mAnycastAddress.GetIid().GetLocator() == mAloc16) && - (aInfo.mSequenceNumber == mSequenceNumber) && (aInfo.mRloc16 == mRloc16); + (aInfo.mSequenceNumber == mSequenceNumber) && (aInfo.mVersion == mVersion) && + (aInfo.mRloc16 == mRloc16); } }; @@ -650,6 +652,7 @@ void TestNetworkDataDsnSrpServices(void) { const char *mAddress; uint16_t mPort; + uint8_t mVersion; uint16_t mRloc16; bool Matches(const Service::DnsSrpUnicastInfo &aInfo) const @@ -659,38 +662,50 @@ void TestNetworkDataDsnSrpServices(void) SuccessOrQuit(sockAddr.GetAddress().FromString(mAddress)); sockAddr.SetPort(mPort); - return (aInfo.mSockAddr == sockAddr) && (aInfo.mRloc16 == mRloc16); + return (aInfo.mSockAddr == sockAddr) && (aInfo.mVersion == mVersion) && (aInfo.mRloc16 == mRloc16); } }; const uint8_t kNetworkData[] = { - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x28, 0x00, 0x0b, 0x08, 0x81, 0x02, 0x5c, 0xff, 0x0d, - 0x02, 0x6c, 0x00, 0x0b, 0x09, 0x82, 0x02, 0x5c, 0x03, 0x0d, 0x03, 0x4c, 0x00, 0xaa, 0x0b, 0x35, 0x83, - 0x13, 0x5d, 0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00, 0x2d, 0x0e, 0xc6, 0x27, 0x55, 0x56, 0x18, - 0xd9, 0x12, 0x34, 0x0d, 0x02, 0x00, 0x00, 0x0d, 0x14, 0x6c, 0x00, 0xfd, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, - 0xee, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xab, 0xcd, 0x0d, 0x04, 0x28, 0x00, 0x56, - 0x78, 0x0b, 0x23, 0x84, 0x01, 0x5d, 0x0d, 0x02, 0x00, 0x00, 0x0d, 0x14, 0x4c, 0x00, 0xfd, 0x00, 0x12, - 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0x00, 0x0e, 0x0d, 0x04, - 0x6c, 0x00, 0xcd, 0x12, 0x0b, 0x08, 0x84, 0x01, 0x5c, 0x0d, 0x02, 0x14, 0x01, 0x0d, 0x0b, 0x10, 0x83, - 0x02, 0x5c, 0xfe, 0x0d, 0x02, 0x12, 0x00, 0x0d, 0x02, 0x12, 0x01, 0x0d, 0x02, 0x16, 0x00, + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x28, 0x00, + + 0x0b, 0x09, 0x81, 0x02, 0x5c, 0xff, 0x0d, 0x03, 0x6c, 0x00, 0x05, + + 0x0b, 0x09, 0x82, 0x03, 0x5c, 0x03, 0xaa, 0x0d, 0x02, 0x4c, 0x00, + + 0x0b, 0x36, 0x83, 0x14, 0x5d, 0xfd, 0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0x00, 0x2d, + 0x0e, 0xc6, 0x27, 0x55, 0x56, 0x18, 0xd9, 0x12, 0x34, 0x03, 0x0d, 0x02, 0x00, 0x00, + 0x0d, 0x14, 0x6c, 0x00, 0xfd, 0x00, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, + 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xab, 0xcd, 0x0d, 0x04, 0x28, 0x00, 0x56, 0x78, + + 0x0b, 0x24, 0x84, 0x01, 0x5d, 0x0d, 0x02, 0x00, 0x00, 0x0d, 0x15, 0x4c, 0x00, 0xfd, + 0x00, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x01, 0x23, 0x45, 0x67, 0x89, + 0xab, 0x00, 0x0e, 0x01, 0x0d, 0x04, 0x6c, 0x00, 0xcd, 0x12, + + 0x0b, 0x08, 0x84, 0x01, 0x5c, 0x0d, 0x02, 0x14, 0x01, 0x0d, + + 0x0b, 0x07, 0x83, 0x01, 0x5c, 0x0d, 0x02, 0x28, 0x00, + + 0x0b, 0x13, 0x83, 0x02, 0x5c, 0xfe, 0x0d, 0x03, 0x12, 0x00, 0x07, 0x0d, 0x03, 0x12, + 0x01, 0x06, 0x0d, 0x03, 0x16, 0x00, 0x07, }; const AnycastEntry kAnycastEntries[] = { - {0xfc10, 0x02, 0x2800}, {0xfc11, 0xff, 0x6c00}, {0xfc12, 0x03, 0x4c00}, - {0xfc13, 0xfe, 0x1200}, {0xfc13, 0xfe, 0x1201}, {0xfc13, 0xfe, 0x1600}, + {0xfc10, 0x02, 0, 0x2800}, {0xfc11, 0xff, 5, 0x6c00}, {0xfc12, 0x03, 0, 0x4c00}, + {0xfc13, 0xfe, 7, 0x1200}, {0xfc13, 0xfe, 6, 0x1201}, {0xfc13, 0xfe, 7, 0x1600}, }; const UnicastEntry kUnicastEntriesFromServerData[] = { - {"fd00:aabb:ccdd:eeff:11:2233:4455:6677", 0xabcd, 0x6c00}, - {"fdde:ad00:beef:0:0:ff:fe00:2800", 0x5678, 0x2800}, - {"fd00:1234:5678:9abc:def0:123:4567:89ab", 0x0e, 0x4c00}, - {"fdde:ad00:beef:0:0:ff:fe00:6c00", 0xcd12, 0x6c00}, + {"fd00:aabb:ccdd:eeff:11:2233:4455:6677", 0xabcd, 0, 0x6c00}, + {"fdde:ad00:beef:0:0:ff:fe00:2800", 0x5678, 0, 0x2800}, + {"fd00:1234:5678:9abc:def0:123:4567:89ab", 0x0e, 1, 0x4c00}, + {"fdde:ad00:beef:0:0:ff:fe00:6c00", 0xcd12, 0, 0x6c00}, }; const UnicastEntry kUnicastEntriesFromServiceData[] = { - {"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234, 0x0000}, - {"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234, 0x6c00}, - {"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234, 0x2800}, + {"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234, 3, 0x0000}, + {"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234, 3, 0x6c00}, + {"fdde:ad00:beef:0:2d0e:c627:5556:18d9", 0x1234, 3, 0x2800}, }; const uint16_t kExpectedRlocs[] = {0x6c00, 0x2800, 0x4c00, 0x0000, 0x1200, 0x1201, 0x1600, 0x1401}; @@ -733,8 +748,9 @@ void TestNetworkDataDsnSrpServices(void) { SuccessOrQuit(manager.GetNextDnsSrpAnycastInfo(iterator, anycastInfo)); - printf("\nanycastInfo { %s, seq:%d, rlco16:%04x }", anycastInfo.mAnycastAddress.ToString().AsCString(), - anycastInfo.mSequenceNumber, anycastInfo.mRloc16); + printf("\nanycastInfo { %s, seq:%d, rlco16:%04x, version:%u }", + anycastInfo.mAnycastAddress.ToString().AsCString(), anycastInfo.mSequenceNumber, anycastInfo.mRloc16, + anycastInfo.mVersion); VerifyOrQuit(entry.Matches(anycastInfo), "GetNextDnsSrpAnycastInfo() returned incorrect info"); } @@ -746,8 +762,8 @@ void TestNetworkDataDsnSrpServices(void) SuccessOrQuit(manager.FindPreferredDnsSrpAnycastInfo(anycastInfo)); - printf("\n\nPreferred anycastInfo { %s, seq:%d }", anycastInfo.mAnycastAddress.ToString().AsCString(), - anycastInfo.mSequenceNumber); + printf("\n\nPreferred anycastInfo { %s, seq:%d, version:%u }", + anycastInfo.mAnycastAddress.ToString().AsCString(), anycastInfo.mSequenceNumber, anycastInfo.mVersion); VerifyOrQuit(kAnycastEntries[kPreferredAnycastEntryIndex].Matches(anycastInfo), "FindPreferredDnsSrpAnycastInfo() returned invalid info"); @@ -813,6 +829,7 @@ void TestNetworkDataDsnSrpAnycastSeqNumSelection(void) const uint8_t *mSeqNumbers; uint8_t mSeqNumbersLength; uint8_t mPreferredSeqNum; + uint8_t mPreferredVersion; }; Instance *instance; @@ -824,90 +841,99 @@ void TestNetworkDataDsnSrpAnycastSeqNumSelection(void) VerifyOrQuit(instance != nullptr); const uint8_t kNetworkData1[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x81, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x81, 0x0d, 0x02, 0x50, 0x01, // Service TLV }; const uint8_t kSeqNumbers1[] = {1, 129}; const uint8_t kPreferredSeqNum1 = 129; + const uint8_t kPreferredVer1 = 0; const uint8_t kNetworkData2[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x85, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x05, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x85, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x05, 0x0d, 0x02, 0x50, 0x01, // Service TLV }; const uint8_t kSeqNumbers2[] = {133, 5}; const uint8_t kPreferredSeqNum2 = 133; + const uint8_t kPreferredVer2 = 0; const uint8_t kNetworkData3[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV - 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xff, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Service TLV + 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xff, 0x0d, 0x02, 0x50, 0x02, // Service TLV }; const uint8_t kSeqNumbers3[] = {1, 2, 255}; const uint8_t kPreferredSeqNum3 = 2; + const uint8_t kPreferredVer3 = 0; const uint8_t kNetworkData4[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x82, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV - 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x82, 0x0d, 0x02, 0x50, 0x01, // Service TLV + 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x02, // Service TLV }; const uint8_t kSeqNumbers4[] = {10, 130, 250}; const uint8_t kPreferredSeqNum4 = 250; + const uint8_t kPreferredVer4 = 0; const uint8_t kNetworkData5[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x82, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV - 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x82, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x01, // Service TLV + 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x02, // Service TLV }; const uint8_t kSeqNumbers5[] = {130, 250, 10}; const uint8_t kPreferredSeqNum5 = 250; + const uint8_t kPreferredVer5 = 0; const uint8_t kNetworkData6[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV - 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x82, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x01, // Service TLV + 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x82, 0x0d, 0x02, 0x50, 0x02, // Service TLV }; const uint8_t kSeqNumbers6[] = {250, 10, 130}; const uint8_t kPreferredSeqNum6 = 250; + const uint8_t kPreferredVer6 = 0; const uint8_t kNetworkData7[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV - 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x8A, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0xfa, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x0a, 0x0d, 0x02, 0x50, 0x01, // Service TLV + 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x8A, 0x0d, 0x02, 0x50, 0x02, // Service TLV }; const uint8_t kSeqNumbers7[] = {250, 10, 138}; const uint8_t kPreferredSeqNum7 = 250; + const uint8_t kPreferredVer7 = 0; const uint8_t kNetworkData8[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV - 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xff, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV - 0x0b, 0x08, 0x83, 0x02, 0x5c, 0xfe, 0x0d, 0x02, 0x50, 0x03, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Service TLV + 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xff, 0x0d, 0x02, 0x50, 0x02, // Service TLV + 0x0b, 0x08, 0x83, 0x02, 0x5c, 0xfe, 0x0d, 0x02, 0x50, 0x03, // Service TLV }; const uint8_t kSeqNumbers8[] = {1, 2, 255, 254}; const uint8_t kPreferredSeqNum8 = 2; + const uint8_t kPreferredVer8 = 0; const uint8_t kNetworkData9[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV - 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV - 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV - 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xff, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV - 0x0b, 0x08, 0x83, 0x02, 0x5c, 0xfe, 0x0d, 0x02, 0x50, 0x03, // Server sub-TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Service TLV + 0x0b, 0x08, 0x82, 0x02, 0x5c, 0xff, 0x0d, 0x02, 0x50, 0x02, // Service TLV + 0x0b, 0x08, 0x83, 0x02, 0x5c, 0xfe, 0x0d, 0x02, 0x50, 0x03, // Service TLV }; const uint8_t kSeqNumbers9[] = {1, 2, 255, 254}; const uint8_t kPreferredSeqNum9 = 2; + const uint8_t kPreferredVer9 = 0; const uint8_t kNetworkData10[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV 0x0b, 0x08, 0x80, 0x02, 0x5c, 0xfe, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x78, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV @@ -916,9 +942,10 @@ void TestNetworkDataDsnSrpAnycastSeqNumSelection(void) }; const uint8_t kSeqNumbers10[] = {254, 2, 120, 1}; const uint8_t kPreferredSeqNum10 = 120; + const uint8_t kPreferredVer10 = 0; const uint8_t kNetworkData11[] = { - 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Service TLV + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV 0x0b, 0x08, 0x80, 0x02, 0x5c, 0xf0, 0x0d, 0x02, 0x50, 0x00, // Server sub-TLV 0x0b, 0x08, 0x81, 0x02, 0x5c, 0x02, 0x0d, 0x02, 0x50, 0x01, // Server sub-TLV 0x0b, 0x08, 0x82, 0x02, 0x5c, 0x78, 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV @@ -927,19 +954,61 @@ void TestNetworkDataDsnSrpAnycastSeqNumSelection(void) }; const uint8_t kSeqNumbers11[] = {240, 2, 120, 1}; const uint8_t kPreferredSeqNum11 = 240; + const uint8_t kPreferredVer11 = 0; + + const uint8_t kNetworkData12[] = { + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x09, 0x81, 0x02, 0x5c, 0x81, 0x0d, 0x03, 0x50, 0x01, 0x01, // Service TLV + }; + const uint8_t kSeqNumbers12[] = {1, 129}; + const uint8_t kPreferredSeqNum12 = 129; + const uint8_t kPreferredVer12 = 1; + + const uint8_t kNetworkData13[] = { + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x08, 0x80, 0x02, 0x5c, 0x01, 0x0d, 0x02, 0x50, 0x00, // Service TLV + 0x0b, 0x0e, 0x81, 0x02, 0x5c, 0x81, // Service TLV + 0x0d, 0x03, 0x50, 0x01, 0x02, // Server sub-TLV + 0x0d, 0x03, 0x50, 0x02, 0x02, // Server sub-TLV + }; + const uint8_t kSeqNumbers13[] = {1, 129, 129}; + const uint8_t kPreferredSeqNum13 = 129; + const uint8_t kPreferredVer13 = 2; + + const uint8_t kNetworkData14[] = { + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x13, 0x81, 0x02, 0x5c, 0x07, // Service TLV + 0x0d, 0x03, 0x50, 0x00, 0x01, // Server sub-TLV + 0x0d, 0x03, 0x50, 0x01, 0x02, // Server sub-TLV + 0x0d, 0x03, 0x50, 0x02, 0x03, // Server sub-TLV + }; + const uint8_t kSeqNumbers14[] = {7, 7, 7}; + const uint8_t kPreferredSeqNum14 = 7; + const uint8_t kPreferredVer14 = 1; + + const uint8_t kNetworkData15[] = { + 0x08, 0x04, 0x0b, 0x02, 0x50, 0xb0, // Commissioning Data TLV + 0x0b, 0x17, 0x81, 0x02, 0x5c, 0x03, // Service TLV + 0x0d, 0x03, 0x50, 0x00, 0x01, // Server sub-TLV + 0x0d, 0x03, 0x50, 0x01, 0x02, // Server sub-TLV + 0x0d, 0x02, 0x50, 0x02, // Server sub-TLV + 0x0d, 0x03, 0x50, 0x03, 0x01, // Server sub-TLV + }; + const uint8_t kSeqNumbers15[] = {3, 3, 3, 3}; + const uint8_t kPreferredSeqNum15 = 3; + const uint8_t kPreferredVer15 = 0; + +#define TEST_CASE(Num) \ + { \ + kNetworkData##Num, sizeof(kNetworkData##Num), kSeqNumbers##Num, sizeof(kSeqNumbers##Num), \ + kPreferredSeqNum##Num, kPreferredVer##Num \ + } const TestInfo kTests[] = { - {kNetworkData1, sizeof(kNetworkData1), kSeqNumbers1, sizeof(kSeqNumbers1), kPreferredSeqNum1}, - {kNetworkData2, sizeof(kNetworkData2), kSeqNumbers2, sizeof(kSeqNumbers2), kPreferredSeqNum2}, - {kNetworkData3, sizeof(kNetworkData3), kSeqNumbers3, sizeof(kSeqNumbers3), kPreferredSeqNum3}, - {kNetworkData4, sizeof(kNetworkData4), kSeqNumbers4, sizeof(kSeqNumbers4), kPreferredSeqNum4}, - {kNetworkData5, sizeof(kNetworkData5), kSeqNumbers5, sizeof(kSeqNumbers5), kPreferredSeqNum5}, - {kNetworkData6, sizeof(kNetworkData6), kSeqNumbers6, sizeof(kSeqNumbers6), kPreferredSeqNum6}, - {kNetworkData7, sizeof(kNetworkData7), kSeqNumbers7, sizeof(kSeqNumbers7), kPreferredSeqNum7}, - {kNetworkData8, sizeof(kNetworkData8), kSeqNumbers8, sizeof(kSeqNumbers8), kPreferredSeqNum8}, - {kNetworkData9, sizeof(kNetworkData9), kSeqNumbers9, sizeof(kSeqNumbers9), kPreferredSeqNum9}, - {kNetworkData10, sizeof(kNetworkData10), kSeqNumbers10, sizeof(kSeqNumbers10), kPreferredSeqNum10}, - {kNetworkData11, sizeof(kNetworkData11), kSeqNumbers11, sizeof(kSeqNumbers11), kPreferredSeqNum11}, + TEST_CASE(1), TEST_CASE(2), TEST_CASE(3), TEST_CASE(4), TEST_CASE(5), + TEST_CASE(6), TEST_CASE(7), TEST_CASE(8), TEST_CASE(9), TEST_CASE(10), + TEST_CASE(11), TEST_CASE(12), TEST_CASE(13), TEST_CASE(14), TEST_CASE(15), }; Service::Manager &manager = instance->Get(); @@ -959,8 +1028,9 @@ void TestNetworkDataDsnSrpAnycastSeqNumSelection(void) { SuccessOrQuit(manager.GetNextDnsSrpAnycastInfo(iterator, anycastInfo)); - printf("\n { %s, seq:%d, rlco16:%04x }", anycastInfo.mAnycastAddress.ToString().AsCString(), - anycastInfo.mSequenceNumber, anycastInfo.mRloc16); + printf("\n { %s, seq:%u, version:%u, rlco16:%04x }", anycastInfo.mAnycastAddress.ToString().AsCString(), + + anycastInfo.mSequenceNumber, anycastInfo.mVersion, anycastInfo.mRloc16); VerifyOrQuit(anycastInfo.mSequenceNumber == test.mSeqNumbers[index]); VerifyOrQuit(anycastInfo.mRloc16 == 0x5000 + index); @@ -969,8 +1039,9 @@ void TestNetworkDataDsnSrpAnycastSeqNumSelection(void) VerifyOrQuit(manager.GetNextDnsSrpAnycastInfo(iterator, anycastInfo) == kErrorNotFound); SuccessOrQuit(manager.FindPreferredDnsSrpAnycastInfo(anycastInfo)); - printf("\n preferred -> seq:%d ", anycastInfo.mSequenceNumber); + printf("\n preferred -> seq:%u, version:%u ", anycastInfo.mSequenceNumber, anycastInfo.mVersion); VerifyOrQuit(anycastInfo.mSequenceNumber == test.mPreferredSeqNum); + VerifyOrQuit(anycastInfo.mVersion == test.mPreferredVersion); } testFreeInstance(instance);