1 /* 2 * Copyright (c) 2021, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definition of Network Data Publisher. 32 */ 33 34 #ifndef NETWORK_DATA_PUBLISHER_HPP_ 35 #define NETWORK_DATA_PUBLISHER_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #if OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 40 41 #if !OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE && !OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 42 #error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE requires either OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE"\ 43 "or OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE" 44 #endif 45 46 #if OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE && (OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES < \ 47 (OPENTHREAD_CONFIG_BORDER_ROUTING_MAX_DISCOVERED_PREFIXES + 4)) 48 #error "OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES needs to support more entries when "\ 49 "OPENTHREAD_CONFIG_BORDER_ROUTING_ENABLE is enabled to accommodate for max on-link prefixes" 50 #endif 51 52 #include <openthread/netdata_publisher.h> 53 54 #include "common/clearable.hpp" 55 #include "common/equatable.hpp" 56 #include "common/error.hpp" 57 #include "common/locator.hpp" 58 #include "common/non_copyable.hpp" 59 #include "common/notifier.hpp" 60 #include "common/string.hpp" 61 #include "common/timer.hpp" 62 #include "net/ip6_address.hpp" 63 #include "thread/network_data_types.hpp" 64 65 namespace ot { 66 namespace NetworkData { 67 68 /** 69 * This class implements the Network Data Publisher. 70 * 71 * It provides mechanisms to limit the number of similar Service and/or Prefix (on-mesh prefix or external route) 72 * entries in the Thread Network Data by monitoring the Network Data and managing if or when to add or remove entries. 73 * 74 */ 75 class Publisher : public InstanceLocator, private NonCopyable 76 { 77 friend class ot::Notifier; 78 79 public: 80 /** 81 * This enumeration represents the events reported from the Publisher callbacks. 82 * 83 */ 84 enum Event : uint8_t 85 { 86 kEventEntryAdded = OT_NETDATA_PUBLISHER_EVENT_ENTRY_ADDED, ///< Entry is added to Network Data. 87 kEventEntryRemoved = OT_NETDATA_PUBLISHER_EVENT_ENTRY_REMOVED, ///< Entry is removed from Network Data. 88 }; 89 90 /** 91 * This constructor initializes `Publisher` object. 92 * 93 * @param[in] aInstance A reference to the OpenThread instance. 94 * 95 */ 96 explicit Publisher(Instance &aInstance); 97 98 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 99 100 /** 101 * This type represents the callback function pointer used to notify when a "DNS/SRP Service" entry is added to or 102 * removed from the Thread Network Data. 103 * 104 * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there 105 * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the 106 * entry (i.e., a call to `UnpublishDnsSrpService()`). 107 * 108 */ 109 typedef otNetDataDnsSrpServicePublisherCallback DnsSrpServiceCallback; 110 111 /** 112 * This method sets a callback for notifying when a published "DNS/SRP Service" is actually added to or removed 113 * from the Thread Network Data. 114 * 115 * A subsequent call to this method replaces any previously set callback function. 116 * 117 * @param[in] aCallback The callback function pointer (can be NULL if not needed). 118 * @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked). 119 * 120 */ SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback,void * aContext)121 void SetDnsSrpServiceCallback(DnsSrpServiceCallback aCallback, void *aContext) 122 { 123 mDnsSrpServiceEntry.SetCallback(aCallback, aContext); 124 } 125 126 /** 127 * This method requests "DNS/SRP Service Anycast Address" to be published in the Thread Network Data. 128 * 129 * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published 130 * (from earlier call to any of `PublishDnsSrpService{Type}()` methods). 131 * 132 * @param[in] aSequenceNumber The sequence number of DNS/SRP Anycast Service. 133 * 134 */ PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber)135 void PublishDnsSrpServiceAnycast(uint8_t aSequenceNumber) { mDnsSrpServiceEntry.PublishAnycast(aSequenceNumber); } 136 137 /** 138 * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data. 139 * 140 * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published 141 * (from earlier call to any of `PublishDnsSrpService{Type}()` methods). 142 * 143 * This method publishes the "DNS/SRP Service Unicast Address" by including the address and port info in the 144 * Service TLV data. 145 * 146 * @param[in] aAddress The DNS/SRP server address to publish. 147 * @param[in] aPort The SRP server port number to publish. 148 * 149 */ PublishDnsSrpServiceUnicast(const Ip6::Address & aAddress,uint16_t aPort)150 void PublishDnsSrpServiceUnicast(const Ip6::Address &aAddress, uint16_t aPort) 151 { 152 mDnsSrpServiceEntry.PublishUnicast(aAddress, aPort); 153 } 154 155 /** 156 * This method requests "DNS/SRP Service Unicast Address" to be published in the Thread Network Data. 157 * 158 * A call to this method will remove and replace any previous "DNS/SRP Service" entry that was being published 159 * (from earlier call to any of `PublishDnsSrpService{Type}()` methods). 160 * 161 * Unlike the `PublishDnsSrpServiceUnicast(aAddress, aPort)` which requires the published address to be given and 162 * includes the info in the Service TLV data, this method uses the device's mesh-local EID and includes the info 163 * in the Server TLV data. 164 * 165 * @param[in] aPort The SRP server port number to publish. 166 * 167 */ PublishDnsSrpServiceUnicast(uint16_t aPort)168 void PublishDnsSrpServiceUnicast(uint16_t aPort) { mDnsSrpServiceEntry.PublishUnicast(aPort); } 169 170 /** 171 * This method indicates whether or not currently the "DNS/SRP Service" entry is added to the Thread Network Data. 172 * 173 * @retval TRUE The published DNS/SRP Service entry is added to the Thread Network Data. 174 * @retval FALSE The entry is not added to Thread Network Data or there is no entry to publish. 175 * 176 */ IsDnsSrpServiceAdded(void) const177 bool IsDnsSrpServiceAdded(void) const { return mDnsSrpServiceEntry.IsAdded(); } 178 179 /** 180 * This method unpublishes any previously added "DNS/SRP (Anycast or Unicast) Service" entry from the Thread 181 * Network Data. 182 * 183 */ UnpublishDnsSrpService(void)184 void UnpublishDnsSrpService(void) { mDnsSrpServiceEntry.Unpublish(); } 185 186 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 187 188 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 189 /** 190 * This type represents the callback function pointer used to notify when a prefix (on-mesh or external route) 191 * entry is added to or removed from the Thread Network Data. 192 * 193 * On remove the callback is invoked independent of whether the entry is removed by `Publisher` (e.g., when there 194 * are too many similar entries already present in the Network Data) or through an explicit call to unpublish the 195 * entry. 196 * 197 */ 198 typedef otNetDataPrefixPublisherCallback PrefixCallback; 199 200 /** 201 * This method sets a callback for notifying when a published prefix entry is actually added to or removed from 202 * the Thread Network Data. 203 * 204 * A subsequent call to this method replaces any previously set callback function. 205 * 206 * @param[in] aCallback The callback function pointer (can be NULL if not needed). 207 * @param[in] aContext A pointer to application-specific context (used when @p aCallback is invoked). 208 * 209 */ 210 void SetPrefixCallback(PrefixCallback aCallback, void *aContext); 211 212 /** 213 * This method requests an on-mesh prefix to be published in the Thread Network Data. 214 * 215 * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`). 216 * 217 * A subsequent call to this method will replace a previous request for the same prefix. In particular if the 218 * new call only changes the flags (e.g., preference level) and the prefix is already added in the Network Data, 219 * the change to flags is immediately reflected in the Network Data. This ensures that existing entries in the 220 * Network Data are not abruptly removed. Note that a change in the preference level can potentially later cause 221 * the entry to be removed from the Network Data after determining there are other nodes that are publishing the 222 * same prefix with the same or higher preference. 223 * 224 * @param[in] aConfig The on-mesh prefix config to publish. 225 * 226 * @retval kErrorNone The on-mesh prefix is published successfully. 227 * @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). 228 * @retval kErrorAlready An entry with the same prefix is already in the published list. 229 * @retval kErrorNoBufs Could not allocate an entry for the new request. Publisher supports a limited number 230 * of entries (shared between on-mesh prefix and external route) determined by config 231 * `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`. 232 * 233 * 234 */ 235 Error PublishOnMeshPrefix(const OnMeshPrefixConfig &aConfig); 236 237 /** 238 * This method requests an external route prefix to be published in the Thread Network Data. 239 * 240 * Only stable entries can be published (i.e.,`aConfig.mStable` MUST be `true`). 241 * 242 * A subsequent call to this method will replace a previous request for the same prefix. In particular if the 243 * new call only changes the flags (e.g., preference level) and the prefix is already added in the Network Data, 244 * the change to flags is immediately reflected in the Network Data. This ensures that existing entries in the 245 * Network Data are not abruptly removed. Note that a change in the preference level can potentially later cause 246 * the entry to be removed from the Network Data after determining there are other nodes that are publishing the 247 * same prefix with the same or higher preference. 248 * 249 * @param[in] aConfig The external route config to publish. 250 * 251 * @retval kErrorNone The external route is published successfully. 252 * @retval kErrorInvalidArgs The @p aConfig is not valid (bad prefix, invalid flag combinations, or not stable). 253 * @retval kErrorNoBufs Could not allocate an entry for the new request. Publisher supports a limited number 254 * of entries (shared between on-mesh prefix and external route) determined by config 255 * `OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES`. 256 * 257 * 258 */ 259 Error PublishExternalRoute(const ExternalRouteConfig &aConfig); 260 261 /** 262 * This method indicates whether or not currently a published prefix entry (on-mesh or external route) is added to 263 * the Thread Network Data. 264 * 265 * @param[in] aPrefix The prefix to check. 266 * 267 * @retval TRUE The published prefix entry is added to the Thread Network Data. 268 * @retval FALSE The entry is not added to Thread Network Data or there is no matching entry to publish. 269 * 270 */ 271 bool IsPrefixAdded(const Ip6::Prefix &aPrefix) const; 272 273 /** 274 * This method unpublishes a previously published prefix (on-mesh or external route). 275 * 276 * @param[in] aPrefix The prefix to unpublish. 277 * 278 * @retval kErrorNone The prefix was unpublished successfully. 279 * @retval kErrorNotFound Could not find the prefix in the published list. 280 * 281 */ 282 Error UnpublishPrefix(const Ip6::Prefix &aPrefix); 283 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 284 285 private: 286 class Entry : public InstanceLocatorInit 287 { 288 protected: 289 enum State : uint8_t 290 { 291 kNoEntry, // Entry is unused (there is no entry). 292 kToAdd, // Entry is ready to be added, monitoring network data to decide if/when to add it. 293 kAdding, // Entry is being added in network data (random wait interval before add). 294 kAdded, // Entry is added in network data, monitoring to determine if/when to remove. 295 kRemoving, // Entry is being removed from network data (random wait interval before remove). 296 }; 297 298 // All intervals are in milliseconds. 299 static constexpr uint32_t kMaxDelayToAdd = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_ADD; 300 static constexpr uint32_t kMaxDelayToRemove = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_DELAY_TO_REMOVE; 301 static constexpr uint32_t kExtraDelayToRemovePeferred = 302 OPENTHREAD_CONFIG_NETDATA_PUBLISHER_EXTRA_DELAY_TIME_TO_REMOVE_PREFERRED; 303 304 static constexpr uint16_t kInfoStringSize = 50; 305 306 typedef String<kInfoStringSize> InfoString; 307 Entry(void)308 Entry(void) 309 : mState(kNoEntry) 310 { 311 } 312 Init(Instance & aInstance)313 void Init(Instance &aInstance) { InstanceLocatorInit::Init(aInstance); } GetState(void) const314 State GetState(void) const { return mState; } 315 void SetState(State aState); GetUpdateTime(void) const316 const TimeMilli &GetUpdateTime(void) const { return mUpdateTime; } 317 bool IsPreferred(uint16_t aRloc16) const; 318 void UpdateState(uint8_t aNumEntries, uint8_t aNumPreferredEntries, uint8_t aDesiredNumEntries); 319 void HandleTimer(void); 320 InfoString ToString(bool aIncludeState = true) const; 321 322 public: IsAdded(void) const323 bool IsAdded(void) const { return (mState == kAdded); } 324 325 private: 326 void Add(void); 327 void Remove(State aNextState); 328 void LogUpdateTime(void) const; 329 static const char *StateToString(State aState); 330 331 TimeMilli mUpdateTime; 332 State mState; 333 }; 334 335 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 336 class DnsSrpServiceEntry : public Entry, private NonCopyable 337 { 338 friend class Entry; 339 340 public: 341 explicit DnsSrpServiceEntry(Instance &aInstance); 342 void SetCallback(DnsSrpServiceCallback aCallback, void *aContext); 343 void PublishAnycast(uint8_t aSequenceNumber); 344 void PublishUnicast(const Ip6::Address &aAddress, uint16_t aPort); 345 void PublishUnicast(uint16_t aPort); 346 void Unpublish(void); HandleTimer(void)347 void HandleTimer(void) { Entry::HandleTimer(); } 348 void HandleNotifierEvents(Events aEvents); 349 350 private: 351 static constexpr uint8_t kDesiredNumAnycast = 352 OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ANYCAST_DNS_SRP_SERVICE_ENTRIES; 353 354 static constexpr uint8_t kDesiredNumUnicast = 355 OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_UNICAST_DNS_SRP_SERVICE_ENTRIES; 356 357 enum Type : uint8_t 358 { 359 kTypeAnycast, 360 kTypeUnicast, 361 kTypeUnicastMeshLocalEid, 362 }; 363 364 class Info : public Clearable<Info>, public Equatable<Info> 365 { 366 public: Info(void)367 Info(void) { Clear(); } GetType(void) const368 Type GetType(void) const { return mType; } GetSequenceNumber(void) const369 uint8_t GetSequenceNumber(void) const { return static_cast<uint8_t>(mPortOrSeqNumber); } GetPort(void) const370 uint16_t GetPort(void) const { return mPortOrSeqNumber; } GetAddress(void) const371 const Ip6::Address &GetAddress(void) const { return mAddress; } SetAddress(const Ip6::Address & aAddress)372 void SetAddress(const Ip6::Address &aAddress) { mAddress = aAddress; } 373 InfoAnycast(uint8_t aSequenceNumber)374 static Info InfoAnycast(uint8_t aSequenceNumber) { return Info(kTypeAnycast, aSequenceNumber); } InfoUnicast(Type aType,const Ip6::Address & aAddress,uint16_t aPort)375 static Info InfoUnicast(Type aType, const Ip6::Address &aAddress, uint16_t aPort) 376 { 377 return Info(aType, aPort, &aAddress); 378 } 379 380 private: 381 Info(Type aType, uint16_t aPortOrSeqNumber, const Ip6::Address *aAddress = nullptr); 382 383 Ip6::Address mAddress; 384 uint16_t mPortOrSeqNumber; 385 Type mType; 386 }; 387 GetType(void) const388 Type GetType(void) const { return mInfo.GetType(); } 389 void Publish(const Info &aInfo); 390 void Add(void); 391 void Remove(State aNextState); 392 void Notify(Event aEvent) const; 393 void Process(void); 394 void CountAnycastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; 395 void CountUnicastEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; 396 397 Info mInfo; 398 DnsSrpServiceCallback mCallback; 399 void * mCallbackContext; 400 }; 401 #endif // OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 402 403 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 404 // Max number of prefix (on-mesh or external route) entries. 405 static constexpr uint16_t kMaxPrefixEntries = OPENTHREAD_CONFIG_NETDATA_PUBLISHER_MAX_PREFIX_ENTRIES; 406 407 class PrefixEntry : public Entry, private NonCopyable 408 { 409 friend class Entry; 410 411 public: Init(Instance & aInstance)412 void Init(Instance &aInstance) { Entry::Init(aInstance); } IsInUse(void) const413 bool IsInUse(void) const { return GetState() != kNoEntry; } Matches(const Ip6::Prefix & aPrefix) const414 bool Matches(const Ip6::Prefix &aPrefix) const { return mPrefix == aPrefix; } 415 void Publish(const OnMeshPrefixConfig &aConfig); 416 void Publish(const ExternalRouteConfig &aConfig); 417 void Unpublish(void); HandleTimer(void)418 void HandleTimer(void) { Entry::HandleTimer(); } 419 void HandleNotifierEvents(Events aEvents); 420 421 private: 422 static constexpr uint8_t kDesiredNumOnMeshPrefix = 423 OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_ON_MESH_PREFIX_ENTRIES; 424 425 static constexpr uint8_t kDesiredNumExternalRoute = 426 OPENTHREAD_CONFIG_NETDATA_PUBLISHER_DESIRED_NUM_EXTERNAL_ROUTE_ENTRIES; 427 428 enum Type : uint8_t 429 { 430 kTypeOnMeshPrefix, 431 kTypeExternalRoute, 432 }; 433 434 void Publish(const Ip6::Prefix &aPrefix, uint16_t aNewFlags, Type aNewType); 435 void Add(void); 436 Error AddOnMeshPrefix(void); 437 Error AddExternalRoute(void); 438 void Remove(State aNextState); 439 void Process(void); 440 void CountOnMeshPrefixEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; 441 void CountExternalRouteEntries(uint8_t &aNumEntries, uint8_t &aNumPreferredEntries) const; 442 443 Type mType; 444 Ip6::Prefix mPrefix; 445 uint16_t mFlags; 446 }; 447 #endif // OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 448 449 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE IsADnsSrpServiceEntry(const Entry & aEntry) const450 bool IsADnsSrpServiceEntry(const Entry &aEntry) const { return (&aEntry == &mDnsSrpServiceEntry); } 451 #endif 452 453 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 454 PrefixEntry * FindOrAllocatePrefixEntry(const Ip6::Prefix &aPrefix); 455 PrefixEntry * FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix); 456 const PrefixEntry *FindMatchingPrefixEntry(const Ip6::Prefix &aPrefix) const; 457 bool IsAPrefixEntry(const Entry &aEntry) const; 458 void NotifyPrefixEntryChange(Event aEvent, const Ip6::Prefix &aPrefix) const; 459 #endif 460 GetTimer(void)461 TimerMilli &GetTimer(void) { return mTimer; } 462 void HandleNotifierEvents(Events aEvents); 463 static void HandleTimer(Timer &aTimer); 464 void HandleTimer(void); 465 466 #if OPENTHREAD_CONFIG_TMF_NETDATA_SERVICE_ENABLE 467 DnsSrpServiceEntry mDnsSrpServiceEntry; 468 #endif 469 470 #if OPENTHREAD_CONFIG_BORDER_ROUTER_ENABLE 471 PrefixEntry mPrefixEntries[kMaxPrefixEntries]; 472 PrefixCallback mPrefixCallback; 473 void * mPrefixCallbackContext; 474 #endif 475 476 TimerMilli mTimer; 477 }; 478 479 } // namespace NetworkData 480 } // namespace ot 481 482 #endif // OPENTHREAD_CONFIG_NETDATA_PUBLISHER_ENABLE 483 484 #endif // NETWORK_DATA_PUBLISHER_HPP_ 485